ContactsProvider2.java revision 3593682b8d9213fde576a0cff54458ad50563980
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 19d9ec58265ae59a549880ef63cdfb5d0d977cdabaDmitri Plotnikovimport com.android.common.content.SQLiteContentProvider; 2053214b3ed12b0ff9cb589b6559311f2ac142f2e3Bjorn Bringertimport com.android.common.content.SyncStateContentProviderHelper; 215b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport com.android.providers.contacts.ContactAggregator.AggregationSuggestionParameter; 2297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactLookupKey.LookupKeySegment; 2324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns; 2497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns; 2597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; 2697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Clauses; 2797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns; 2897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsStatusUpdatesColumns; 2997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; 3071340347b4862d4b1368a5d69d1667e2245952e4Daisuke Miyakawaimport com.android.providers.contacts.ContactsDatabaseHelper.DataUsageStatColumns; 3197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns; 322f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawaimport com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns; 3397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns; 3497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType; 3597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneColumns; 3697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; 371dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.PhotoFilesColumns; 3897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 3997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 4003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SearchIndexColumns; 4197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SettingsColumns; 4297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns; 433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemPhotosColumns; 44f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemsColumns; 4597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables; 46ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmannimport com.android.providers.contacts.ContactsDatabaseHelper.Views; 472f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawaimport com.android.providers.contacts.util.DbQueryUtils; 4897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardComposer; 4997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardConfig; 5097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Lists; 5197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Maps; 5297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Sets; 53f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawaimport com.google.common.annotations.VisibleForTesting; 5497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 55b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account; 56caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager; 575b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanaimport android.accounts.OnAccountsUpdateListener; 58bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.Notification; 59bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.NotificationManager; 60bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.PendingIntent; 61c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager; 62568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation; 63568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult; 646ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.content.ContentResolver; 6535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris; 6667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues; 6767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context; 68627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.IContentService; 69bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.content.Intent; 70568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException; 713d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences; 72627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.SyncAdapterType; 7367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher; 74f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringertimport android.content.res.AssetFileDescriptor; 753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.content.res.Resources; 76e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikovimport android.database.CrossProcessCursor; 774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor; 78e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikovimport android.database.CursorWindow; 79ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.database.CursorWrapper; 80ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils; 8109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor; 8209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor.RowBuilder; 834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase; 8408ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwoodimport android.database.sqlite.SQLiteDoneException; 854f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder; 86f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.Bitmap; 87f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.BitmapFactory; 884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri; 89d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.net.Uri.Builder; 90bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Binder; 916ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.os.Bundle; 92bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Handler; 93bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.HandlerThread; 94bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Message; 95ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringertimport android.os.ParcelFileDescriptor; 96bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Process; 97b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException; 9815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikovimport android.os.StrictMode; 990dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikovimport android.os.SystemClock; 1000e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport android.os.SystemProperties; 1013d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager; 102508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns; 1033de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract; 104b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions; 10597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email; 10697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.GroupMembership; 10797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im; 10897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname; 1096d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Note; 11097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization; 11197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone; 11297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo; 1134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.SipAddress; 11497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 11597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 116ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.provider.ContactsContract.ContactCounts; 1173de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Contacts; 1185b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.AggregationSuggestions; 1193de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Data; 12071340347b4862d4b1368a5d69d1667e2245952e4Daisuke Miyakawaimport android.provider.ContactsContract.DataUsageFeedback; 121d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.provider.ContactsContract.Directory; 122f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.DisplayPhoto; 1233de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Groups; 124bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.provider.ContactsContract.Intents; 1253de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup; 1261dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoroimport android.provider.ContactsContract.PhotoFiles; 12709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.provider.ContactsContract.ProviderStatus; 1283de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.RawContacts; 129916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikovimport android.provider.ContactsContract.SearchSnippetColumns; 1303de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Settings; 13182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikovimport android.provider.ContactsContract.StatusUpdates; 1323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.provider.ContactsContract.StreamItemPhotos; 133f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.StreamItems; 13497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.LiveFolders; 13597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.OpenableColumns; 13697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.SyncStateContract; 137a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils; 1389a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikovimport android.telephony.TelephonyManager; 139a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils; 140c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log; 1414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 142108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.BufferedWriter; 143d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.ByteArrayOutputStream; 144f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.File; 145b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException; 146d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.IOException; 147d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.OutputStream; 148108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.OutputStreamWriter; 149108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.Writer; 15042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.text.SimpleDateFormat; 1517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList; 15246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawaimport java.util.Arrays; 1535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections; 15442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.util.Date; 155b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap; 1560e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.HashSet; 1575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List; 158622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkeyimport java.util.Locale; 159b5a4add17815167d20a90645779df34cdf45280dFred Quintanaimport java.util.Map; 1600e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.Set; 161ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch; 1624f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/** 1644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications 1654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}. 1664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 1675b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanapublic class ContactsProvider2 extends SQLiteContentProvider implements OnAccountsUpdateListener { 168caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 169bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov private static final String TAG = "ContactsProvider"; 170bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov 171bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE); 1724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 17315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_INITIALIZE = 0; 17415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_OPEN_WRITE_ACCESS = 1; 17515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS = 2; 17615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_ACCOUNTS = 3; 17715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_LOCALE = 4; 17815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM = 5; 17905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_SEARCH_INDEX = 6; 18005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_PROVIDER_STATUS = 7; 18105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_DIRECTORIES = 8; 18205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_CHANGE_LOCALE = 9; 183f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int BACKGROUND_TASK_CLEANUP_PHOTOS = 10; 184619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** Default for the maximum number of returned aggregation suggestions. */ 1863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DEFAULT_MAX_SUGGESTIONS = 5; 1873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 1883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Limit for the maximum number of social stream items to store under a raw contact. */ 1893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int MAX_STREAM_ITEMS_PER_RAW_CONTACT = 5; 1903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 191f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Rate limit (in ms) for photo cleanup. Do it at most once per day. */ 192f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_CLEANUP_RATE_LIMIT = 24 * 60 * 60 * 1000; 193f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1943d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /** 195b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov * Property key for the legacy contact import version. The need for a version 1963d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov * as opposed to a boolean flag is that if we discover bugs in the contact import process, 1973d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov * we can trigger re-import by incrementing the import version. 1983d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov */ 199b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov private static final String PROPERTY_CONTACTS_IMPORTED = "contacts_imported_v1"; 200b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov private static final int PROPERTY_CONTACTS_IMPORT_VERSION = 1; 20151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov private static final String PREF_LOCALE = "locale"; 2023d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2030dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final String PROPERTY_AGGREGATION_ALGORITHM = "aggregation_v2"; 2040dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final int PROPERTY_AGGREGATION_ALGORITHM_VERSION = 2; 2050dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 2060e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate"; 2070e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff 208a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 2094f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2102f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 2112f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * Used to insert a column into strequent results, which enables SQL to sort the list using 2122f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * the total times contacted. See also {@link #sStrequentFrequentProjectionMap}. 2132f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 2142f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private static final String TIMES_USED_SORT_COLUMN = "times_used_sort"; 2155e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 216d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, " 2172f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa + TIMES_USED_SORT_COLUMN + " DESC, " 2189b43551f1ce33b79141772737a262ce609bd0cebMegha Joshi + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 219d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final String STREQUENT_LIMIT = 220d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE " 221d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov + Contacts.STARRED + "=1) + 25"; 222d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov 22345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final String FREQUENT_ORDER_BY = DataUsageStatColumns.TIMES_USED + " DESC," 22445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 22545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 2266e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE = 2279b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.CONTACTS + " SET " + Contacts.TIMES_CONTACTED + "=" + 2289b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " CASE WHEN " + Contacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " + 2299b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " (" + Contacts.TIMES_CONTACTED + " + 1) END WHERE " + Contacts._ID + "=?"; 2309b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 2316e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE = 2329b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.RAW_CONTACTS + " SET " + RawContacts.TIMES_CONTACTED + "=" + 2339b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " CASE WHEN " + RawContacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " + 2349b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " (" + RawContacts.TIMES_CONTACTED + " + 1) END WHERE " + RawContacts.CONTACT_ID + "=?"; 2359b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 236de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK"; 237de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa 2383716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Regex for splitting query strings - we split on any group of non-alphanumeric characters, 2393716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // excluding the @ symbol. 2403716f1447ceb21180d1301790eabd8b9453f486dDave Santoro /* package */ static final String QUERY_TOKENIZER_REGEX = "[^\\w@]+"; 2413716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 242d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS = 1000; 243d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS_ID = 1001; 2445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP = 1002; 2455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP_ID = 1003; 246a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_DATA = 1004; 2475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_FILTER = 1005; 2485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT = 1006; 2495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT_FILTER = 1007; 2505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_GROUP = 1008; 251a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_PHOTO = 1009; 252f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_DISPLAY_PHOTO = 1010; 253f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_DISPLAY_PHOTO = 1011; 254f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_DISPLAY_PHOTO = 1012; 255f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_AS_VCARD = 1013; 256f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_AS_MULTI_VCARD = 1014; 257f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_DATA = 1015; 258f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_DATA = 1016; 259f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_ENTITIES = 1017; 260f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ENTITIES = 1018; 261f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_ENTITIES = 1019; 262f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_STREAM_ITEMS = 1020; 263f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_STREAM_ITEMS = 1021; 264f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_STREAM_ITEMS = 1022; 26545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final int CONTACTS_FREQUENT = 1023; 2664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS = 2002; 2685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_ID = 2003; 2695ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_DATA = 2004; 27046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITY_ID = 2005; 271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_DISPLAY_PHOTO = 2006; 272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS = 2007; 2734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2746bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 2756bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 276ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 27748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_ID = 3003; 27848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_FILTER = 3004; 27948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS = 3005; 28048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_ID = 3006; 28148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_LOOKUP = 3007; 28248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_FILTER = 3008; 28348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS = 3009; 28448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS_ID = 3010; 285a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2866bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 2876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 288b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 289b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 290b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 29182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES = 7000; 29282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES_ID = 7001; 2931f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 29431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 29531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 296eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey private static final int SETTINGS = 9000; 297eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 298ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 299ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 300ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 301ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 30235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 303b5a4add17815167d20a90645779df34cdf45280dFred Quintana private static final int SYNCSTATE_ID = 11001; 30435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 305c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SUGGESTIONS = 12001; 306c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SHORTCUT = 12002; 307c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 3081b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS = 14000; 3091b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001; 3101b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002; 3111b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003; 3121b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 31346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITIES = 15001; 31446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 31509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private static final int PROVIDER_STATUS = 16001; 31609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 317d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES = 17001; 318d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES_ID = 17002; 319d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 3207a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private static final int COMPLETE_NAME = 18000; 3217a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 32224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE = 19000; 32324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_ENTITIES = 19001; 32424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA = 19002; 32524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA_ID = 19003; 32624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_AS_VCARD = 19004; 32724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS = 19005; 32824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID = 19006; 32924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_DATA = 19007; 33024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_ENTITIES = 19008; 33124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 33246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final int DATA_USAGE_FEEDBACK_ID = 20001; 33346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 3343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS = 21000; 3353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_PHOTOS = 21001; 3363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID = 21002; 3373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS = 21003; 3383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS_ID = 21004; 3393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_LIMIT = 21005; 3403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 341f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int DISPLAY_PHOTO = 22000; 342f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_DIMENSIONS = 22001; 343f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 344dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID = 345dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 346dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME 347dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "=" + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 348dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE 34943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + "=" + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND (" 35043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET 35143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + "=" + RawContactsColumns.CONCRETE_DATA_SET + " OR " 35243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 35343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " IS NULL)" 354dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND " + Groups.FAVORITES + " != 0"; 355dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 356dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID = 357dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 358dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 359dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 360dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 36143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND (" 36243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + "=" 36343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " OR " 36443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 36543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " IS NULL)" 36643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + " AND " + Groups.AUTO_ADD + " != 0"; 367dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 368dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String[] PROJECTION_GROUP_ID 369dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana = new String[]{Tables.GROUPS + "." + Groups._ID}; 370dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 371dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_GROUPMEMBERSHIP_DATA = DataColumns.MIMETYPE_ID + "=? " 372dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.GROUP_ROW_ID + "=? " 373dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.RAW_CONTACT_ID + "=?"; 374dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 375dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_STARRED_FROM_RAW_CONTACTS = 376dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana "SELECT " + RawContacts.STARRED 377dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " FROM " + Tables.RAW_CONTACTS + " WHERE " + RawContacts._ID + "=?"; 378dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 379e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public class AddressBookCursor extends CursorWrapper implements CrossProcessCursor { 380e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov private final CrossProcessCursor mCursor; 381e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov private final Bundle mBundle; 382e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 383e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public AddressBookCursor(CrossProcessCursor cursor, String[] titles, int[] counts) { 384e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov super(cursor); 385e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mCursor = cursor; 386e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle = new Bundle(); 387e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle.putStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES, titles); 388e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle.putIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, counts); 389e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 390e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 391e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 392e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public Bundle getExtras() { 393e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mBundle; 394e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 395e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 396e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 397e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public void fillWindow(int pos, CursorWindow window) { 398e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mCursor.fillWindow(pos, window); 399e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 400e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 401e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 402e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public CursorWindow getWindow() { 403e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mCursor.getWindow(); 404e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 405e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 406e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 407e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public boolean onMove(int oldPosition, int newPosition) { 408e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mCursor.onMove(oldPosition, newPosition); 409e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 410e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 411e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 412d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private interface DataContactsQuery { 413f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov public static final String TABLE = "data " 414f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) " 415f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)"; 41667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 41767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 4186cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov RawContactsColumns.CONCRETE_ID, 4196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_TYPE, 4206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_NAME, 42143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContactsColumns.CONCRETE_DATA_SET, 4223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 423f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov ContactsColumns.CONCRETE_ID 424ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 425ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 426d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov public static final int RAW_CONTACT_ID = 0; 4276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_TYPE = 1; 4286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_NAME = 2; 42943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_SET = 3; 43043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_ID = 4; 43143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int CONTACT_ID = 5; 432ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 4331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 434f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov interface RawContactsQuery { 43519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String TABLE = Tables.RAW_CONTACTS; 43619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 43719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String[] COLUMNS = new String[] { 438ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.DELETED, 439ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 440ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_NAME, 44143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.DATA_SET, 44219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka }; 44319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 44419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int DELETED = 0; 445ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_TYPE = 1; 446ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_NAME = 2; 44743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int DATA_SET = 3; 44819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 44919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 450c76cdd0723b99f478c9ba5329d14a971cd8dfb3dCostin Manolache public static final String DEFAULT_ACCOUNT_TYPE = "com.google"; 451caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 45271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov /** Sql where statement for filtering on groups. */ 45371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov private static final String CONTACTS_IN_GROUP_SELECT = 45471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov Contacts._ID + " IN " 45571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + RawContacts.CONTACT_ID 45671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.RAW_CONTACTS 45771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN " 45871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 45971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.DATA_JOIN_MIMETYPES 46071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 46171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 46271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + Tables.GROUPS + "." + Groups._ID 46371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.GROUPS 46471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Groups.TITLE + "=?)))"; 46571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov 466a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating DIRTY flag on multiple raw contacts */ 467a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_DIRTY_SQL = 468a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 469a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.DIRTY + "=1" + 470a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 471a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 472a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating VERSION on multiple raw contacts */ 473a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL = 474a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 475a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.VERSION + " = " + RawContacts.VERSION + " + 1" + 476a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 477a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 478c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Current contacts - those contacted within the last 3 days (in seconds) 479c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_CURRENT = 3 * 24 * 60 * 60; 480c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 481c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Recent contacts - those contacted within the last 30 days (in seconds) 482c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_RECENT = 30 * 24 * 60 * 60; 483c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 484f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa private static final String TIME_SINCE_LAST_USED = 485f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa "(strftime('%s', 'now') - " + DataUsageStatColumns.LAST_TIME_USED + "/1000)"; 486f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa 487c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov /* 488c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * Sorting order for email address suggestions: first starred, then the rest. 4892262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * second in_visible_group, then the rest. 4902262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * Within the four (starred/unstarred, in_visible_group/not-in_visible_group) groups 4912262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * - three buckets: very recently contacted, then fairly 492c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * recently contacted, then the rest. Within each of the bucket - descending count 49346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * of times contacted (both for data row and for contact row). If all else fails, alphabetical. 49446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * (Super)primary email address is returned before other addresses for the same contact. 495c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov */ 496c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final String EMAIL_FILTER_SORT_ORDER = 4972262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa Contacts.STARRED + " DESC, " 4982262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa + Contacts.IN_VISIBLE_GROUP + " DESC, " 499f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + "(CASE WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_CURRENT 50046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 0 " 501f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + " WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_RECENT 50246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 1 " 50346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " ELSE 2 END), " 50446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.TIMES_USED + " DESC, " 50546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Contacts.DISPLAY_NAME + ", " 50646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Data.CONTACT_ID + ", " 507c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_SUPER_PRIMARY + " DESC, " 508c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_PRIMARY + " DESC"; 50946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 51046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** Currently same as {@link #EMAIL_FILTER_SORT_ORDER} */ 51146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final String PHONE_FILTER_SORT_ORDER = EMAIL_FILTER_SORT_ORDER; 512c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 513916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Name lookup types used for contact filtering */ 514916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private static final String CONTACT_LOOKUP_NAME_TYPES = 515916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.NAME_COLLATION_KEY + "," + 516916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.EMAIL_BASED_NICKNAME + "," + 51792ddc5cdc4d89ee2c6e861ae7b3a3a913ffa0100Dmitri Plotnikov NameLookupType.NICKNAME; 518916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 519f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov /** 520f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * If any of these columns are used in a Data projection, there is no point in 521f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * using the DISTINCT keyword, which can negatively affect performance. 522f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov */ 523f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov private static final String[] DISTINCT_DATA_PROHIBITING_COLUMNS = { 524f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data._ID, 525f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.RAW_CONTACT_ID, 526f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.NAME_RAW_CONTACT_ID, 527f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 528f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 52943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.DATA_SET, 53043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 531f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.DIRTY, 532f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.NAME_VERIFIED, 533f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.SOURCE_ID, 534f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.VERSION, 535f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov }; 536916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 537f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsColumns = ProjectionMap.builder() 538f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CUSTOM_RINGTONE) 539f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME) 540f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_ALTERNATIVE) 541f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_SOURCE) 542f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.IN_VISIBLE_GROUP) 543f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LAST_TIME_CONTACTED) 544f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LOOKUP_KEY) 545f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME) 546f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME_STYLE) 547f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHOTO_ID) 548f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .add(Contacts.PHOTO_FILE_ID) 5493d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_URI) 5503d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_THUMBNAIL_URI) 551f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SEND_TO_VOICEMAIL) 552f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_ALTERNATIVE) 553f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_PRIMARY) 554f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.STARRED) 555f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.TIMES_CONTACTED) 556cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 557f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 558f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 559f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsPresenceColumns = ProjectionMap.builder() 560f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 561f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE) 562f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 563f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 564f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 565f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 566f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 567f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 568f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 569f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 570f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 571f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 572f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 573f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 574f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 575f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 576f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSnippetColumns = ProjectionMap.builder() 57703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov .add(SearchSnippetColumns.SNIPPET) 578f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 579f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 580f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactColumns = ProjectionMap.builder() 581f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_NAME) 582f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_TYPE) 58343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.DATA_SET) 58443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.ACCOUNT_TYPE_AND_DATA_SET) 585f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DIRTY) 586f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.NAME_VERIFIED) 587f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SOURCE_ID) 588f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.VERSION) 589f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 590f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 591f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactSyncColumns = ProjectionMap.builder() 592f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC1) 593f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC2) 594f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC3) 595f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC4) 596f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 597f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 598f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataColumns = ProjectionMap.builder() 599f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA1) 600f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA2) 601f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA3) 602f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA4) 603f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA5) 604f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA6) 605f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA7) 606f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA8) 607f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA9) 608f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA10) 609f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA11) 610f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA12) 611f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA13) 612f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA14) 613f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA15) 614f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA_VERSION) 615f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_PRIMARY) 616f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_SUPER_PRIMARY) 617f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.MIMETYPE) 618f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RES_PACKAGE) 619f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC1) 620f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC2) 621f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC3) 622f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC4) 623f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(GroupMembership.GROUP_SOURCE_ID) 624f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 625f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 626f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactPresenceColumns = ProjectionMap.builder() 627f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 628f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.PRESENCE) 629f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 630f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.CHAT_CAPABILITY) 631f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 632f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 633f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 634f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 635f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 636f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 637f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 638f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 639f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 640f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 641f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 642f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 643f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataPresenceColumns = ProjectionMap.builder() 644f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.PRESENCE, Tables.PRESENCE + "." + StatusUpdates.PRESENCE) 645f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CHAT_CAPABILITY, Tables.PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 646f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS, StatusUpdatesColumns.CONCRETE_STATUS) 647f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_TIMESTAMP, StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 648f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_RES_PACKAGE, StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 649f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_LABEL, StatusUpdatesColumns.CONCRETE_STATUS_LABEL) 650f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_ICON, StatusUpdatesColumns.CONCRETE_STATUS_ICON) 651f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 652f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 653038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana /** Contains just BaseColumns._COUNT */ 654f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sCountProjectionMap = ProjectionMap.builder() 655f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(BaseColumns._COUNT, "COUNT(*)") 656f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 657f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 658e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov /** Contains just the contacts columns */ 659f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionMap = ProjectionMap.builder() 660f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts._ID) 661f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 662f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.NAME_RAW_CONTACT_ID) 66324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 664f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 665f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsPresenceColumns) 666f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 667f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 668916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Contains just the contacts columns */ 669f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionWithSnippetMap = ProjectionMap.builder() 670f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 671f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sSnippetColumns) 672f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 673916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6745e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar /** Used for pushing starred contacts to the top of a times contacted list **/ 675f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentStarredProjectionMap = ProjectionMap.builder() 676f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 6772f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 678f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 679f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 680f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder() 681f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 6822f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, "SUM(" + DataUsageStatColumns.CONCRETE_TIMES_USED + ")") 683f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 684f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 6854928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 6864928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 6874928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. Right now Starred part just returns NULL for 6884928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * those data columns (frequent part should return real ones in data table). 6894928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 6904928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyStarredProjectionMap 6914928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 6924928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 6934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 6944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER, "NULL") 6954928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE, "NULL") 6964928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL, "NULL") 6974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 6984928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 6994928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 7004928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 7014928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. We hard-code {@link Contacts#IS_USER_PROFILE} to NULL, 7024928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * because sContactsProjectionMap specifies a field that doesn't exist in the view behind the 7034928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * query that uses this projection map. 7044928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 7054928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyFrequentProjectionMap 7064928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 7074928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 7084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, DataUsageStatColumns.CONCRETE_TIMES_USED) 7094928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER) 7104928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE) 7114928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL) 7124928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Contacts.IS_USER_PROFILE, "NULL") 7134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 715f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey /** Contains just the contacts vCard columns */ 716f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsVCardProjectionMap = ProjectionMap.builder() 717fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen .add(Contacts._ID) 718f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME + " || '.vcf'") 719f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.SIZE, "NULL") 720f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 721f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 722ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov /** Contains just the raw contacts columns */ 723f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactsProjectionMap = ProjectionMap.builder() 724f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 725f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 726f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 727f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_PRIMARY) 728f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_ALTERNATIVE) 729f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_SOURCE) 730f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME) 731f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME_STYLE) 732f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_PRIMARY) 733f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_ALTERNATIVE) 734f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.TIMES_CONTACTED) 735f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.LAST_TIME_CONTACTED) 736f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CUSTOM_RINGTONE) 737f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SEND_TO_VOICEMAIL) 738f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 739f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.AGGREGATION_MODE) 74024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 741f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 742f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 743f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 744f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 745a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the raw entity view*/ 746f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawEntityProjectionMap = ProjectionMap.builder() 747f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 748f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 749f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.Entity.DATA_ID) 750f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 751f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 75224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 753f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 754f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 755f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 756f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 757f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 758a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the contact entity view*/ 759f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sEntityProjectionMap = ProjectionMap.builder() 760f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity._ID) 761f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.CONTACT_ID) 762f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.RAW_CONTACT_ID) 763f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DATA_ID) 764f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.NAME_RAW_CONTACT_ID) 765f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DELETED) 76624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 767f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 768f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 769f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 770f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 771f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 772f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 773f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 774f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** Contains columns from the data view */ 776f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataProjectionMap = ProjectionMap.builder() 777f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID) 778f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RAW_CONTACT_ID) 779f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CONTACT_ID) 780f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.NAME_RAW_CONTACT_ID) 78124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 782f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 783f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 784f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 785f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 786f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 787f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 788f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7895e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov /** Contains columns from the data view */ 790f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDistinctDataProjectionMap = ProjectionMap.builder() 791f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID, "MIN(" + Data._ID + ")") 792f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 79324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 794f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 795f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 796f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 797f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 798f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 799f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 8009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data and contacts columns, for joined tables */ 801f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sPhoneLookupProjectionMap = ProjectionMap.builder() 802f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup._ID, "contacts_view." + Contacts._ID) 803f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LOOKUP_KEY, "contacts_view." + Contacts.LOOKUP_KEY) 804f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.DISPLAY_NAME, "contacts_view." + Contacts.DISPLAY_NAME) 805f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LAST_TIME_CONTACTED, "contacts_view." + Contacts.LAST_TIME_CONTACTED) 806f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TIMES_CONTACTED, "contacts_view." + Contacts.TIMES_CONTACTED) 807f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.STARRED, "contacts_view." + Contacts.STARRED) 808f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.IN_VISIBLE_GROUP, "contacts_view." + Contacts.IN_VISIBLE_GROUP) 809f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.PHOTO_ID, "contacts_view." + Contacts.PHOTO_ID) 8103d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_URI, "contacts_view." + Contacts.PHOTO_URI) 8113d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_THUMBNAIL_URI, "contacts_view." + Contacts.PHOTO_THUMBNAIL_URI) 812f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.CUSTOM_RINGTONE, "contacts_view." + Contacts.CUSTOM_RINGTONE) 813f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.HAS_PHONE_NUMBER, "contacts_view." + Contacts.HAS_PHONE_NUMBER) 814f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.SEND_TO_VOICEMAIL, "contacts_view." + Contacts.SEND_TO_VOICEMAIL) 815f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.NUMBER, Phone.NUMBER) 816f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TYPE, Phone.TYPE) 817f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LABEL, Phone.LABEL) 8182530512f639c4979fd7371c7dd25dd67e8118124Bai Tao .add(PhoneLookup.NORMALIZED_NUMBER, Phone.NORMALIZED_NUMBER) 819f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 820f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 821ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 822f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsProjectionMap = ProjectionMap.builder() 823f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups._ID) 824f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_NAME) 825f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_TYPE) 82643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.DATA_SET) 82743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.ACCOUNT_TYPE_AND_DATA_SET) 828f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SOURCE_ID) 829f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DIRTY) 830f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.VERSION) 831f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.RES_PACKAGE) 832f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE) 833f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE_RES) 834f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.GROUP_VISIBLE) 835f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYSTEM_ID) 836f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DELETED) 837f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.NOTES) 8381cdfc9dacc136e99d3c0bc5b4212bc3c973be337Daniel Lehmann .add(Groups.ACTION) 8391cdfc9dacc136e99d3c0bc5b4212bc3c973be337Daniel Lehmann .add(Groups.ACTION_URI) 840f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SHOULD_SYNC) 841f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.FAVORITES) 842f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.AUTO_ADD) 843c039cfb78c40730483fd71178df63ada5826a315Dmitri Plotnikov .add(Groups.GROUP_IS_READ_ONLY) 844f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC1) 845f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC2) 846f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC3) 847f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC4) 848f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 849f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 850ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains {@link Groups} columns along with summary details */ 851f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsSummaryProjectionMap = ProjectionMap.builder() 852f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sGroupsProjectionMap) 853f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_COUNT, 854f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 855f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 856f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")") 857f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_WITH_PHONES, 858f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 859f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 860f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " WHERE " + Contacts.HAS_PHONE_NUMBER + ")") 861f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .build(); 862f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa 863f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa // This is only exposed as hidden API for the contacts app, so we can be very specific in 864f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa // the filtering 865f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa private static final ProjectionMap sGroupsSummaryProjectionMapWithGroupCountPerAccount = 866f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa ProjectionMap.builder() 867f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .addAll(sGroupsSummaryProjectionMap) 868f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .add(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 869f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(*) FROM " + Views.GROUPS + " WHERE " 870f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + "(" + Groups.ACCOUNT_NAME + "=" 871f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + GroupsColumns.CONCRETE_ACCOUNT_NAME 872f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " AND " 873f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.ACCOUNT_TYPE + "=" + GroupsColumns.CONCRETE_ACCOUNT_TYPE 874f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " AND " 875f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.DELETED + "=0 AND " 876f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.FAVORITES + "=0 AND " 877f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.AUTO_ADD + "=0" 878f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")" 879f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " GROUP BY " 880f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.ACCOUNT_NAME + ", " + Groups.ACCOUNT_TYPE 881f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")") 882f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 883f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 884373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov /** Contains the agg_exceptions columns */ 885f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sAggregationExceptionsProjectionMap = ProjectionMap.builder() 886f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id") 887f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.TYPE) 888f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID1) 889f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID2) 890f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 891f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 892eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey /** Contains the agg_exceptions columns */ 893f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSettingsProjectionMap = ProjectionMap.builder() 894f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_NAME) 895f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_TYPE) 896f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_VISIBLE) 897f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.SHOULD_SYNC) 898f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ANY_UNSYNCED, 899f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN MIN(" + Settings.SHOULD_SYNC 900f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ",(SELECT " 901f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "(CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL" 902f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 903f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE MIN(" + Groups.SHOULD_SYNC + ")" 904f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)" 905f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.GROUPS 906f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 907f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_NAME 908f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 909f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_TYPE + "))=0" 910f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 911f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE 0" 912f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)") 913f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_COUNT, 914f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 915f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 916f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 917f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 918f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 919f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 920f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_WITH_PHONES, 921f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 922f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 923f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 924f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Contacts.HAS_PHONE_NUMBER 925f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 926f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 927f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 928f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 929f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 93082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov /** Contains StatusUpdates columns */ 931f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStatusUpdatesProjectionMap = ProjectionMap.builder() 932f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PresenceColumns.RAW_CONTACT_ID) 933f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.DATA_ID, DataColumns.CONCRETE_ID) 934f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_ACCOUNT) 935f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_HANDLE) 936f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PROTOCOL) 937f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 938f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // properly enforce uniqueness of null values 939f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CUSTOM_PROTOCOL, 940f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL + "=''" 941f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN NULL" 942f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END)") 943f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PRESENCE) 944f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CHAT_CAPABILITY) 945f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS) 946f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_TIMESTAMP) 947f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_RES_PACKAGE) 948f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_ICON) 949f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_LABEL) 950f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 951f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 9523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Contains StreamItems columns */ 9533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemsProjectionMap = ProjectionMap.builder() 9543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems._ID, StreamItemsColumns.CONCRETE_ID) 9553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(RawContacts.CONTACT_ID) 9563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_PACKAGE) 9583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_ICON) 9593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_LABEL) 9603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TEXT) 9613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TIMESTAMP) 9623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.COMMENTS) 9633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.ACTION) 9643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.ACTION_URI) 9653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemPhotosProjectionMap = ProjectionMap.builder() 9683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos._ID, StreamItemPhotosColumns.CONCRETE_ID) 9693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.STREAM_ITEM_ID) 9713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.SORT_INDEX) 9726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_FILE_ID) 9736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_URI, 9746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro "'" + DisplayPhoto.CONTENT_URI + "'||'/'||" + StreamItemPhotos.PHOTO_FILE_ID) 9753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.ACTION, StreamItemPhotosColumns.CONCRETE_ACTION) 9763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.ACTION_URI, StreamItemPhotosColumns.CONCRETE_ACTION_URI) 9771dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.HEIGHT) 9781dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.WIDTH) 9791dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.FILESIZE) 9803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9821b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov /** Contains Live Folders columns */ 983f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sLiveFoldersProjectionMap = ProjectionMap.builder() 984f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders._ID, Contacts._ID) 985f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders.NAME, Contacts.DISPLAY_NAME) 986f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // TODO: Put contact photo back when we have a way to display a default icon 987f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // for contacts without a photo 988f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // .add(LiveFolders.ICON_BITMAP, Photos.DATA) 989f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 990f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 991d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** Contains {@link Directory} columns */ 992f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDirectoryProjectionMap = ProjectionMap.builder() 993f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory._ID) 994f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.PACKAGE_NAME) 995f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.TYPE_RESOURCE_ID) 996f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DISPLAY_NAME) 997f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DIRECTORY_AUTHORITY) 998f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_TYPE) 999f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_NAME) 1000f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.EXPORT_SUPPORT) 1001778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.SHORTCUT_SUPPORT) 1002778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.PHOTO_SUPPORT) 1003f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 10047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10059705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // where clause to update the status_updates table 10069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE = 10079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID + 10089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE + 10099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE "; 10109705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 10112526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private static final String[] EMPTY_STRING_ARRAY = new String[0]; 10122526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1013bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1014bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Notification ID for failure to import contacts. 1015bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1016bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private static final int LEGACY_IMPORT_FAILED_NOTIFICATION = 1; 101751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 101803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_START_MATCH = "["; 101903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_END_MATCH = "]"; 102003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_ELLIPSIS = "..."; 102103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final int DEFAULT_SNIPPET_ARG_MAX_TOKENS = -10; 102203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 10239a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhoneInitialized; 10249a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhone; 10259a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 1026f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov private StringBuilder mSb = new StringBuilder(); 10271129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs1 = new String[1]; 10281129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs2 = new String[2]; 10292526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private ArrayList<String> mSelectionArgs = Lists.newArrayList(); 10302526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1031f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private Account mAccount; 1032f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 103346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 103446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Stores mapping from type Strings exposed via {@link DataUsageFeedback} to 103546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type integers in {@link DataUsageStatColumns}. 103646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 103746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final Map<String, Integer> sDataUsageTypeMap; 103846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 10394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 10404f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 1041a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 1042d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 1043d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 1044a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA); 1045a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES); 10463653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", 10473653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 10482d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", 10492d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov AGGREGATION_SUGGESTIONS); 1050a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO); 1051f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", 1052f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_ID_DISPLAY_PHOTO); 10533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", 10543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_ID_STREAM_ITEMS); 1055c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER); 10565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER); 10575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP); 10582149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA); 10595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID); 10602149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", 10612149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov CONTACTS_LOOKUP_ID_DATA); 1062f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", 1063f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_DISPLAY_PHOTO); 1064f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo", 1065f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_ID_DISPLAY_PHOTO); 1066a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities", 1067a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ENTITIES); 1068a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities", 1069a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ID_ENTITIES); 10703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items", 10713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_STREAM_ITEMS); 10723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items", 10733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_ID_STREAM_ITEMS); 1074f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD); 107542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*", 107642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann CONTACTS_AS_MULTI_VCARD); 10775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT); 1078ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*", 1079ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov CONTACTS_STREQUENT_FILTER); 10805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP); 108145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "contacts/frequent", CONTACTS_FREQUENT); 10823653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 10835ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); 10845ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); 10855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA); 1086f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/display_photo", 1087f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro RAW_CONTACTS_ID_DISPLAY_PHOTO); 108846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ENTITY_ID); 10893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items", 10903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RAW_CONTACTS_ID_STREAM_ITEMS); 109146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 109246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES); 1093b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 10944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 10954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 1096ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 109748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID); 10985e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER); 1099ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 11004a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS); 110148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID); 11021dac83b8fa58944acfd00f44e717a7dddc659d2dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP); 11035e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP); 11045e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER); 11054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER); 1106ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 110748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID); 110846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** "*" is in CSV form with data ids ("123,456,789") */ 110946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/usagefeedback/*", DATA_USAGE_FEEDBACK_ID); 11101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1111ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 1112ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 1113ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 1114ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 111535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 1116b5a4add17815167d20a90645779df34cdf45280dFred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#", 1117b5a4add17815167d20a90645779df34cdf45280dFred Quintana SYNCSTATE_ID); 111835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1119a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 1120b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 1121b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 1122b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 1123b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 11244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1125eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS); 1126eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 112782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES); 112882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID); 11291f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1130c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, 1131c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 1132c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 1133c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 11342d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 1135c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SHORTCUT); 1136c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 11371b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts", 11381b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS); 11391b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*", 11401b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_GROUP_NAME); 11411b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones", 11421b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_WITH_PHONES); 11431b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites", 11441b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_FAVORITES); 114509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 114609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS); 1147d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1148d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES); 1149d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID); 11507a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 11517a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME); 115224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 115324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile", PROFILE); 115424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/entities", PROFILE_ENTITIES); 115524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data", PROFILE_DATA); 115624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data/#", PROFILE_DATA_ID); 115724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/as_vcard", PROFILE_AS_VCARD); 115824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts", PROFILE_RAW_CONTACTS); 115924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#", 116024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID); 116124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/data", 116224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_DATA); 116324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/entity", 116424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_ENTITIES); 116546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 11663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items", STREAM_ITEMS); 11673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/photo", STREAM_ITEMS_PHOTOS); 11683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#", STREAM_ITEMS_ID); 11693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo", STREAM_ITEMS_ID_PHOTOS); 11703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo/#", 11713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann STREAM_ITEMS_ID_PHOTOS_ID); 11723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items_limit", STREAM_ITEMS_LIMIT); 11733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 1174f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "display_photo/*", DISPLAY_PHOTO); 1175f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS); 1176f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 117746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa HashMap<String, Integer> tmpTypeMap = new HashMap<String, Integer>(); 117846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_CALL, DataUsageStatColumns.USAGE_TYPE_INT_CALL); 117946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, 118046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT); 118146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, 118246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT); 118346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sDataUsageTypeMap = Collections.unmodifiableMap(tmpTypeMap); 118419a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov } 118519a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov 1186d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static class DirectoryInfo { 1187d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String authority; 1188d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountName; 1189d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountType; 1190d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 1191d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1192d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 1193d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Cached information about contact directories. 1194d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 11954458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private HashMap<String, DirectoryInfo> mDirectoryCache = new HashMap<String, DirectoryInfo>(); 11964458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private boolean mDirectoryCacheValid = false; 1197d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 11983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 119943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * An entry in group id cache. It maps the combination of (account type, account name, data set, 1200ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov * and source id) to group row id. 1201ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov */ 1202e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov public static class GroupIdCacheEntry { 1203ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType; 1204ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName; 120543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet; 1206ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String sourceId; 1207ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov long groupId; 1208ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov } 1209a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov 1210e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // We don't need a soft cache for groups - the assumption is that there will only 1211e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // be a small number of contact groups. The cache is keyed off source id. The value 1212e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // is a list of groups with this group id. 1213e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap(); 1214e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov 121524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 121624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Cached information about the contact ID and raw contact IDs that make up the user's 121724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile entry. 121824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 121924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static class ProfileIdCache { 122024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean inited; 122124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long profileContactId; 122224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Set<Long> profileRawContactIds = Sets.newHashSet(); 122324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Set<Long> profileDataIds = Sets.newHashSet(); 122424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 122524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 122624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Initializes the cache of profile contact and raw contact IDs. Does nothing if 122724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * the cache is already initialized (unless forceRefresh is set to true). 122824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param db The contacts database. 122924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forceRefresh Whether to force re-initialization of the cache. 123024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 123124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void init(SQLiteDatabase db, boolean forceRefresh) { 123224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!inited || forceRefresh) { 123324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileContactId = 0; 123424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactIds.clear(); 123524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileDataIds.clear(); 123624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Cursor c = db.rawQuery("SELECT " + 123724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_CONTACT_ID + "," + 123824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "," + 123924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro DataColumns.CONCRETE_ID + 124024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro " FROM " + Tables.RAW_CONTACTS + " JOIN " + Tables.ACCOUNTS + " ON " + 124124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "=" + 124224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro AccountsColumns.PROFILE_RAW_CONTACT_ID + 124324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro " JOIN " + Tables.DATA + " ON " + 124424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "=" + DataColumns.CONCRETE_RAW_CONTACT_ID, 124524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro null); 124624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro try { 124724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro while (c.moveToNext()) { 124824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (profileContactId == 0) { 124924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileContactId = c.getLong(0); 125024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 125124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactIds.add(c.getLong(1)); 125224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileDataIds.add(c.getLong(2)); 125324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 125424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } finally { 125524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro c.close(); 125624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 125724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 125824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 125924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 126024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 126124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private ProfileIdCache mProfileIdCache; 126224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1263f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1264f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of display photos. Larger images will be scaled 1265f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to fit. 1266f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1267f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxDisplayPhotoDim; 1268f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1269f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1270f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of photo thumbnails. 1271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxThumbnailPhotoDim; 1273f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private HashMap<String, DataRowHandler> mDataRowHandlers; 1275b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private ContactsDatabaseHelper mDbHelper; 127631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1277f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private PhotoStore mPhotoStore; 1278f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12794097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 1280f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private NameLookupBuilder mNameLookupBuilder; 1281315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov 1282622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private PostalSplitter mPostalSplitter; 1283622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey 128472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov private ContactDirectoryManager mContactDirectoryManager; 1285622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private ContactAggregator mContactAggregator; 1286f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 1287a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private GlobalSearchSupport mGlobalSearchSupport; 1288d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov private CommonNicknameCache mCommonNicknameCache; 1289f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov private SearchIndexManager mSearchIndexManager; 1290a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 129120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private ContentValues mValues = new ContentValues(); 129273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov private HashMap<String, Boolean> mAccountWritability = Maps.newHashMap(); 129320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 129409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private int mProviderStatus = ProviderStatus.STATUS_NORMAL; 12953826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private boolean mProviderStatusUpdateNeeded; 129609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private long mEstimatedStorageRequirement = 0; 129715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mReadAccessLatch; 129815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mWriteAccessLatch; 129915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private boolean mAccountUpdateListenerRegistered; 1300bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private boolean mOkToOpenAccess = true; 130173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 1302d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private TransactionContext mTransactionContext = new TransactionContext(); 1303de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov 13041a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey private boolean mVisibleTouched = false; 13051a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 130681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov private boolean mSyncToNetwork; 130781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 13084cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao private Locale mCurrentLocale; 13093826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private int mContactsAccountCount; 1310d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov 1311bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private HandlerThread mBackgroundThread; 1312bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private Handler mBackgroundHandler; 1313bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1314f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mLastPhotoCleanup = 0; 1315f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 13164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 13174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 1318de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov super.onCreate(); 1319ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov try { 1320ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return initialize(); 1321ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } catch (RuntimeException e) { 1322ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov Log.e(TAG, "Cannot start provider", e); 1323ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return false; 1324ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 1325ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 132635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1327ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov private boolean initialize() { 132815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov StrictMode.setThreadPolicy( 132915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 133015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 13313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Resources resources = getContext().getResources(); 1332f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxDisplayPhotoDim = resources.getInteger( 1333f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_display_photo_dim); 1334f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim = resources.getInteger( 1335f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_thumbnail_photo_dim); 13363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 133724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mProfileIdCache = new ProfileIdCache(); 1338b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper = (ContactsDatabaseHelper)getDatabaseHelper(); 133972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov mContactDirectoryManager = new ContactDirectoryManager(this); 1340a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov mGlobalSearchSupport = new GlobalSearchSupport(this); 134165ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov 1342bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // The provider is closed for business until fully initialized 134315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = new CountDownLatch(1); 134415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = new CountDownLatch(1); 134572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1346bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread = new HandlerThread("ContactsProviderWorker", 1347bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov Process.THREAD_PRIORITY_BACKGROUND); 1348bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread.start(); 1349bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler = new Handler(mBackgroundThread.getLooper()) { 1350bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov @Override 1351bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov public void handleMessage(Message msg) { 1352bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov performBackgroundTask(msg.what, msg.obj); 1353bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1354bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov }; 13552a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov 135615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_INITIALIZE); 1357bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1358bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 1359bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_LOCALE); 1360bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM); 136105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_SEARCH_INDEX); 1362bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_PROVIDER_STATUS); 136315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_OPEN_WRITE_ACCESS); 1364f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 13653826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 136649d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov return true; 13674f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 13684f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1369767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov /** 137051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * (Re)allocates all locale-sensitive structures. 137151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 137204b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov private void initForDefaultLocale() { 137315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 137415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mLegacyApiSupport = new LegacyApiSupport(context, mDbHelper, this, mGlobalSearchSupport); 13754cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mCurrentLocale = getLocale(); 137604b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov mNameSplitter = mDbHelper.createNameSplitter(); 13774cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter); 13784cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mPostalSplitter = new PostalSplitter(mCurrentLocale); 137951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov mCommonNicknameCache = new CommonNicknameCache(mDbHelper.getReadableDatabase()); 1380cdd03b2ba03718a7fa85663a2438136284a1557cBai Tao ContactLocaleUtils.getIntance().setLocale(mCurrentLocale); 13815b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator = new ContactAggregator(this, mDbHelper, 138215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 13835b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 1384f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov mSearchIndexManager = new SearchIndexManager(this); 138524bc499d6756e7b2bd95b2eabb64a6d9d13435baDave Santoro mPhotoStore = new PhotoStore(getContext().getFilesDir(), mDbHelper); 13865b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 1387bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers = new HashMap<String, DataRowHandler>(); 1388bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1389bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, 13906d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForEmail(context, mDbHelper, mContactAggregator)); 1391bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE, 13926d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForIm(context, mDbHelper, mContactAggregator)); 1393bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, 13946d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForOrganization(context, mDbHelper, mContactAggregator)); 1395bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, 13966d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForPhoneNumber(context, mDbHelper, mContactAggregator)); 1397bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, 13986d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForNickname(context, mDbHelper, mContactAggregator)); 1399bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE, 14006d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForStructuredName(context, mDbHelper, mContactAggregator, 1401bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mNameSplitter, mNameLookupBuilder)); 1402bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(StructuredPostal.CONTENT_ITEM_TYPE, 14036d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForStructuredPostal(context, mDbHelper, mContactAggregator, 1404bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mPostalSplitter)); 1405bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE, 14066d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForGroupMembership(context, mDbHelper, mContactAggregator, 1407bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mGroupIdCache)); 1408bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Photo.CONTENT_ITEM_TYPE, 1409f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new DataRowHandlerForPhoto(context, mDbHelper, mContactAggregator, mPhotoStore)); 14106d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov mDataRowHandlers.put(Note.CONTENT_ITEM_TYPE, 14116d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForNote(context, mDbHelper, mContactAggregator)); 1412bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1413bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1414bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /** 1415bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Visible for testing. 1416bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov */ 1417bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /* package */ PhotoPriorityResolver createPhotoPriorityResolver(Context context) { 1418bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov return new PhotoPriorityResolver(context); 1419bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1420bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1421bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task) { 1422bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendEmptyMessage(task); 1423bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1424bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1425bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task, Object arg) { 1426bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(task, arg)); 1427bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1428bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1429bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void performBackgroundTask(int task, Object arg) { 1430bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov switch (task) { 143115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_INITIALIZE: { 143215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov initForDefaultLocale(); 143315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch.countDown(); 143415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = null; 143515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov break; 143615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 143715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 143815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_OPEN_WRITE_ACCESS: { 1439bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (mOkToOpenAccess) { 144015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch.countDown(); 144115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = null; 1442bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1443bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1444bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1445bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1446bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS: { 1447bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isLegacyContactImportNeeded()) { 1448bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov importLegacyContactsInBackground(); 1449bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1450bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1451bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1452bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1453bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_ACCOUNTS: { 145415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 145515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (!mAccountUpdateListenerRegistered) { 145615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov AccountManager.get(context).addOnAccountsUpdatedListener(this, null, false); 145715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mAccountUpdateListenerRegistered = true; 145815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 145915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 146015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Account[] accounts = AccountManager.get(context).getAccounts(); 1461bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov boolean accountsChanged = updateAccountsInBackground(accounts); 1462bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateContactsAccountCount(accounts); 1463bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateDirectoriesInBackground(accountsChanged); 1464bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1465bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1466bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1467bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_LOCALE: { 1468bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateLocaleInBackground(); 1469bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1470bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1471bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1472fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov case BACKGROUND_TASK_CHANGE_LOCALE: { 1473fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov changeLocaleInBackground(); 1474fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov break; 1475fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1476fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1477bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM: { 1478bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isAggregationUpgradeNeeded()) { 1479bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov upgradeAggregationAlgorithmInBackground(); 1480bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1481bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1482bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1483bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 148405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_SEARCH_INDEX: { 148505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov updateSearchIndexInBackground(); 148605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov break; 148705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 148805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1489bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_PROVIDER_STATUS: { 1490bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateProviderStatus(); 1491bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1492bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1493bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1494bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_DIRECTORIES: { 1495bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (arg != null) { 1496bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.onPackageChanged((String) arg); 1497bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1498bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1499bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1500f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1501f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case BACKGROUND_TASK_CLEANUP_PHOTOS: { 1502f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check rate limit. 1503f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long now = System.currentTimeMillis(); 1504f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (now - mLastPhotoCleanup > PHOTO_CLEANUP_RATE_LIMIT) { 1505f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mLastPhotoCleanup = now; 1506f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupPhotoStore(); 1507f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro break; 1508f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1509f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1510bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 15114cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 15124cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao 151353fac8f99f3884c372c907a76766d27fa9e1d95fDmitri Plotnikov public void onLocaleChanged() { 15143826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 15153826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 15164f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov return; 15174f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov } 15184f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov 1519fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_CHANGE_LOCALE); 15204cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 152151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 152251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov /** 152351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * Verifies that the contacts database is properly configured for the current locale. 152451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * If not, changes the database locale to the current locale using an asynchronous task. 152551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * This needs to be done asynchronously because the process involves rebuilding 152651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * large data structures (name lookup, sort keys), which can take minutes on 152751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * a large set of contacts. 152851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 1529bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateLocaleInBackground() { 1530f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 1531f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov // The process is already running - postpone the change 1532f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov if (mProviderStatus == ProviderStatus.STATUS_CHANGING_LOCALE) { 1533f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov return; 1534f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov } 1535f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 153651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 153751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final String providerLocale = prefs.getString(PREF_LOCALE, null); 153851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final Locale currentLocale = mCurrentLocale; 153951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov if (currentLocale.toString().equals(providerLocale)) { 154051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov return; 154151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 154251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 154351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov int providerStatus = mProviderStatus; 154451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_CHANGING_LOCALE); 1545bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDbHelper.setLocale(this, currentLocale); 1546bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).apply(); 1547bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov setProviderStatus(providerStatus); 1548bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 154951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 1550fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov /** 1551fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov * Reinitializes the provider for a new locale. 1552fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov */ 1553fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov private void changeLocaleInBackground() { 1554fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Re-initializing the provider without stopping it. 1555fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Locking the database will prevent inserts/updates/deletes from 1556fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // running at the same time, but queries may still be running 1557fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // on other threads. Those queries may return inconsistent results. 1558fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov SQLiteDatabase db = mDbHelper.getWritableDatabase(); 1559fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.beginTransaction(); 1560fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov try { 1561fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov initForDefaultLocale(); 1562fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.setTransactionSuccessful(); 1563fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } finally { 1564fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.endTransaction(); 1565fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1566fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1567fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov updateLocaleInBackground(); 1568fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1569fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 157005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov protected void updateSearchIndexInBackground() { 157105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov mSearchIndexManager.updateIndex(); 157205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 157305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1574bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateDirectoriesInBackground(boolean rescan) { 1575bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanAllPackages(rescan); 157651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 157751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 15783826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateProviderStatus() { 15793826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 15803826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 15813826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return; 15823826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15833826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 15843826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mContactsAccountCount == 0 158549d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov && DatabaseUtils.queryNumEntries(mDbHelper.getReadableDatabase(), 158649d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Tables.CONTACTS, null) == 0) { 15873826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 15883826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } else { 15893826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 15903826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15913826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15923826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 159331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* Visible for testing */ 1594f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro protected void cleanupPhotoStore() { 15956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro SQLiteDatabase db = mDbHelper.getWritableDatabase(); 15966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 15976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Assemble the set of photo store file IDs that are in use, and send those to the photo 1598f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // store. Any photos that aren't in that set will be deleted, and any photos that no 1599f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // longer exist in the photo store will be returned for us to clear out in the DB. 16006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = db.query(Views.DATA, new String[]{Data._ID, Photo.PHOTO_FILE_ID}, 1601f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.MIMETYPE + "=" + Photo.MIMETYPE + " AND " 1602f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro + Photo.PHOTO_FILE_ID + " IS NOT NULL", null, null, null, null); 16036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> usedPhotoFileIds = Sets.newHashSet(); 16046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToDataId = Maps.newHashMap(); 1605f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1606f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro while (c.moveToNext()) { 16076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = c.getLong(0); 16086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(1); 16096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 16106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToDataId.put(photoFileId, dataId); 16116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 16126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 16136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 16146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 16156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 16166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Also query for all social stream item photos. 16176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c = db.query(Tables.STREAM_ITEM_PHOTOS, 16186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{ 16196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos._ID, 16206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.STREAM_ITEM_ID, 16216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.PHOTO_FILE_ID 16226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro }, 16236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro null, null, null, null, null); 16246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToStreamItemPhotoId = Maps.newHashMap(); 16256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> streamItemPhotoIdToStreamItemId = Maps.newHashMap(); 16266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 16276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro while (c.moveToNext()) { 16286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = c.getLong(0); 16296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = c.getLong(1); 16306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(2); 16316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 16326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToStreamItemPhotoId.put(photoFileId, streamItemPhotoId); 16336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemPhotoIdToStreamItemId.put(streamItemPhotoId, streamItemId); 1634f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1635f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 1636f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 1637f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1638f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1639f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Run the photo store cleanup. 16406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> missingPhotoIds = mPhotoStore.cleanup(usedPhotoFileIds); 1641f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1642f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If any of the keys we're using no longer exist, clean them up. 16436802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!missingPhotoIds.isEmpty()) { 1644f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 16456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro for (long missingPhotoId : missingPhotoIds) { 16466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToDataId.containsKey(missingPhotoId)) { 16476802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = photoFileIdToDataId.get(missingPhotoId); 1648f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 1649f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.putNull(Photo.PHOTO_FILE_ID); 1650f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ops.add(ContentProviderOperation.newUpdate( 16516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentUris.withAppendedId(Data.CONTENT_URI, dataId)) 1652f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .withValues(updateValues).build()); 1653f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 16546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToStreamItemPhotoId.containsKey(missingPhotoId)) { 16556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For missing photos that were in stream item photos, just delete the stream 16566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // item photo. 16576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = photoFileIdToStreamItemPhotoId.get(missingPhotoId); 16586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = streamItemPhotoIdToStreamItemId.get(streamItemPhotoId); 16596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ops.add(ContentProviderOperation.newDelete( 16606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.CONTENT_URI.buildUpon() 16616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemId)) 16626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY) 16636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemPhotoId)) 16646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .build()).build()); 16656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 1666f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1667f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1668f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro applyBatch(ops); 1669f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (OperationApplicationException oae) { 1670f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Not a fatal problem (and we'll try again on the next cleanup). 1671f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Failed to clean up outdated photo references", oae); 1672f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1673f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1674f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1675f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1676f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* Visible for testing */ 1677de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov @Override 1678b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 1679b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return ContactsDatabaseHelper.getInstance(context); 168031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 168131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1682524913c66ce75ca8dec127ac88e3bc2249c246d9Dave Santoro @VisibleForTesting 1683f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* package */ PhotoStore getPhotoStore() { 1684f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return mPhotoStore; 1685f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1686f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 168787614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxDisplayPhotoDim() { 168887614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxDisplayPhotoDim; 168987614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 169087614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 169187614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxThumbnailPhotoDim() { 169287614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxThumbnailPhotoDim; 169387614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 169487614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1695013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov /* package */ NameSplitter getNameSplitter() { 1696013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov return mNameSplitter; 1697013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov } 1698013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov 16995df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov /* package */ NameLookupBuilder getNameLookupBuilder() { 17005df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov return mNameLookupBuilder; 17015df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov } 17025df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov 17035dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov /* Visible for testing */ 1704ed78fd6df5e9f3a2d572162e5d374d1f4a625bddDmitri Plotnikov public ContactDirectoryManager getContactDirectoryManagerForTest() { 170572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov return mContactDirectoryManager; 170672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 170772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 170872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov /* Visible for testing */ 17095dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov protected Locale getLocale() { 17105dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov return Locale.getDefault(); 17115dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov } 17125dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 17133d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov protected boolean isLegacyContactImportNeeded() { 1714b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_CONTACTS_IMPORTED, "0")); 1715b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov return version < PROPERTY_CONTACTS_IMPORT_VERSION; 17163d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17173d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1718568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov protected LegacyContactImporter getLegacyContactImporter() { 1719568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return new LegacyContactImporter(getContext(), this); 1720568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1721568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1722568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 1723bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Imports legacy contacts as a background task. 1724568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 1725bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private void importLegacyContactsInBackground() { 1726bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Importing legacy contacts"); 1727bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADING); 1728568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1729bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 1730bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDbHelper.setLocale(this, mCurrentLocale); 1731bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, mCurrentLocale.toString()).commit(); 1732568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1733bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov LegacyContactImporter importer = getLegacyContactImporter(); 1734bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (importLegacyContacts(importer)) { 1735bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportSuccess(); 1736bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } else { 1737bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportFailure(); 1738bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1739568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1740568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1741bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1742bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Unlocks the provider and declares that the import process is complete. 1743bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1744bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportSuccess() { 1745bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1746bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)getContext().getSystemService(Context.NOTIFICATION_SERVICE); 1747bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.cancel(LEGACY_IMPORT_FAILED_NOTIFICATION); 1748bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1749b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov // Store a property in the database indicating that the conversion process succeeded 1750b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov mDbHelper.setProperty(PROPERTY_CONTACTS_IMPORTED, 1751b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov String.valueOf(PROPERTY_CONTACTS_IMPORT_VERSION)); 1752bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 1753bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Completed import of legacy contacts"); 1754bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1755bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1756bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1757bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Announces the provider status and keeps the provider locked. 1758bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1759bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportFailure() { 1760bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Context context = getContext(); 1761bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1762bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); 1763bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1764bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // Show a notification 1765bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Notification n = new Notification(android.R.drawable.stat_notify_error, 1766bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_ticker), 1767bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov System.currentTimeMillis()); 1768bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.setLatestEventInfo(context, 1769bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_title), 1770bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_text), 1771bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov PendingIntent.getActivity(context, 0, new Intent(Intents.UI.LIST_DEFAULT), 0)); 1772bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; 1773bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1774bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.notify(LEGACY_IMPORT_FAILED_NOTIFICATION, n); 1775bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1776bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADE_OUT_OF_MEMORY); 1777bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Failed to import legacy contacts"); 1778bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1779bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // Do not let any database changes until this issue is resolved. 1780bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mOkToOpenAccess = false; 17813d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17823d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 17833d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /* Visible for testing */ 1784568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /* package */ boolean importLegacyContacts(LegacyContactImporter importer) { 17850e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff boolean aggregatorEnabled = mContactAggregator.isEnabled(); 17863d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov mContactAggregator.setEnabled(false); 17873d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov try { 1788bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (importer.importContacts()) { 1789bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1790bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // TODO aggregate all newly added raw contacts 1791bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mContactAggregator.setEnabled(aggregatorEnabled); 1792bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return true; 1793bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 17943d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } catch (Throwable e) { 17953d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov Log.e(TAG, "Legacy contact import failed", e); 17963d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 1797bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mEstimatedStorageRequirement = importer.getEstimatedStorageRequirement(); 1798bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return false; 17993d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 18003d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1801a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 1802a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 1803a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 1804a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /* package */ void wipeData() { 1805b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.wipeData(); 1806f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mPhotoStore.clear(); 18073826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS; 1808a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 1809a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1810568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 181115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov * During intialization, this content provider will 1812568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * block all attempts to change contacts data. In particular, it will hold 1813568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * up all contact syncs. As soon as the import process is complete, all 1814568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * processes waiting to write to the provider are unblocked and can proceed 1815568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * to compete for the database transaction monitor. 1816568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 181715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private void waitForAccess(CountDownLatch latch) { 181815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (latch == null) { 181915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 182015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 182115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 182215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov while (true) { 182315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov try { 182415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov latch.await(); 182515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 182615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } catch (InterruptedException e) { 182715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Thread.currentThread().interrupt(); 1828ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov } 1829568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1830568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1831568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1832568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1833568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public Uri insert(Uri uri, ContentValues values) { 183415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1835568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.insert(uri, values); 1836568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1837568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1838568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1839568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 184015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (mWriteAccessLatch != null) { 1841bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // We are stuck trying to upgrade contacts db. The only update request 1842bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // allowed in this case is an update of provider status, which will trigger 1843bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // an attempt to upgrade contacts again. 1844bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov int match = sUriMatcher.match(uri); 1845bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (match == PROVIDER_STATUS) { 1846bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Integer newStatus = values.getAsInteger(ProviderStatus.STATUS); 1847bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (newStatus != null && newStatus == ProviderStatus.STATUS_UPGRADING) { 1848bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1849bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 1; 1850bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } else { 1851bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 0; 1852bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1853bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1854bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 185515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1856568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.update(uri, values, selection, selectionArgs); 1857568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1858568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1859568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1860568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int delete(Uri uri, String selection, String[] selectionArgs) { 186115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1862568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.delete(uri, selection, selectionArgs); 1863568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1864568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1865568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1866568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 1867568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov throws OperationApplicationException { 186815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1869568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.applyBatch(operations); 1870568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1871568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 18724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 18737b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov public int bulkInsert(Uri uri, ContentValues[] values) { 18747b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov waitForAccess(mWriteAccessLatch); 18757b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov return super.bulkInsert(uri, values); 18767b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov } 18777b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov 18787b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov @Override 1879285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void onBeginTransaction() { 1880bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1881b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "onBeginTransaction"); 1882b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1883285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.onBeginTransaction(); 18841ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana mContactAggregator.clearPendingAggregations(); 1885d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.clear(); 1886b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1887b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1888285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 1889285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 1890285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void beforeTransactionCommit() { 18911129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 1892bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1893b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "beforeTransactionCommit"); 1894b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1895285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.beforeTransactionCommit(); 1896b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 1897bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateInTransaction(mTransactionContext, mDb); 18981a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (mVisibleTouched) { 18991a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = false; 1900b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.updateAllVisible(); 19011a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey } 19023826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 1903bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 1904bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 19053826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatusUpdateNeeded) { 19063826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 19073826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = false; 19083826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 1909b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1910b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1911bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov private void updateSearchIndexInTransaction() { 1912bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov Set<Long> staleContacts = mTransactionContext.getStaleSearchIndexContactIds(); 1913bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov Set<Long> staleRawContacts = mTransactionContext.getStaleSearchIndexRawContactIds(); 1914bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov if (!staleContacts.isEmpty() || !staleRawContacts.isEmpty()) { 1915bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mSearchIndexManager.updateIndexForRawContacts(staleContacts, staleRawContacts); 1916bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mTransactionContext.clearSearchIndexUpdates(); 1917bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 1918bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 1919bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 1920b5a4add17815167d20a90645779df34cdf45280dFred Quintana private void flushTransactionalChanges() { 1921bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1922b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "flushTransactionChanges"); 1923b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 19241129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 192524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Determine whether we need to refresh the profile ID cache. 192624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean profileCacheRefreshNeeded = false; 192724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1928d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov for (long rawContactId : mTransactionContext.getInsertedRawContactIds()) { 19298ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(mDb, rawContactId); 1930bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.onRawContactInsert(mTransactionContext, mDb, rawContactId); 1931285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 1932b5a4add17815167d20a90645779df34cdf45280dFred Quintana 193343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Map<Long, AccountWithDataSet> insertedProfileRawContactAccountMap = 193424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.getInsertedProfileRawContactIds(); 193524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!insertedProfileRawContactAccountMap.isEmpty()) { 193624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro for (long profileRawContactId : insertedProfileRawContactAccountMap.keySet()) { 193724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mDbHelper.updateRawContactDisplayName(mDb, profileRawContactId); 193824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mContactAggregator.onProfileRawContactInsert(mTransactionContext, mDb, 193924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactId, 194024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro insertedProfileRawContactAccountMap.get(profileRawContactId)); 194124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 194224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = true; 194324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 194424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1945d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov Set<Long> dirtyRawContacts = mTransactionContext.getDirtyRawContactIds(); 1946d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!dirtyRawContacts.isEmpty()) { 1947a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 1948a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL); 1949d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, dirtyRawContacts); 1950a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 1951a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mDb.execSQL(mSb.toString()); 195224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 195324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = profileCacheRefreshNeeded || 195424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro !Collections.disjoint(mProfileIdCache.profileRawContactIds, dirtyRawContacts); 1955a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov } 1956a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 1957d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov Set<Long> updatedRawContacts = mTransactionContext.getUpdatedRawContactIds(); 1958d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!updatedRawContacts.isEmpty()) { 1959a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 1960a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL); 1961d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, updatedRawContacts); 1962a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 1963a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mDb.execSQL(mSb.toString()); 196424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 196524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = profileCacheRefreshNeeded || 196624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro !Collections.disjoint(mProfileIdCache.profileRawContactIds, updatedRawContacts); 1967b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1968b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1969d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov for (Map.Entry<Long, Object> entry : mTransactionContext.getUpdatedSyncStates()) { 1970b5a4add17815167d20a90645779df34cdf45280dFred Quintana long id = entry.getKey(); 19719d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana if (mDbHelper.getSyncState().update(mDb, id, entry.getValue()) <= 0) { 19729d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana throw new IllegalStateException( 19739d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana "unable to update sync state, does it still exist?"); 19749d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana } 1975b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1976b5a4add17815167d20a90645779df34cdf45280dFred Quintana 197724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (profileCacheRefreshNeeded) { 197824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Force the profile ID cache to refresh. 197924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mProfileIdCache.init(mDb, true); 198024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 198124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1982d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.clear(); 1983b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1984b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1985a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** 1986a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * Appends comma separated ids. 1987a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * @param ids Should not be empty 1988a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov */ 1989d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private void appendIds(StringBuilder sb, Set<Long> ids) { 1990b5a4add17815167d20a90645779df34cdf45280dFred Quintana for (long id : ids) { 1991a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(id).append(','); 1992b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1993a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 1994a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.setLength(sb.length() - 1); // Yank the last comma 1995285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 1996285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 199724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 199824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given contact ID represents the user's personal profile - if it is, calls 199924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * a permission check (for writing the profile if forWrite is true, for reading the profile 200024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * otherwise). If the contact ID is not the user's profile, no check is executed. 2001afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 200224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param contactId The contact ID to be checked. 200324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 200424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 2005afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForContact(SQLiteDatabase db, long contactId, 2006afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro boolean forWrite) { 2007afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 200824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileContactId == contactId) { 200924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 201024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 201124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 201224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 201324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 201424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given raw contact ID is a member of the user's personal profile - if it 201524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * is, calls a permission check (for writing the profile if forWrite is true, for reading the 201624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile otherwise). If the raw contact ID is not in the user's profile, no check is 201724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * executed. 2018afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 201924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param rawContactId The raw contact ID to be checked. 202024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 202124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 2022afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForRawContact(SQLiteDatabase db, long rawContactId, 2023afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro boolean forWrite) { 2024afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 202524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileRawContactIds.contains(rawContactId)) { 202624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 202724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 202824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 202924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 203024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 203124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given data ID is a member of the user's personal profile - if it is, 203224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * calls a permission check (for writing the profile if forWrite is true, for reading the 203324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile otherwise). If the data ID is not in the user's profile, no check is executed. 2034afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 203524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param dataId The data ID to be checked. 203624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 203724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 2038afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForData(SQLiteDatabase db, long dataId, boolean forWrite) { 2039afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 204024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileDataIds.contains(dataId)) { 204124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 204224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 204324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 204424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 204524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 204624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Performs a permission check for WRITE_PROFILE or READ_PROFILE (depending on the parameter). 204724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * If the permission check fails, this will throw a SecurityException. 204824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 204924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 205024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void enforceProfilePermission(boolean forWrite) { 205124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String profilePermission = forWrite 205224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro ? "android.permission.WRITE_PROFILE" 205324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro : "android.permission.READ_PROFILE"; 205424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro getContext().enforceCallingOrSelfPermission(profilePermission, null); 205524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 205624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2057285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2058cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov protected void notifyChange() { 205981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov notifyChange(mSyncToNetwork); 206081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = false; 206181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 206281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 206381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov protected void notifyChange(boolean syncToNetwork) { 206481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null, 206581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov syncToNetwork); 2066cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov } 2067568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 206851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov protected void setProviderStatus(int status) { 20693826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != status) { 20703826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = status; 20713826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov getContext().getContentResolver().notifyChange(ProviderStatus.CONTENT_URI, null, false); 20723826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 207351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 207451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 2075f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public DataRowHandler getDataRowHandler(final String mimeType) { 20763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataRowHandler handler = mDataRowHandlers.get(mimeType); 20773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (handler == null) { 20786d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov handler = new DataRowHandlerForCustomMimetype( 20796d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov getContext(), mDbHelper, mContactAggregator, mimeType); 20803cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(mimeType, handler); 20813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 20823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return handler; 20833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 20843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 20854f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 2086de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected Uri insertInTransaction(Uri uri, ContentValues values) { 2087bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 20881129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Log.v(TAG, "insertInTransaction: " + uri + " " + values); 2089b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2090f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2091f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 2092f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 2093f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2094a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 2095a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 209635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2097a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 209835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 2099b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov id = mDbHelper.getSyncState().insert(mDb, values); 210035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 210135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2102d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 2103d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov insertContact(values); 21046bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 21056bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 21066bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 210724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 210824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro throw new UnsupportedOperationException( 210924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "The profile contact is created automatically"); 211024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 211124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 21125ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 211324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter, false); 2114f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2115a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2116a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2117a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21185ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 21195ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 2120f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2121f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2122a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2123a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2124a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 21263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItems.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 21273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 21283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 213224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 213324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(true); 213424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter, true); 213524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mSyncToNetwork |= !callerIsSyncAdapter; 213624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 213724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 213824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2139a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case DATA: { 2140f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2141f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2142a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2143a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2144a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2145ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 2146f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov id = insertGroup(uri, values, callerIsSyncAdapter); 2147f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2148ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2149ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2150ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2151eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 21525aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey id = insertSettings(uri, values); 215343880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 2154eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 2155eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 2156eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 215782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 215882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov id = insertStatusUpdate(values); 21591f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 21601f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 21611f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 21623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 21633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 21643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 21683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 21693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 21703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 21743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 21753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItemPhotos.STREAM_ITEM_ID, uri.getPathSegments().get(1)); 21763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 21773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2181a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 218281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 2183f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 2184a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2185a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 21877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 21887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 21897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2190de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return ContentUris.withAppendedId(uri, id); 2191a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2192a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2193a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2194e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * If account is non-null then store it in the values. If the account is 2195e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * already specified in the values then it must be consistent with the 2196e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * account, if it is non-null. 2197e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * 2198e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param uri Current {@link Uri} being operated on. 2199e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param values {@link ContentValues} to read and possibly update. 2200e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when only one of 2201e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_NAME} or 2202e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the 2203e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * other undefined. 2204e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME} 2205e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between 2206e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * the given {@link Uri} and {@link ContentValues}. 22077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 2208e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException { 2209f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 2210f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 2211e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 2212f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2213f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME); 2214f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 2215e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialValues = TextUtils.isEmpty(valueAccountName) 2216e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey ^ TextUtils.isEmpty(valueAccountType); 2217e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2218e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri || partialValues) { 2219e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 2220fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 2221fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 2222e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2223e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2224e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 2225e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 2226e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validUri = !TextUtils.isEmpty(accountName); 2227e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validValues = !TextUtils.isEmpty(valueAccountName); 2228e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2229e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validValues && validUri) { 2230e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Check that accounts match when both present 2231e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean accountMatch = TextUtils.equals(accountName, valueAccountName) 2232e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey && TextUtils.equals(accountType, valueAccountType); 2233e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (!accountMatch) { 2234fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 2235fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "When both specified, ACCOUNT_NAME and ACCOUNT_TYPE must match", uri)); 2236e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2237e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validUri) { 2238e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Fill values from Uri when not present 2239f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_NAME, accountName); 2240f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_TYPE, accountType); 2241e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validValues) { 2242f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountName = valueAccountName; 2243f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountType = valueAccountType; 2244e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else { 2245e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return null; 2246f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 2247f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2248e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Use cached Account object when matches, otherwise create 2249f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mAccount == null 2250f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.name.equals(accountName) 2251f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.type.equals(accountType)) { 2252f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mAccount = new Account(accountName, accountType); 2253035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 2254f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2255e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return mAccount; 22567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 22577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 22587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 225943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Resolves the account and builds an {@link AccountWithDataSet} based on the data set specified 226043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * in the URI or values (if any). 226143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param uri Current {@link Uri} being operated on. 226243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param values {@link ContentValues} to read and possibly update. 226343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro */ 226443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private AccountWithDataSet resolveAccountWithDataSet(Uri uri, ContentValues values) { 22653593682b8d9213fde576a0cff54458ad50563980Dave Santoro final Account account = resolveAccount(uri, values); 226643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = null; 226743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (account != null) { 226843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 226943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (dataSet == null) { 22703593682b8d9213fde576a0cff54458ad50563980Dave Santoro dataSet = values.getAsString(RawContacts.DATA_SET); 2271a71dc460ca951c7aca591f3f470c160cde70a1e3Dave Santoro } else { 22723593682b8d9213fde576a0cff54458ad50563980Dave Santoro values.put(RawContacts.DATA_SET, dataSet); 227343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 227443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet = new AccountWithDataSet(account.name, account.type, dataSet); 227543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 227643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro return accountWithDataSet; 227743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 227843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 227943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro /** 2280d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov * Inserts an item in the contacts table 22816bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 22826bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 22836bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 22846bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 2285d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private long insertContact(ContentValues values) { 2286de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new UnsupportedOperationException("Aggregate contacts are created automatically"); 22876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 22886bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 22896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 229024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Inserts an item in the raw contacts table 2291a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2292f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param uri the values for the new row 2293f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param values the account this contact should be associated with. may be null. 2294dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana * @param callerIsSyncAdapter 229524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forProfile Whether this raw contact is being inserted into the user's profile. 2296a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2297a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 229824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private long insertRawContact(Uri uri, ContentValues values, boolean callerIsSyncAdapter, 229924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean forProfile) { 2300f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2301f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2302f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 2303f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 230443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = resolveAccountWithDataSet(uri, mValues); 23057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 23063d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov if (values.containsKey(RawContacts.DELETED) 23073d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov && values.getAsInteger(RawContacts.DELETED) != 0) { 2308f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 23093d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 23103d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2311f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov long rawContactId = mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, mValues); 2312f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = RawContacts.AGGREGATION_MODE_DEFAULT; 231324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (forProfile) { 231424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Profile raw contacts should never be aggregated by the aggregator; they are always 231524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // aggregated under a single profile contact. 231624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro aggregationMode = RawContacts.AGGREGATION_MODE_DISABLED; 231724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else if (mValues.containsKey(RawContacts.AGGREGATION_MODE)) { 2318f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov aggregationMode = mValues.getAsInteger(RawContacts.AGGREGATION_MODE); 2319f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 2320f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov mContactAggregator.markNewForAggregation(rawContactId, aggregationMode); 2321285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 232224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (forProfile) { 232324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Trigger creation of the user profile Contact (or association with the existing one) 232424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // at the end of the transaction. 232543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mTransactionContext.profileRawContactInserted(rawContactId, accountWithDataSet); 232624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else { 232724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Trigger creation of a Contact based on this RawContact at the end of transaction 232843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mTransactionContext.rawContactInserted(rawContactId, accountWithDataSet); 232924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 2330f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2331dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 2332dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 2333dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long starred = values.getAsLong(RawContacts.STARRED); 2334dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (starred != null && starred != 0) { 2335dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred != 0); 2336dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2337dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2338dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 23393826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 2340023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov return rawContactId; 2341a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2342a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2343dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void addAutoAddMembership(long rawContactId) { 2344dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID, 2345dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2346dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2347dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2348dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2349dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2350dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2351dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private Long findGroupByRawContactId(String selection, long rawContactId) { 2352dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Cursor c = mDb.query(Tables.GROUPS + "," + Tables.RAW_CONTACTS, PROJECTION_GROUP_ID, 2353dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, 2354dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}, 2355dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana null /* groupBy */, null /* having */, null /* orderBy */); 2356dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 2357dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (c.moveToNext()) { 2358dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return c.getLong(0); 2359dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2360dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return null; 2361dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 2362dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana c.close(); 2363dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2364dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2365dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2366dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void updateFavoritesMembership(long rawContactId, boolean isStarred) { 2367dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID, 2368dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2369dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2370dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (isStarred) { 2371dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2372dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2373dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana deleteDataGroupMembership(rawContactId, groupId); 2374dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2375dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2376dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2377dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2378dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void insertDataGroupMembership(long rawContactId, long groupId) { 2379dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ContentValues groupMembershipValues = new ContentValues(); 2380dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.GROUP_ROW_ID, groupId); 2381dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 2382dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(DataColumns.MIMETYPE_ID, 2383dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 2384dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDb.insert(Tables.DATA, null, groupMembershipValues); 2385dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2386dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2387dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void deleteDataGroupMembership(long rawContactId, long groupId) { 2388dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final String[] selectionArgs = { 2389dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)), 2390dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(groupId), 2391dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(rawContactId)}; 2392dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDb.delete(Tables.DATA, SELECTION_GROUPMEMBERSHIP_DATA, selectionArgs); 2393dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2394dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2395a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2396a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 2397a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2398a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 2399a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2400a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 2401f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private long insertData(ContentValues values, boolean callerIsSyncAdapter) { 2402a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 2403de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.clear(); 2404de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.putAll(values); 240567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 2406de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID); 240720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 240824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // If the data being inserted belongs to the user's profile entry, check for the 240924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // WRITE_PROFILE permission before proceeding. 2410afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 241124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2412de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace package with internal mapping 2413de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String packageName = mValues.getAsString(Data.RES_PACKAGE); 2414de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (packageName != null) { 2415b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 2416de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 2417de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 2418508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 2419de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace mimetype with internal mapping 2420de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String mimeType = mValues.getAsString(Data.MIMETYPE); 2421de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (TextUtils.isEmpty(mimeType)) { 2422de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new IllegalArgumentException(Data.MIMETYPE + " is required"); 2423de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 24244097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 2425b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.getMimeTypeId(mimeType)); 2426de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 2427a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2428a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2429d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov id = rowHandler.insert(mDb, mTransactionContext, rawContactId, mValues); 2430f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2431d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 2432a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2433d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.rawContactUpdated(rawContactId); 2434a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 24354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 24364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 24373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_items table. The account is checked against the 24393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account in the raw contact for which the stream item is being inserted. If the 24403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * new stream item results in more stream items under this raw contact than the limit, 24413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest one will be deleted (note that if the stream item inserted was the 24423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * oldest, it will be immediately deleted, and this will return 0). 24433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 24443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 24453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 24463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return the stream item _ID of the newly created row, or 0 if it was not created 24473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 24483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItem(Uri uri, ContentValues values) { 24493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 24503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 24513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 24523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = mValues.getAsLong(StreamItems.RAW_CONTACT_ID); 24543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If the data being inserted belongs to the user's profile entry, check for the 24563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // WRITE_PROFILE permission before proceeding. 2457afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 24583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 24603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 24613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 24623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream items table. 24646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 24656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 24666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 24673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Insert the new stream item. 24686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro id = mDb.insert(Tables.STREAM_ITEMS, null, mValues); 24696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (id == -1) { 24706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insertion failed. 24716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 24726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check to see if we're over the limit for stream items under this raw contact. 24753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // It's possible that the inserted stream item is older than the the existing 24763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // ones, in which case it may be deleted immediately (resetting the ID to 0). 24773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = cleanUpOldStreamItems(rawContactId, id); 24783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 24803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_item_photos table. The account is checked against 24843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the account in the raw contact that owns the stream item being modified. 24853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 24863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 24873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 24886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return the stream item photo _ID of the newly created row, or 0 if there was an issue 24896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * with processing the photo or creating the row 24903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 24913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItemPhoto(Uri uri, ContentValues values) { 24923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 24933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 24943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 24953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = mValues.getAsLong(StreamItemPhotos.STREAM_ITEM_ID); 24973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemId != 0) { 24983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = lookupRawContactIdForStreamId(streamItemId); 24993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If the data being inserted belongs to the user's profile entry, check for the 25013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // WRITE_PROFILE permission before proceeding. 2502afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 25033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 25053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 25063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 25073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream item 25096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 25106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 25116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 25123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 25146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(mValues, false)) { 25156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insert the stream item photo. 25166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro id = mDb.insert(Tables.STREAM_ITEM_PHOTOS, null, mValues); 25176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 25203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Processes the photo contained in the {@link ContactsContract.StreamItemPhotos#PHOTO} 25246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * field of the given values, attempting to store it in the photo store. If successful, 25256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * the resulting photo file ID will be added to the values for insert/update in the table. 25266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * <p> 25276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * If updating, it is valid for the picture to be empty or unspecified (the function will 25286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * still return true). If inserting, a valid picture must be specified. 25296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param values The content values provided by the caller. 25306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param forUpdate Whether this photo is being processed for update (vs. insert). 25316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return Whether the insert or update should proceed. 25326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 25336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro private boolean processStreamItemPhoto(ContentValues values, boolean forUpdate) { 25346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!values.containsKey(StreamItemPhotos.PHOTO)) { 25356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 25366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro byte[] photoBytes = values.getAsByteArray(StreamItemPhotos.PHOTO); 25386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoBytes == null) { 25396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 25406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 25426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 25436802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 25446802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = mPhotoStore.insert(new PhotoProcessor(photoBytes, 25451dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim, true), true); 25466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileId != 0) { 25476802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.put(StreamItemPhotos.PHOTO_FILE_ID, photoFileId); 25486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(StreamItemPhotos.PHOTO); 25496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return true; 25506802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 25516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Couldn't store the photo, return 0. 25526802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert"); 25536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 25546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } catch (IOException ioe) { 25566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert", ioe); 25576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 25586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 25616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 25623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Looks up the raw contact ID that owns the specified stream item. 25633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param streamItemId The ID of the stream item. 25643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The associated raw contact ID, or -1 if no such stream item exists. 25653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long lookupRawContactIdForStreamId(long streamItemId) { 25673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = -1; 25683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = mDb.query(Tables.STREAM_ITEMS, new String[]{StreamItems.RAW_CONTACT_ID}, 25693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems._ID + "=?", new String[]{String.valueOf(streamItemId)}, 25703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c.moveToFirst()) { 25733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann rawContactId = c.getLong(0); 25743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 25763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 25773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return rawContactId; 25793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given raw contact ID is owned by the given account. 25833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account is null, this will return true iff the raw contact 25843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * is also associated with the "null" account. 25853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 25863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account does not match, this will throw a security exception. 25873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 25883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to check for. 25893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void enforceModifyingAccount(Account account, long rawContactId) { 25913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String accountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 25923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + "=? AND " 25933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + "=?"; 25943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String noAccountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 25953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " IS NULL AND " 25963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " IS NULL"; 25973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c; 25983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (account != null) { 25993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContactsColumns.CONCRETE_ID}, 26003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann accountSelection, 26013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(rawContactId), mAccount.name, mAccount.type}, 26023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 26033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 26043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContactsColumns.CONCRETE_ID}, 26053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann noAccountSelection, new String[]{String.valueOf(rawContactId)}, 26063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 26073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if(c.getCount() == 0) { 26103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new SecurityException("Caller account does not match raw contact ID " 26113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + rawContactId); 26123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream items matches up with the given 26203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 26213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 26223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 26233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 26243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 26253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item IDs that would be included in this selection. 26263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItems(Account account, String selection, 26283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 26293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = Lists.newArrayList(); 26303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 26313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 26323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = qb.query(mDb, 26333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{StreamItems._ID, StreamItems.RAW_CONTACT_ID}, 26343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 26353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 26373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemIds.add(c.getLong(0)); 26383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 26403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 26413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds; 26463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream item photos matches up with the given 26503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 26513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 26523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 26533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 26543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 26553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item photo IDs that would be included in this selection. 26563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItemPhotos(Account account, String selection, 26583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 26593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemPhotoIds = Lists.newArrayList(); 26603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 26613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 26623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = qb.query(mDb, new String[]{StreamItemPhotos._ID, StreamItems.RAW_CONTACT_ID}, 26633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 26643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 26663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemPhotoIds.add(c.getLong(0)); 26673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 26693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 26703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemPhotoIds; 26753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Queries the database for stream items under the given raw contact. If there are 26793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * more entries than {@link ContactsProvider2#MAX_STREAM_ITEMS_PER_RAW_CONTACT}, 26803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest entries (as determined by timestamp) will be deleted. 26813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to examine for stream items. 26823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param insertedStreamItemId The ID of the stream item that was just inserted, 26833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * prompting this cleanup. Callers may pass 0 if no insertion prompted the 26843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * cleanup. 26853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The ID of the inserted stream item if it still exists after cleanup; 26863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 0 otherwise. 26873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long cleanUpOldStreamItems(long rawContactId, long insertedStreamItemId) { 26893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long postCleanupInsertedStreamId = insertedStreamItemId; 26903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = mDb.query(Tables.STREAM_ITEMS, new String[]{StreamItems._ID}, 26913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 26923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, StreamItems.TIMESTAMP + " DESC, " + StreamItems._ID + " DESC"); 26933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int streamItemCount = c.getCount(); 26953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemCount <= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 26963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Still under the limit - nothing to clean up! 26973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return insertedStreamItemId; 26983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 26993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToLast(); 27003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.getPosition() >= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 27013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = c.getLong(0); 27023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (insertedStreamItemId == streamItemId) { 27033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // The stream item just inserted is being deleted. 27043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann postCleanupInsertedStreamId = 0; 27053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(c.getLong(0)); 27073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToPrevious(); 27083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 27113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 27123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return postCleanupInsertedStreamId; 27143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2716ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateRawContactDisplayName(SQLiteDatabase db, long rawContactId) { 27178ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(db, rawContactId); 2718d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov } 2719d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov 27209261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 272120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov * Delete data row by row so that fixing of primaries etc work correctly. 272220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov */ 2723f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) { 272420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 272520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2726de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 2727de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 2728f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, 2729f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov selection, selectionArgs, null); 2730de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov try { 2731de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov while(c.moveToNext()) { 2732f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 273324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 273424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for write profile permission if the data belongs to the profile. 2735afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 273624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2737f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 2738a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2739d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov count += rowHandler.delete(mDb, mTransactionContext, c); 2740f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2741d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 274288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov } 274320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 274420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 2745de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov c.close(); 274620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 274720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 274820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 274920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 275020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 275188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov /** 275288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov * Delete a data row provided that it is one of the allowed mime types. 275388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov */ 275420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov public int deleteData(long dataId, String[] allowedMimeTypes) { 2755f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 275688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 275788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 27584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 2759f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, Data._ID + "=?", 27604da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1, null); 2761f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 276220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 276320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!c.moveToFirst()) { 276420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 276520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 276620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2767f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 276820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean valid = false; 276920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov for (int i = 0; i < allowedMimeTypes.length; i++) { 277020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.equals(mimeType, allowedMimeTypes[i])) { 277120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov valid = true; 277220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 277320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 277420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 277520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 277620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!valid) { 27777a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana throw new IllegalArgumentException("Data type mismatch: expected " 277820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov + Lists.newArrayList(allowedMimeTypes)); 277920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 278020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 278124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for write profile permission if the data belongs to the profile. 278224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 2783afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 278424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2785a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2786d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov return rowHandler.delete(mDb, mTransactionContext, c); 278720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 278820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 278920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 279020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 279120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 279220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov /** 2793ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 2794ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 2795f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2796f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2797f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2798f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 27993593682b8d9213fde576a0cff54458ad50563980Dave Santoro final AccountWithDataSet accountWithDataSet = resolveAccountWithDataSet(uri, mValues); 2800ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2801ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 2802f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String packageName = mValues.getAsString(Groups.RES_PACKAGE); 280367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 2804f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 280567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 2806f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.remove(Groups.RES_PACKAGE); 2807ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2808dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final boolean isFavoritesGroup = mValues.getAsLong(Groups.FAVORITES) != null 2809dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ? mValues.getAsLong(Groups.FAVORITES) != 0 2810dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana : false; 2811dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2812f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2813f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(Groups.DIRTY, 1); 281473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 281573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 2816f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov long result = mDb.insert(Tables.GROUPS, Groups.TITLE, mValues); 2817ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2818dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && isFavoritesGroup) { 2819dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // add all starred raw contacts to this group 2820dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String selection; 2821dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs; 28223593682b8d9213fde576a0cff54458ad50563980Dave Santoro if (accountWithDataSet == null) { 2823dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + " IS NULL AND " 282443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.ACCOUNT_TYPE + " IS NULL AND " 282543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.DATA_SET + " IS NULL"; 2826dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = null; 28273593682b8d9213fde576a0cff54458ad50563980Dave Santoro } else if (accountWithDataSet.getDataSet() == null) { 2828dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + "=? AND " 28293593682b8d9213fde576a0cff54458ad50563980Dave Santoro + RawContacts.ACCOUNT_TYPE + "=? AND " 28303593682b8d9213fde576a0cff54458ad50563980Dave Santoro + RawContacts.DATA_SET + " IS NULL"; 28313593682b8d9213fde576a0cff54458ad50563980Dave Santoro selectionArgs = new String[] { 28323593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountName(), 28333593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountType() 28343593682b8d9213fde576a0cff54458ad50563980Dave Santoro }; 283543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } else { 283643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selection = RawContacts.ACCOUNT_NAME + "=? AND " 283743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.ACCOUNT_TYPE + "=? AND " 283843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.DATA_SET + "=?"; 28393593682b8d9213fde576a0cff54458ad50563980Dave Santoro selectionArgs = new String[] { 28403593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountName(), 28413593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountType(), 28423593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getDataSet() 28433593682b8d9213fde576a0cff54458ad50563980Dave Santoro }; 2844dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2845dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Cursor c = mDb.query(Tables.RAW_CONTACTS, 2846dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{RawContacts._ID, RawContacts.STARRED}, 2847dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, selectionArgs, null, null, null); 2848892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov try { 2849892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov while (c.moveToNext()) { 2850892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (c.getLong(1) != 0) { 2851892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov final long rawContactId = c.getLong(0); 2852892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov insertDataGroupMembership(rawContactId, result); 2853d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 2854892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } 2855dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2856892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } finally { 2857892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov c.close(); 2858dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2859dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2860dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2861f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mValues.containsKey(Groups.GROUP_VISIBLE)) { 28621a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2863ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey } 2864ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2865ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey return result; 2866ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2867ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 28685aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private long insertSettings(Uri uri, ContentValues values) { 2869e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final long id = mDb.insert(Tables.SETTINGS, null, values); 28705aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey 28711a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 28721a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2873e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 28741a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 2875e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return id; 2876e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 2877e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 2878ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 287982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov * Inserts a status update. 28801f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 288182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov public long insertStatusUpdate(ContentValues values) { 288282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov final String handle = values.getAsString(StatusUpdates.IM_HANDLE); 28830a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL); 28844dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov String customProtocol = null; 28854dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov 28860a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) { 288782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL); 28884dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov if (TextUtils.isEmpty(customProtocol)) { 28894dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov throw new IllegalArgumentException( 28904dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM"); 28914dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov } 28921f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 28931f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2894dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long rawContactId = -1; 2895dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long contactId = -1; 289682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov Long dataId = values.getAsLong(StatusUpdates.DATA_ID); 28976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountType = null; 28986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountName = null; 2899f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov mSb.setLength(0); 29002526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.clear(); 2901dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (dataId != null) { 2902dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the contact info for the given data row. 2903dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 29042526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(Tables.DATA + "." + Data._ID + "=?"); 29052526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(dataId)); 29061f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 2907dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the data row to attach this presence update to 2908dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 29090a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(handle) || protocol == null) { 29100a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required"); 29110a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 29120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 2913dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // TODO: generalize to allow other providers to match against email 2914dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol; 2915dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 29162a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov String mimeTypeIdIm = String.valueOf(mDbHelper.getMimeTypeIdForIm()); 2917dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (matchEmail) { 29182a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov String mimeTypeIdEmail = String.valueOf(mDbHelper.getMimeTypeIdForEmail()); 2919f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 2920f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise 2921f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the "OR" conjunction confuses it and it switches to a full scan of 2922f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the raw_contacts table. 2923f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 2924f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // This code relies on the fact that Im.DATA and Email.DATA are in fact the same 2925f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // column - Data.DATA1 29262526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + " IN (?,?)" + 29272526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Data.DATA1 + "=?" + 29282526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND ((" + DataColumns.MIMETYPE_ID + "=? AND " + Im.PROTOCOL + "=?"); 29292526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 29302526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 29312526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 29322526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 29332526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 2934dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 29352526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 29362526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 2937dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 29382526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=?))"); 29392526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 2940dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } else { 29412526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + "=?" + 29422526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.PROTOCOL + "=?" + 29432526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.DATA + "=?"); 29442526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 29452526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 29462526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 2947dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 29482526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 29492526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 2950dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 2951dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 29521f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 295382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.DATA_ID)) { 29542526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + DataColumns.CONCRETE_ID + "=?"); 29552526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(values.getAsString(StatusUpdates.DATA_ID)); 2956dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 295770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 295870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 29591f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 29601f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 2961de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 29622526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null, 29634394086494fe7909aaca70f56fb4bb08beebf303Dmitri Plotnikov Clauses.CONTACT_VISIBLE + " DESC, " + Data.RAW_CONTACT_ID); 29641f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 296567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataId = cursor.getLong(DataContactsQuery.DATA_ID); 29665ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID); 29676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountType = cursor.getString(DataContactsQuery.ACCOUNT_TYPE); 29686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountName = cursor.getString(DataContactsQuery.ACCOUNT_NAME); 2969e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 29701f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 29711f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 29721f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 29731f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 29741f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 297531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 297631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 297731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 29781f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 29791f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 298082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.PRESENCE)) { 2981a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (customProtocol == null) { 2982a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 2983a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // properly enforce uniqueness of null values 2984a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov customProtocol = ""; 2985a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 2986a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 2987a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.clear(); 298882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.DATA_ID, dataId); 2989a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId); 2990a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.CONTACT_ID, contactId); 299182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PROTOCOL, protocol); 299282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 299382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_HANDLE, handle); 299482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.IM_ACCOUNT)) { 299582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT)); 2996a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 299782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PRESENCE, 299882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov values.getAsString(StatusUpdates.PRESENCE)); 2999aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori mValues.put(StatusUpdates.CHAT_CAPABILITY, 3000aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori values.getAsString(StatusUpdates.CHAT_CAPABILITY)); 30011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3002a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // Insert the presence update 3003a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mDb.replace(Tables.PRESENCE, null, mValues); 3004a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3005e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 30060a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 300782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.STATUS)) { 300882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String status = values.getAsString(StatusUpdates.STATUS); 30090a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE); 30100a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov Integer labelResource = values.getAsInteger(StatusUpdates.STATUS_LABEL); 30110a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 30120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(resPackage) 30130a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov && (labelResource == null || labelResource == 0) 30140a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov && protocol != null) { 30150a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov labelResource = Im.getProtocolLabelResource(protocol); 30160a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 30170a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 30180a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov Long iconResource = values.getAsLong(StatusUpdates.STATUS_ICON); 30190a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov // TODO compute the default icon based on the protocol 30200a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 3021a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (TextUtils.isEmpty(status)) { 302278fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.deleteStatusUpdate(dataId); 3023a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } else { 30246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP); 30256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (timestamp != null) { 30266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mDbHelper.replaceStatusUpdate(dataId, timestamp, status, resPackage, 30276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro iconResource, labelResource); 30286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 30296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mDbHelper.insertStatusUpdate(dataId, status, resPackage, iconResource, 30306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro labelResource); 30316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For forward compatibility with the new stream item API, insert this status update 30346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // there as well. If we already have a stream item from this source, update that 30356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // one instead of inserting a new one (since the semantics of the old status update 30366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // API is to only have a single record). 30376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (rawContactId != -1 && !TextUtils.isEmpty(status)) { 30386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentValues streamItemValues = new ContentValues(); 30396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 30406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TEXT, status); 30416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.COMMENTS, ""); 30426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_PACKAGE, resPackage); 30436802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_ICON, iconResource); 30446802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_LABEL, labelResource); 30456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TIMESTAMP, 30466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro timestamp == null ? System.currentTimeMillis() : timestamp); 30476802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Note: The following is basically a workaround for the fact that status 30496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates didn't do any sort of account enforcement, while social stream item 30506802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates do. We can't expect callers of the old API to start passing account 30516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // information along, so we just populate the account params appropriately for 305243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // the raw contact. Data set is not relevant here, as we only check account 305343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // name and type. 30546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (accountName != null && accountType != null) { 30556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_NAME, accountName); 30566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_TYPE, accountType); 30576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Check for an existing stream item from this source, and insert or update. 30606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Uri streamUri = StreamItems.CONTENT_URI; 30616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = query(streamUri, new String[]{StreamItems._ID}, 30626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", 30636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{String.valueOf(rawContactId)}, null); 30646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 30656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (c.getCount() > 0) { 30666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.moveToFirst(); 30676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro update(ContentUris.withAppendedId(streamUri, c.getLong(0)), 30686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues, null, null); 30696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 30706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro insert(streamUri, streamItemValues); 30716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 30736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 30746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 3077e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3078e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3079bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov 3080a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (contactId != -1) { 3081f4015ab9ab7c26b766b5331fbf6655b8c54877eaDmitri Plotnikov mContactAggregator.updateLastStatusUpdateId(contactId); 3082a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3083a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3084a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov return dataId; 30851f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 30861f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 30874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3088de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 3089bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3090b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "deleteInTransaction: " + uri); 3091b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3092b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3093f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3094f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 3095508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 3096508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 309735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 3098b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().delete(mDb, selection, selectionArgs); 309935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3100b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: 3101b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3102b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3103b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3104b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().delete(mDb, selectionWithId, selectionArgs); 3105b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3106cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov case CONTACTS: { 3107cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov // TODO 3108cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return 0; 3109cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3110cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3111d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3112d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 3113dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 31146bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 31156bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 31169fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP: { 31172e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 31182e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 31192e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 3120fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 3121fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 31222e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 31232e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 31242e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final long contactId = lookupContactIdByLookupKey(mDb, lookupKey); 3125dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 31262e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 31272e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 31289fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP_ID: { 31299fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // lookup contact by id and lookup key to see if they still match the actual record 31309fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final List<String> pathSegments = uri.getPathSegments(); 31319fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final String lookupKey = pathSegments.get(2); 31329fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 31339fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann setTablesAndProjectionMapForContacts(lookupQb, uri, null); 3134a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 31359fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann String[] args; 31369fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (selectionArgs == null) { 31379fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[2]; 31389fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 31399fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[selectionArgs.length + 2]; 31409fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 31419fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31429fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args[0] = String.valueOf(contactId); 314360de6f6c3c70e53b603a47b0efc80993353a8368Daniel Lehmann args[1] = Uri.encode(lookupKey); 31449fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?"); 31459fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 31469fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann Cursor c = query(db, lookupQb, null, selection, args, null, null, null); 31479fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann try { 31489fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (c.getCount() == 1) { 31499fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // contact was unmodified so go ahead and delete it 3150dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 31519fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 31529fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // row was changed (e.g. the merging might have changed), we got multiple 31539fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // rows or the supplied selection filtered the record out 31549fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann return 0; 31559fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31569fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } finally { 31579fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann c.close(); 31589fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31599fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31609fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann 31612971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case RAW_CONTACTS: { 31622971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 3163fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov Cursor c = mDb.query(Tables.RAW_CONTACTS, 3164fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov new String[]{RawContacts._ID, RawContacts.CONTACT_ID}, 3165e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 31662971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 31672971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 31682971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = c.getLong(0); 3169fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov long contactId = c.getLong(1); 3170fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov numDeletes += deleteRawContact(rawContactId, contactId, 3171fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 31722971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31732971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 31742971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 31752971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31762971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 31772971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31782971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 31795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 31802971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = ContentUris.parseId(uri); 3181fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return deleteRawContact(rawContactId, mDbHelper.getContactId(rawContactId), 3182fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 3183508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3184508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 318520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3186f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 3187944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong return deleteData(appendAccountToSelection(uri, selection), selectionArgs, 3188f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana callerIsSyncAdapter); 318920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 319020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 319148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 319248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 319348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 319448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3195508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 3196f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 31974da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 31984da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter); 3199ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3200ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3201ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3202f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 32035aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter); 32042971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 32052971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 32062971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case GROUPS: { 32072971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 32082971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups._ID}, 3209e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 32102971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 32112971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 32125aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter); 32132971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 32142971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 32152971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 32162971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 321781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (numDeletes > 0) { 3218f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 321981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 32202971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 3221508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3222508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 3223eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 322443880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3225e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs); 3226eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3227eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 322882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 32290a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov return deleteStatusUpdates(selection, selectionArgs); 32301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 32311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 32323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 32333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 32343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), selection, selectionArgs); 32353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 32383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 32393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), 32403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemsColumns.CONCRETE_ID + "=?", 32413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 32423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 32453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 32463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), selection, selectionArgs); 32473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 32503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 32513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 32523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 32533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), 32543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " 32553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + StreamItemPhotos.STREAM_ITEM_ID + "=?", 32563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 32573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 325981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 326081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 32613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return mLegacyApiSupport.delete(uri, selection, selectionArgs); 326281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3263508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 32644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 32654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 32661c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) { 3267ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3268b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final long groupMembershipMimetypeId = mDbHelper 326994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 3270de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 327194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 327294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupId, null); 327394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 327494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana try { 3275f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 3276de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 327794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } else { 327894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.clear(); 327994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.put(Groups.DELETED, 1); 3280f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mValues.put(Groups.DIRTY, 1); 3281de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null); 328294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 328394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } finally { 32841a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 328594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 328694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 328794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 32885aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int deleteSettings(Uri uri, String selection, String[] selectionArgs) { 3289e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final int count = mDb.delete(Tables.SETTINGS, selection, selectionArgs); 32901a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3291e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3292e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3293e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3294dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int deleteContact(long contactId, boolean callerIsSyncAdapter) { 3295afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(mDb, contactId, true); 329696b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(contactId); 3297cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, 329896b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker RawContacts.CONTACT_ID + "=?", mSelectionArgs1, 329996b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker null, null, null); 3300cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov try { 3301cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov while (c.moveToNext()) { 3302cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov long rawContactId = c.getLong(0); 3303dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 3304cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3305cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } finally { 3306cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov c.close(); 3307cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3308cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 33093826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 33103826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3311cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return mDb.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 3312cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3313cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3314fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) { 3315afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 33163389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov mContactAggregator.invalidateAggregationExceptionCache(); 33173826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 33183826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3319f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 332014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null); 3321fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov int count = mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null); 3322fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov mContactAggregator.updateDisplayNameForContact(mDb, contactId); 3323fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return count; 332433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } else { 3325b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.removeContactIfSingleton(rawContactId); 3326dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 332733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 332833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 332933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 33300a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private int deleteStatusUpdates(String selection, String[] selectionArgs) { 33319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // delete from both tables: presence and status_updates 33329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 33339705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (VERBOSE_LOGGING) { 33349705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori Log.v(TAG, "deleting data from status_updates for " + selection); 33359705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 33369705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mDb.delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection), 33379705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 33389705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mDb.delete(Tables.PRESENCE, selection, selectionArgs); 33390a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 33400a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 33413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItems(Uri uri, ContentValues values, String selection, 33423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 33433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream items to be deleted, and check that they belong 33443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // to the account. 33453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 33463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = enforceModifyingAccountForStreamItems( 33473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann account, selection, selectionArgs); 33483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 33503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann for (long streamItemId : streamItemIds) { 33513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(streamItemId); 33523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mVisibleTouched = true; 33553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds.size(); 33563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItem(long streamItemId) { 33593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 33603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItemPhotos(streamItemId); 33613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEMS, StreamItems._ID + "=?", 33623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 33633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(Uri uri, ContentValues values, String selection, 33663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 33673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream item photos to be deleted, and check that they 33683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // belong to the account. 33693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 33703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 33713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 33733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEM_PHOTOS, selection, selectionArgs); 33743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(long streamItemId) { 33773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 33783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEM_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID + "=?", 33793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 33803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 3382dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int markRawContactAsDeleted(long rawContactId, boolean callerIsSyncAdapter) { 338381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 338481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 3385cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.clear(); 3386cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DELETED, 1); 3387cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 3388cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1); 3389cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 3390cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3391dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return updateRawContact(rawContactId, mValues, callerIsSyncAdapter); 3392cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3393cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 33944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3395de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int updateInTransaction(Uri uri, ContentValues values, String selection, 3396de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov String[] selectionArgs) { 3397bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3398b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "updateInTransaction: " + uri); 3399b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3400b5a4add17815167d20a90645779df34cdf45280dFred Quintana 340135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 340200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 340300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 3404b5a4add17815167d20a90645779df34cdf45280dFred Quintana if (match == SYNCSTATE_ID && selection == null) { 3405b5a4add17815167d20a90645779df34cdf45280dFred Quintana long rowId = ContentUris.parseId(uri); 34061129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Object data = values.get(ContactsContract.SyncState.DATA); 3407d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.syncStateUpdated(rowId, data); 3408b5a4add17815167d20a90645779df34cdf45280dFred Quintana return 1; 3409b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3410b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3411f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3412f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 341300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 341435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 3415b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().update(mDb, values, 3416b5a4add17815167d20a90645779df34cdf45280dFred Quintana appendAccountToSelection(uri, selection), selectionArgs); 3417b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3418b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: { 3419b5a4add17815167d20a90645779df34cdf45280dFred Quintana selection = appendAccountToSelection(uri, selection); 3420b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3421b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3422b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3423b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().update(mDb, values, 3424b5a4add17815167d20a90645779df34cdf45280dFred Quintana selectionWithId, selectionArgs); 3425b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 342635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3427d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 3428dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter); 342900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 343000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 343100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3432d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3433dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(ContentUris.parseId(uri), values, callerIsSyncAdapter); 3434c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 3435c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 3436c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 343724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 343824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Restrict update to the user's profile. 343924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro StringBuilder profileSelection = new StringBuilder(); 344024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileSelection.append(Contacts.IS_USER_PROFILE + "=1"); 344124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(selection)) { 344224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileSelection.append(" AND (").append(selection).append(")"); 344324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 344424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro count = updateContactOptions(values, profileSelection.toString(), selectionArgs, 344524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro callerIsSyncAdapter); 344624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 344724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 344824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 34492e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP: 34502e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP_ID: { 34512e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 34522e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 34532e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 3454fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 3455fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 34562e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 34572e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 34582e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final long contactId = lookupContactIdByLookupKey(mDb, lookupKey); 3459dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(contactId, values, callerIsSyncAdapter); 34602e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey break; 34612e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 34622e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 34637d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh case RAW_CONTACTS_DATA: { 34647d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh final String rawContactId = uri.getPathSegments().get(1); 34657d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ") 34667d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh + (selection == null ? "" : " AND " + selection); 34677d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 34687d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter); 34697d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 34707d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh break; 34717d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh } 34727d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 347320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3474944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong count = updateData(uri, values, appendAccountToSelection(uri, selection), 3475f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 347681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3477f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 347881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 347920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 348020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3481c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 348248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 348348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 348448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 348548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3486f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter); 348781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3488f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 348981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 349000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 349100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 34927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 34935ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 34945ac5c70d1165309302ebcc931f51723e37d31e0bJeff Sharkey selection = appendAccountToSelection(uri, selection); 3495dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, selection, selectionArgs, callerIsSyncAdapter); 34967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 34977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 34987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 34995ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 350033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 35014529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (selection != null) { 35024da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 35034da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov count = updateRawContacts(values, RawContacts._ID + "=?" 3504dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND(" + selection + ")", selectionArgs, 3505dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 35064529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } else { 35074da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 3508dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1, 3509dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 35104529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 35117e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 35127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 35137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 3514ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 35155aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, appendAccountToSelection(uri, selection), 3516f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 351781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3518f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 351981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3520ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3521ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3522ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3523ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3524ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 35254da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId)); 35264da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String selectionWithId = Groups._ID + "=? " 352773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov + (selection == null ? "" : " AND " + selection); 35285aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, selectionWithId, selectionArgs, 35295aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey callerIsSyncAdapter); 353081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3531f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 353281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3533ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3534ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3535ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3536127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 3537de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov count = updateAggregationException(mDb, values); 3538b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 3539b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3540b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 3541eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 3542e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey count = updateSettings(uri, values, appendAccountToSelection(uri, selection), 3543e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey selectionArgs); 354443880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3545eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 3546eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3547eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 35489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori case STATUS_UPDATES: { 35499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori count = updateStatusUpdate(uri, values, selection, selectionArgs); 35509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori break; 35519705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35529705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 35533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 35543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, selection, selectionArgs); 35553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 35593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, StreamItemsColumns.CONCRETE_ID + "=?", 35603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 35613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 35653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, selection, selectionArgs); 35663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 35703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 35713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 35723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{streamItemId}); 35733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 35773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 35783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 35793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 35803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " + 35813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?", 35823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 35833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 358672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov case DIRECTORIES: { 3587bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanPackagesByUid(Binder.getCallingUid()); 358872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov count = 1; 3589d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 3590d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 3591d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 359246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa case DATA_USAGE_FEEDBACK_ID: { 359346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (handleDataUsageFeedback(uri)) { 359446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 1; 359546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 359646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 0; 359746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 359846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa break; 359946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 360046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 360181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 360281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 3603f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 360481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 360500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 360600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 360700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 36084f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 36094f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 36109705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private int updateStatusUpdate(Uri uri, ContentValues values, String selection, 36119705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori String[] selectionArgs) { 36129705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // update status_updates table, if status is provided 36139705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 36149705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori int updateCount = 0; 36159705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values); 36169705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 36179705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori updateCount = mDb.update(Tables.STATUS_UPDATES, 36189705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues, 36199705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori getWhereClauseForStatusUpdatesTable(selection), 36209705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 36219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36229705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36239705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // now update the Presence table 36249705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues = getSettableColumnsForPresenceTable(values); 36259705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 36269705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori updateCount = mDb.update(Tables.PRESENCE, settableValues, 36279705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selection, selectionArgs); 36289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36299705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO updateCount is not entirely a valid count of updated rows because 2 tables could 36309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // potentially get updated in this method. 36319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return updateCount; 36329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36339705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItems(Uri uri, ContentValues values, String selection, 36353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 36363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream items can't be moved to a new raw contact. 36373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItems.RAW_CONTACT_ID); 36383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream items being updated belong to the account. 36403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 36413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItems(account, selection, selectionArgs); 36423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36436802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream items table. 36446802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 36456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 36466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 36473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If there's been no exception, the update should be fine. 36483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.update(Tables.STREAM_ITEMS, values, selection, selectionArgs); 36493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItemPhotos(Uri uri, ContentValues values, String selection, 36523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 36533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream item photos can't be moved to a new stream item. 36543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItemPhotos.STREAM_ITEM_ID); 36553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream item photos being updated belong to the account. 36573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 36583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 36593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream item 36616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 36626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 36636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 36646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 36656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo (since we're updating, it's valid for the photo to not be present). 36666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(values, true)) { 36676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // If there's been no exception, the update should be fine. 36686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return mDb.update(Tables.STREAM_ITEM_PHOTOS, values, selection, selectionArgs); 36696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 36706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 36713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori /** 36749705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori * Build a where clause to select the rows to be updated in status_updates table. 36759705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori */ 36769705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private String getWhereClauseForStatusUpdatesTable(String selection) { 36779705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.setLength(0); 36789705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE); 36799705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(selection); 36809705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(")"); 36819705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mSb.toString(); 36829705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36839705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36849705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) { 36859705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 36869705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values, 36879705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS); 36889705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values, 36899705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_TIMESTAMP); 36909705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values, 36919705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_RES_PACKAGE); 36929705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values, 36939705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_LABEL); 36949705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values, 36959705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_ICON); 36969705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 36979705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36989705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36999705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForPresenceTable(ContentValues values) { 37009705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 37019705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values, 37029705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.PRESENCE); 3703aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.CHAT_CAPABILITY, values, 3704aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori StatusUpdates.CHAT_CAPABILITY); 37059705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 37069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 37079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 37085aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int updateGroups(Uri uri, ContentValues values, String selectionWithId, 3709f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 371073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3711ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3712ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov 371373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov ContentValues updatedValues; 3714f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter && !values.containsKey(Groups.DIRTY)) { 371573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = mValues; 371673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.clear(); 371773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.putAll(values); 371873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.put(Groups.DIRTY, 1); 371973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } else { 372073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = values; 372173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 372273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3723ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey int count = mDb.update(Tables.GROUPS, updatedValues, selectionWithId, selectionArgs); 37241a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) { 37251a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 372694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 372743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 372843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO: This will not work for groups that have a data set specified, since the content 372943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // resolver will not be able to request a sync for the right source (unless it is updated 373043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // to key off account with data set). 37316ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi if (updatedValues.containsKey(Groups.SHOULD_SYNC) 37321129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) { 37336ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups.ACCOUNT_NAME, 3734e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey Groups.ACCOUNT_TYPE}, selectionWithId, selectionArgs, null, 37356ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi null, null); 37366ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountName; 37376ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountType; 37386ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi try { 37396ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi while (c.moveToNext()) { 37406ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountName = c.getString(0); 37416ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountType = c.getString(1); 374224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 37436ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Account account = new Account(accountName, accountType); 3744ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov ContentResolver.requestSync(account, ContactsContract.AUTHORITY, 37456ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi new Bundle()); 37466ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi break; 37476ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 37486ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 37496ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } finally { 37506ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi c.close(); 37516ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 37526ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 375394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana return count; 375494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 375594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 3756b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private int updateSettings(Uri uri, ContentValues values, String selection, 3757b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov String[] selectionArgs) { 3758e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final int count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs); 37591a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 37601a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3761e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3762e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3763e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3764e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3765dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs, 3766dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 37674529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (values.containsKey(RawContacts.CONTACT_ID)) { 37684529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " + 37694529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov "in content values. Contact IDs are assigned automatically"); 37704529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 377173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 377297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 377397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 377497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0"); 377597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 377697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 37774529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov int count = 0; 3778ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.RAW_CONTACTS, 377951bf5ea9531b9da72caff607dbdf35fd6f61cbe2Jeff Sharkey new String[] { RawContacts._ID }, selection, 37804529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov selectionArgs, null, null, null); 37814529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov try { 37824529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov while (cursor.moveToNext()) { 37834529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov long rawContactId = cursor.getLong(0); 3784dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateRawContact(rawContactId, values, callerIsSyncAdapter); 37854529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov count++; 37864529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37874529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } finally { 37884529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov cursor.close(); 37894529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37904529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 37914529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov return count; 37924529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37934529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 3794dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContact(long rawContactId, ContentValues values, 3795dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 379624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 379724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Enforce profile permissions if the raw contact is in the user's profile. 3798afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 379924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 380096b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker final String selection = RawContacts._ID + " = ?"; 380196b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(rawContactId); 380219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED) 380319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka && values.getAsInteger(RawContacts.DELETED) == 0); 380419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int previousDeleted = 0; 3805ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType = null; 3806ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName = null; 380743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = null; 380819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete) { 380919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka Cursor cursor = mDb.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, selection, 381096b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1, null, null, null); 381119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka try { 381219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (cursor.moveToFirst()) { 381319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka previousDeleted = cursor.getInt(RawContactsQuery.DELETED); 3814ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE); 3815ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME); 381643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro dataSet = cursor.getString(RawContactsQuery.DATA_SET); 381719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 381819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } finally { 381919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka cursor.close(); 382019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 382119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 382219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT); 382319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 3824f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 382596b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker int count = mDb.update(Tables.RAW_CONTACTS, values, selection, mSelectionArgs1); 38265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count != 0) { 3827f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (values.containsKey(RawContacts.AGGREGATION_MODE)) { 3828f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = values.getAsInteger(RawContacts.AGGREGATION_MODE); 3829f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov 3830f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // As per ContactsContract documentation, changing aggregation mode 3831f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // to DEFAULT should not trigger aggregation 3832f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) { 383369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, aggregationMode, false); 3834f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 3835f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 3836433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey if (values.containsKey(RawContacts.STARRED)) { 3837dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 3838dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 3839dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana values.getAsLong(RawContacts.STARRED) != 0); 3840dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 38414529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov mContactAggregator.updateStarred(rawContactId); 3842dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 3843dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then update the 3844dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // favorites group membership based on whether or not this contact is starred. 3845dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // If it is starred, add a group membership, if one doesn't already exist 3846dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // otherwise delete any matching group memberships. 3847dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 3848dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean starred = 0 != DatabaseUtils.longForQuery(mDb, 3849dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana SELECTION_STARRED_FROM_RAW_CONTACTS, 3850dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}); 3851dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred); 3852dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3853dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3854dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3855dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then add a 3856dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // group membership to the group marked as AutoAdd, if any. 3857dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 3858dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 3859433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey } 3860dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3861285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov if (values.containsKey(RawContacts.SOURCE_ID)) { 38622b7a632bba423357ae5641f94da6a2f71afc523bDmitri Plotnikov mContactAggregator.updateLookupKeyForRawContact(mDb, rawContactId); 3863285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 3864f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.containsKey(RawContacts.NAME_VERIFIED)) { 3865f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 3866f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // If setting NAME_VERIFIED for this raw contact, reset it for all 3867f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // other raw contacts in the same aggregate 3868f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) { 386978fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.resetNameVerifiedForOtherRawContacts(rawContactId); 3870f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 3871f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov mContactAggregator.updateDisplayNameForRawContact(mDb, rawContactId); 3872f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 387319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete && previousDeleted == 1) { 3874d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.rawContactInserted(rawContactId, 387543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new AccountWithDataSet(accountName, accountType, dataSet)); 387619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 38775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 38785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return count; 387933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 388033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 3881321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana private int updateData(Uri uri, ContentValues values, String selection, 3882f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 388320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 388420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 388520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data._ID); 38865ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov mValues.remove(Data.RAW_CONTACT_ID); 388720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 388820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 388920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String packageName = values.getAsString(Data.RES_PACKAGE); 389020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (packageName != null) { 389120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 3892b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 389320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 389420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 389597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 389697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 389797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov Data.IS_READ_ONLY + "=0"); 389897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 389997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 3900653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov int count = 0; 390120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3902653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 3903653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // so we don't need to worry about updating data we don't have permission to read. 3904f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // This query will be allowed to return profiles, and we'll do the permission check 3905f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // within the loop. 39066ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Cursor c = queryLocal(uri.buildUpon() 3907f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "1").build(), 3908f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro DataRowHandler.DataUpdateQuery.COLUMNS, 39096ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro selection, selectionArgs, null, -1 /* directory ID */, 39106ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro true /* suppress profile check */); 3911653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov try { 3912653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov while(c.moveToNext()) { 391324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check profile permission for the raw contact that owns each data record. 391424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = c.getLong(DataRowHandler.DataUpdateQuery.RAW_CONTACT_ID); 3915afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 391624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 3917f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count += updateData(mValues, c, callerIsSyncAdapter); 391820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3919653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov } finally { 3920653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov c.close(); 392120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 392220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3923653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return count; 392420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 392520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3926f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) { 3927653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov if (values.size() == 0) { 3928653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return 0; 3929321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 3930653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov 3931f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String mimeType = c.getString(DataRowHandler.DataUpdateQuery.MIMETYPE); 3932a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 3933f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean updated = 3934f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro rowHandler.update(mDb, mTransactionContext, values, c, callerIsSyncAdapter); 3935f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) { 3936f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 3937a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov } 3938f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return updated ? 1 : 0; 3939321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 3940321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana 39418c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov private int updateContactOptions(ContentValues values, String selection, 3942dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 39438c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov int count = 0; 3944ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.CONTACTS, 394524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[] { Contacts._ID, Contacts.IS_USER_PROFILE }, selection, 39468c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov selectionArgs, null, null, null); 39478c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov try { 39488c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov while (cursor.moveToNext()) { 39498c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov long contactId = cursor.getLong(0); 395024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 395124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for profile write permission before updating a user's profile contact. 395224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean isProfile = cursor.getInt(1) == 1; 395324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (isProfile) { 395424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(true); 395524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 395624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 3957dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateContactOptions(contactId, values, callerIsSyncAdapter); 39588c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov count++; 39598c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 39608c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } finally { 39618c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov cursor.close(); 39628c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 39638c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 39648c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov return count; 39658c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 39668c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 3967dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateContactOptions(long contactId, ContentValues values, 3968dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 3969d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 397024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check write permission if the contact is the user's profile. 3971afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(mDb, contactId, true); 397224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 39738c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 3974b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 3975d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 3976b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 3977d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 3978b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 3979d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 3980b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 3981d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 3982b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 3983d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.STARRED); 3984d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 3985d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 39868c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.size() == 0) { 3987d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 3988d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 3989d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 39908c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.containsKey(RawContacts.STARRED)) { 3991c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey // Mark dirty when changing starred to trigger sync 39928c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3993c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey } 3994c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey 39954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(contactId); 399697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov mDb.update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?" 399797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov + " AND " + RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0", mSelectionArgs1); 39988c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 3999dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (mValues.containsKey(RawContacts.STARRED) && !callerIsSyncAdapter) { 4000ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.RAW_CONTACTS, 4001dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=?", 4002dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mSelectionArgs1, null, null, null); 4003dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 4004dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (cursor.moveToNext()) { 4005dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana long rawContactId = cursor.getLong(0); 4006dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 4007dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mValues.getAsLong(RawContacts.STARRED) != 0); 4008dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4009dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 4010dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana cursor.close(); 4011dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4012dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4013dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 40148c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // Copy changeable values to prevent automatically managed fields from 40158c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // being explicitly updated by clients. 40168c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 4017b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 40188c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 4019b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 40208c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 4021b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 40228c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 4023b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 40248c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 4025b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 40268c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.STARRED); 40278c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 40289b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori int rslt = mDb.update(Tables.CONTACTS, mValues, Contacts._ID + "=?", mSelectionArgs1); 40296e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori 40309b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori if (values.containsKey(Contacts.LAST_TIME_CONTACTED) && 40319b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori !values.containsKey(Contacts.TIMES_CONTACTED)) { 40329b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 40339b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 40349b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori } 40359b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori return rslt; 4036f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 4037d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 4038127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 4039127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 40400c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1); 40410c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2); 404280c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 4043ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId1; 4044ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId2; 40450c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (rcId1 < rcId2) { 40460c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId1; 40470c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId2; 40480c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 40490c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId1; 40500c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId2; 4051b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4052127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 40530c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 40544da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[0] = String.valueOf(rawContactId1); 40554da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[1] = String.valueOf(rawContactId2); 40560c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, 40574da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov AggregationExceptions.RAW_CONTACT_ID1 + "=? AND " 40584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2); 40590c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 40606bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 40616bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 40620c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 40630c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 40640c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 40650c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues); 4066127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 4067127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 40683389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov mContactAggregator.invalidateAggregationExceptionCache(); 406969cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId1, 407069cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 407169cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId2, 407269cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 4073dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov 4074bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateContact(mTransactionContext, db, rawContactId1); 4075bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateContact(mTransactionContext, db, rawContactId2); 4076127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 4077127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 4078127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 4079127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 4080b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4081b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 408270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong public void onAccountsUpdated(Account[] accounts) { 4083bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 40843826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 40853826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4086bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected boolean updateAccountsInBackground(Account[] accounts) { 4087f8536aaa7a52b9a7a353bc54e158becdbe79ec87Bai Tao // TODO : Check the unit test. 4088e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov boolean accountsChanged = false; 408949d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov mDb = mDbHelper.getWritableDatabase(); 409070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.beginTransaction(); 409170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong try { 409243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> existingAccountsWithDataSets = 409343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro findValidAccountsWithDataSets(Tables.ACCOUNTS); 4094743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov 409543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add a row to the ACCOUNTS table (with no data set) for each new account. 4096743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov for (Account account : accounts) { 409743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = new AccountWithDataSet( 409843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro account.name, account.type, null); 409943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!existingAccountsWithDataSets.contains(accountWithDataSet)) { 4100e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 410143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 410243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add an account entry with an empty data set to match the account. 4103743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov mDb.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 410443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ", " + RawContacts.ACCOUNT_TYPE + ", " + RawContacts.DATA_SET 410543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ") VALUES (?, ?, ?)", 410643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new String[] { 410743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 410843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 410943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 411043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }); 4111743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 4112743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 411348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 411443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Check each of the existing sub-accounts against the account list. If the owning 411543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // account no longer exists, the sub-account and all its data should be deleted. 411643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro List<AccountWithDataSet> accountsWithDataSetsToDelete = 411743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new ArrayList<AccountWithDataSet>(); 411843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro List<Account> accountList = Arrays.asList(accounts); 411943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : existingAccountsWithDataSets) { 412043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Account owningAccount = new Account( 412143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), accountWithDataSet.getAccountType()); 412243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!accountList.contains(owningAccount)) { 412343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsWithDataSetsToDelete.add(accountWithDataSet); 412443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 412570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 412670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong 412743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!accountsWithDataSetsToDelete.isEmpty()) { 4128e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 412943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : accountsWithDataSetsToDelete) { 413043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Log.d(TAG, "removing data for removed account " + accountWithDataSet); 413143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String[] accountParams = new String[] { 413243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 413343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType() 413443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }; 413543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String[] accountWithDataSetParams = accountWithDataSet.getDataSet() == null 413643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ? accountParams 413743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro : new String[] { 413843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 413943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 414043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 414143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }; 414243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String groupsDataSetClause = " AND " + Groups.DATA_SET 414343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + (accountWithDataSet.getDataSet() == null ? " IS NULL" : " = ?"); 414443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String rawContactsDataSetClause = " AND " + RawContacts.DATA_SET 414543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + (accountWithDataSet.getDataSet() == null ? " IS NULL" : " = ?"); 414643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 4147e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4148e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.GROUPS + 4149e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Groups.ACCOUNT_NAME + " = ?" + 415043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Groups.ACCOUNT_TYPE + " = ?" + 415143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro groupsDataSetClause, accountWithDataSetParams); 4152e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4153e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.PRESENCE + 4154e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" + 4155e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "SELECT " + RawContacts._ID + 4156e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 4157e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 415843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + " = ?" + 415943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause + ")", accountWithDataSetParams); 4160e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4161e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.RAW_CONTACTS + 4162e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 416343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + " = ?" + 416443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause, accountWithDataSetParams); 4165e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4166e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.SETTINGS + 4167e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Settings.ACCOUNT_NAME + " = ?" + 416843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Settings.ACCOUNT_TYPE + " = ?", accountParams); 4169e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4170e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.ACCOUNTS + 4171e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + "=?" + 417243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + "=?" + 417343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause, accountWithDataSetParams); 4174d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov mDb.execSQL( 4175d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov "DELETE FROM " + Tables.DIRECTORIES + 4176d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov " WHERE " + Directory.ACCOUNT_NAME + "=?" + 417743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Directory.ACCOUNT_TYPE + "=?", accountParams); 41784458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov resetDirectoryCache(); 4179e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 4180e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov 418133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // Find all aggregated contacts that used to contain the raw contacts 418233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // we have just deleted and see if they are still referencing the deleted 4183e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov // names or photos. If so, fix up those contacts. 418433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov HashSet<Long> orphanContactIds = Sets.newHashSet(); 418533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Cursor cursor = mDb.rawQuery("SELECT " + Contacts._ID + 418633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " FROM " + Tables.CONTACTS + 418733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " WHERE (" + Contacts.NAME_RAW_CONTACT_ID + " NOT NULL AND " + 418869cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov Contacts.NAME_RAW_CONTACT_ID + " NOT IN " + 418969cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + RawContacts._ID + 419069cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + "))" + 419133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " OR (" + Contacts.PHOTO_ID + " NOT NULL AND " + 419233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Contacts.PHOTO_ID + " NOT IN " + 419369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + Data._ID + 419469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.DATA + "))", null); 419533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov try { 419633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov while (cursor.moveToNext()) { 419733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov orphanContactIds.add(cursor.getLong(0)); 419833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 419933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } finally { 420033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov cursor.close(); 420133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 420233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 420333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov for (Long contactId : orphanContactIds) { 4204bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.updateAggregateData(mTransactionContext, contactId); 420533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 4206e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDbHelper.updateAllVisible(); 4207bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 420833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 420933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 421043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Now that we've done the account-based additions and subtractions from the Accounts 421143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // table, check for raw contacts that have been added with a data set and add Accounts 421243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // entries for those if necessary. 421343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro existingAccountsWithDataSets = findValidAccountsWithDataSets(Tables.ACCOUNTS); 421443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> rawContactAccountsWithDataSets = 421543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro findValidAccountsWithDataSets(Tables.RAW_CONTACTS); 421643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactAccountsWithDataSets.removeAll(existingAccountsWithDataSets); 421743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 421843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Any remaining raw contact sub-accounts need to be added to the Accounts table. 421943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : rawContactAccountsWithDataSets) { 422043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsChanged = true; 422143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 422243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add an account entry to match the raw contact. 422343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mDb.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 422443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ", " + RawContacts.ACCOUNT_TYPE + ", " + RawContacts.DATA_SET 422543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ") VALUES (?, ?, ?)", 422643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new String[] { 422743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 422843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 422943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 423043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }); 423143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 423243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 4233e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov if (accountsChanged) { 423443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO: Should sync state take data set into consideration? 4235e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDbHelper.getSyncState().onAccountsChanged(mDb, accounts); 4236e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 423770d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.setTransactionSuccessful(); 423870d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } finally { 423970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.endTransaction(); 424070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 424173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.clear(); 42423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 42433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (accountsChanged) { 42443826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateContactsAccountCount(accounts); 42453826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 42463826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42473826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4248afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov return accountsChanged; 424970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 4250619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 42513826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateContactsAccountCount(Account[] accounts) { 42523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov int count = 0; 42533826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov for (Account account : accounts) { 42543826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (isContactsAccount(account)) { 42553826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov count++; 42563826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42573826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42583826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mContactsAccountCount = count; 42593826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42603826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 42613826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov protected boolean isContactsAccount(Account account) { 42623826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov final IContentService cs = ContentResolver.getContentService(); 42633826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov try { 42643826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0; 42653826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } catch (RemoteException e) { 42663826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov Log.e(TAG, "Cannot obtain sync flag for account: " + account, e); 42673826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return false; 42683826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42693826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42703826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 427172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void onPackageChanged(String packageName) { 4272bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_DIRECTORIES, packageName); 4273d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4274d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4275619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 427643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Finds all distinct account types and data sets present in the specified table. 4277627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov */ 427843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private Set<AccountWithDataSet> findValidAccountsWithDataSets(String table) { 427943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> accountsWithDataSets = new HashSet<AccountWithDataSet>(); 4280743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov Cursor c = mDb.rawQuery( 428143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro "SELECT DISTINCT " + RawContacts.ACCOUNT_NAME + "," + RawContacts.ACCOUNT_TYPE + 428243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro "," + RawContacts.DATA_SET + 428343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " FROM " + table, null); 4284627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 4285627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov while (c.moveToNext()) { 4286dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!c.isNull(0) || !c.isNull(1)) { 428743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsWithDataSets.add( 428843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new AccountWithDataSet(c.getString(0), c.getString(1), c.getString(2))); 4289627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4290627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4291627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } finally { 4292627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov c.close(); 4293627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 429443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro return accountsWithDataSets; 4295627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4296627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov 42974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 42984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 42994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 430015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 430115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mReadAccessLatch); 430215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 4303d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY); 4304385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directory == null) { 43053716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 43066ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1, false)); 4307385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directory.equals("0")) { 43083716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 43093716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 43106ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Directory.DEFAULT, false)); 4311d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } else if (directory.equals("1")) { 43123716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 43133716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 43146ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Directory.LOCAL_INVISIBLE, false)); 4315d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4316d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4317d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov DirectoryInfo directoryInfo = getDirectoryAuthority(directory); 4318d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo == null) { 4319a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov Log.e(TAG, "Invalid directory ID: " + uri); 4320a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov return null; 4321d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4322d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4323d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Builder builder = new Uri.Builder(); 4324d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.scheme(ContentResolver.SCHEME_CONTENT); 4325d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.authority(directoryInfo.authority); 4326d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.encodedPath(uri.getEncodedPath()); 4327d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountName != null) { 4328d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName); 4329d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4330d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountType != null) { 4331d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType); 4332d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 43332e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 43342e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limit = getLimit(uri); 43352e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov if (limit != null) { 43362e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit); 43372e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov } 43382e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 4339d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Uri directoryUri = builder.build(); 434009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 434109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov if (projection == null) { 434209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov projection = getDefaultProjection(uri); 434309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 434409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 4345332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov Cursor cursor = getContext().getContentResolver().query(directoryUri, projection, selection, 4346d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov selectionArgs, sortOrder); 43476ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 43486ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (cursor == null) { 43496ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 43506ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 43516ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 4352547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro CrossProcessCursor crossProcessCursor = getCrossProcessCursor(cursor); 4353547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (crossProcessCursor != null) { 4354547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return wrapCursor(uri, cursor); 4355547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } else { 4356547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return matrixCursorFromCursor(wrapCursor(uri, cursor)); 4357547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 43583716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 43593716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4360547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro private Cursor wrapCursor(Uri uri, Cursor cursor) { 4361547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 4362547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro // If the cursor doesn't contain a snippet column, don't bother wrapping it. 4363547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (cursor.getColumnIndex(SearchSnippetColumns.SNIPPET) < 0) { 43645517770250b3afa4fd88b6869c3244680821d222Dave Santoro if (VERBOSE_LOGGING) { 43655517770250b3afa4fd88b6869c3244680821d222Dave Santoro return new InstrumentedCursorWrapper(cursor, uri, TAG); 43665517770250b3afa4fd88b6869c3244680821d222Dave Santoro } else { 43675517770250b3afa4fd88b6869c3244680821d222Dave Santoro return cursor; 43685517770250b3afa4fd88b6869c3244680821d222Dave Santoro } 4369547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 4370547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 43713716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Parse out snippet arguments for use when snippets are retrieved from the cursor. 43723716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String[] args = null; 43733716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String snippetArgs = 43743716f1447ceb21180d1301790eabd8b9453f486dDave Santoro getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 43753716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (snippetArgs != null) { 43763716f1447ceb21180d1301790eabd8b9453f486dDave Santoro args = snippetArgs.split(","); 43773716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 43783716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 43793716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String query = uri.getLastPathSegment(); 43803716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String startMatch = args != null && args.length > 0 ? args[0] 43813716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_START_MATCH; 43823716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String endMatch = args != null && args.length > 1 ? args[1] 43833716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_END_MATCH; 43843716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String ellipsis = args != null && args.length > 2 ? args[2] 43853716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_ELLIPSIS; 43863716f1447ceb21180d1301790eabd8b9453f486dDave Santoro int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 43873716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 43883716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 43895517770250b3afa4fd88b6869c3244680821d222Dave Santoro if (VERBOSE_LOGGING) { 43905517770250b3afa4fd88b6869c3244680821d222Dave Santoro return new InstrumentedCursorWrapper(new SnippetizingCursorWrapper( 43915517770250b3afa4fd88b6869c3244680821d222Dave Santoro cursor, query, startMatch, endMatch, ellipsis, maxTokens), uri, TAG); 43925517770250b3afa4fd88b6869c3244680821d222Dave Santoro } else { 43935517770250b3afa4fd88b6869c3244680821d222Dave Santoro return new SnippetizingCursorWrapper(cursor, query, startMatch, endMatch, ellipsis, 43945517770250b3afa4fd88b6869c3244680821d222Dave Santoro maxTokens); 43955517770250b3afa4fd88b6869c3244680821d222Dave Santoro } 43966ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 43976ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 43986ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov private CrossProcessCursor getCrossProcessCursor(Cursor cursor) { 43996ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov Cursor c = cursor; 44006ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (c instanceof CrossProcessCursor) { 44016ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return (CrossProcessCursor) c; 44026ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else if (c instanceof CursorWindow) { 44036ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return getCrossProcessCursor(((CursorWrapper) c).getWrappedCursor()); 44046ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else { 44056ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 44066ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 44076ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 44086ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 44096ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov public MatrixCursor matrixCursorFromCursor(Cursor cursor) { 44106ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); 44116ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov int numColumns = cursor.getColumnCount(); 44126ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov String data[] = new String[numColumns]; 44136ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov cursor.moveToPosition(-1); 44146ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov while (cursor.moveToNext()) { 44156ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov for (int i = 0; i < numColumns; i++) { 44166ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov data[i] = cursor.getString(i); 44176ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 44186ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov newCursor.addRow(data); 4419332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov } 44206ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return newCursor; 4421d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4422d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4423d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final class DirectoryQuery { 4424d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final String[] COLUMNS = new String[] { 4425d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory._ID, 4426d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.DIRECTORY_AUTHORITY, 4427d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_NAME, 4428d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_TYPE 4429d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov }; 4430d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4431d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int DIRECTORY_ID = 0; 4432d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int AUTHORITY = 1; 4433d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_NAME = 2; 4434d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_TYPE = 3; 4435d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4436d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4437d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 4438d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Reads and caches directory information for the database. 4439d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 4440d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private DirectoryInfo getDirectoryAuthority(String directoryId) { 44414458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized (mDirectoryCache) { 44424458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov if (!mDirectoryCacheValid) { 44434458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.clear(); 444449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov SQLiteDatabase db = mDbHelper.getReadableDatabase(); 444549d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Cursor cursor = db.query(Tables.DIRECTORIES, 44464458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryQuery.COLUMNS, 44474458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov null, null, null, null, null); 44484458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov try { 44494458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov while (cursor.moveToNext()) { 44504458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryInfo info = new DirectoryInfo(); 44514458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov String id = cursor.getString(DirectoryQuery.DIRECTORY_ID); 44524458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.authority = cursor.getString(DirectoryQuery.AUTHORITY); 44534458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME); 44544458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE); 44554458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.put(id, info); 44564458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 44574458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } finally { 44584458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov cursor.close(); 4459d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 44604458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = true; 4461d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4462d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 44634458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov return mDirectoryCache.get(directoryId); 44644458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 4465d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4466d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 446772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void resetDirectoryCache() { 44684458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized(mDirectoryCache) { 44694458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = false; 44704458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 447172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 447272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 44736ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private Cursor queryLocal(Uri uri, String[] projection, String selection, 44746ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro String[] selectionArgs, String sortOrder, long directoryId, 44754b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki final boolean suppressProfileCheck) { 4476bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 4477bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov Log.v(TAG, "query: " + uri); 4478bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov } 44790b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov 4480b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 448135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4482d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 44831f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 4484c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov String limit = getLimit(uri); 4485c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 44864b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki // Column name for appendProfileRestriction(). We append the profile check to the original 44874b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki // selection if it's not null. 44884b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki String profileRestrictionColumnName = null; 44894b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki 4490a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 44914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 449235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 4493b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().query(db, projection, selection, selectionArgs, 449435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana sortOrder); 449535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4496d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 4497763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 44984b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki appendLocalDirectorySelectionIfNeeded(qb, directoryId); 44994b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki profileRestrictionColumnName = Contacts.IS_USER_PROFILE; 45006ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro sortOrder = prependProfileSortIfNeeded(uri, sortOrder, suppressProfileCheck); 4501619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 4502619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 4503619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 4504d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 45054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 4506afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 4507763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 45084da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 45094da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 45106bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 45116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 45126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 45135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP: 45145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP_ID: { 45155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 45165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = pathSegments.size(); 45175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount < 3) { 4518fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 4519fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 45205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 4521a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 45225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String lookupKey = pathSegments.get(2); 45235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount == 4) { 45245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4525afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4527763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 4528a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4529a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4530a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4531a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 4532a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 45335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return c; 45345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 45355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 45365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 4537763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 45384da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 45394da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 45404da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 45415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 45425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 45435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 45442149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_DATA: 45452149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_ID_DATA: { 45462149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 45472149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov int segmentCount = pathSegments.size(); 45482149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount < 4) { 45492149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 45502149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov "Missing a lookup key", uri)); 45512149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 45522149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov String lookupKey = pathSegments.get(2); 45532149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount == 5) { 45542149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4555afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45562149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 45572149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(lookupQb, uri, projection, false); 4558a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 4559a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4560a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4561a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Data.CONTACT_ID, contactId, Data.LOOKUP_KEY, lookupKey); 4562a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 45632149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov return c; 45642149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 45652149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 45662149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov // TODO see if the contact exists but has no data rows (rare) 45672149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 45682149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 45692149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 457024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 4571afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45722149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 457324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 45742149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov qb.appendWhere(" AND " + Data.CONTACT_ID + "=?"); 45752149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov break; 45762149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 45772149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 45783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_ID_STREAM_ITEMS: { 45793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4580afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 45823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 45833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContactsColumns.CONCRETE_CONTACT_ID + "=?"); 45843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 45853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 45863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 45873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_STREAM_ITEMS: 45883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_ID_STREAM_ITEMS: { 45893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<String> pathSegments = uri.getPathSegments(); 45903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int segmentCount = pathSegments.size(); 45913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount < 4) { 45923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new IllegalArgumentException(mDbHelper.exceptionMessage( 45933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann "Missing a lookup key", uri)); 45943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 45953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String lookupKey = pathSegments.get(2); 45963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount == 5) { 45973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(pathSegments.get(3)); 4598afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 46003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(lookupQb); 46013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 46023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann projection, selection, selectionArgs, sortOrder, groupBy, limit, 46033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RawContacts.CONTACT_ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 46043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c != null) { 46053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return c; 46063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 46073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 46083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 46093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 46103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = lookupContactIdByLookupKey(db, lookupKey); 4611afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 46123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 46133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContacts.CONTACT_ID + "=?"); 46143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 46153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 46163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4617f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: { 461842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKey = Uri.encode(uri.getPathSegments().get(2)); 461924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 4620afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 4621ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 4622f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey qb.setProjectionMap(sContactsVCardProjectionMap); 46234da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 462424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 46254da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 4626f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey break; 4627f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey } 4628f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey 462942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 463042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); 463142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann String currentDateString = dateFormat.format(new Date()).toString(); 463242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann return db.rawQuery( 463342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann "SELECT" + 463442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " 'vcards_' || ? || '.vcf' AS " + OpenableColumns.DISPLAY_NAME + "," + 463542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " NULL AS " + OpenableColumns.SIZE, 463642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann new String[] { currentDateString }); 463742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 463842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 4639ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_FILTER: { 4640916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov String filterParam = ""; 4641ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 4642916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov filterParam = uri.getLastPathSegment(); 4643ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 46447ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov setTablesAndProjectionMapForContactsWithSnippet( 46457ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov qb, uri, projection, filterParam, directoryId); 46464b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki profileRestrictionColumnName = Contacts.IS_USER_PROFILE; 46476ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro sortOrder = prependProfileSortIfNeeded(uri, sortOrder, suppressProfileCheck); 4648ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4649ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4650ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 4651ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT_FILTER: 4652ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT: { 46532f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Basically the resultant SQL should look like this: 46542f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing starred items) 46552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 46562f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing frequently contacted items) 46572f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // ORDER BY ... 46582f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 46592f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final boolean phoneOnly = readBooleanQueryParameter( 46602f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa uri, ContactsContract.STREQUENT_PHONE_ONLY, false); 46612f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (match == CONTACTS_STREQUENT_FILTER && uri.getPathSegments().size() > 3) { 46624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 46634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4664e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(Contacts._ID + " IN "); 46655e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov appendContactFilterAsNestedQuery(sb, filterParam); 46662f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection = DbQueryUtils.concatenateClauses(selection, sb.toString()); 46674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 46684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 46692f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] subProjection = null; 46705e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection != null) { 46712f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa subProjection = appendProjectionArg(projection, TIMES_USED_SORT_COLUMN); 46725e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 46735e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 46744a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov // Build the first query for starred 46754928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 46764928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(phoneOnly ? 46774928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa sStrequentPhoneOnlyStarredProjectionMap 46784928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa : sStrequentStarredProjectionMap); 46792f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 46802f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection, Contacts.IS_USER_PROFILE + "=0")); 46819dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa if (phoneOnly) { 46829dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa qb.appendWhere(" AND " + Contacts.HAS_PHONE_NUMBER + "=1"); 46839dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa } 46842f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 46852f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String starredQuery = qb.buildQuery(subProjection, 468624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Contacts.STARRED + "=1", Contacts._ID, null, null, null); 4687d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 46882f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Reset the builder. 4689d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 46902f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 46914928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 46924928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // Build the second query for frequent part. 46934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final String frequentQuery; 46944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (phoneOnly) { 46954928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final StringBuilder tableBuilder = new StringBuilder(); 46964928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // In phone only mode, we need to look at view_data instead of 46974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // contacts/raw_contacts to obtain actual phone numbers. One problem is that 46984928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data is much larger than view_contacts, so our query might become much 46994928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // slower. 47004928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // 47014928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // To avoid the possible slow down, we start from data usage table and join 47024928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data to the table, assuming data usage table is quite smaller than 47034928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // data rows (almost always it should be), and we don't want any phone 47044928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // numbers not used by the user. This way sqlite is able to drop a number of 47054928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // rows in view_data in the early stage of data lookup. 47064928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa tableBuilder.append(Tables.DATA_USAGE_STAT 47074928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " INNER JOIN " + Views.DATA + " " + Tables.DATA 47084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" 47094928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataColumns.CONCRETE_ID + " AND " 47104928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" 47114928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT_CALL + ")"); 47124928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactPresenceJoin(tableBuilder, projection, RawContacts.CONTACT_ID); 47134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactStatusUpdateJoin(tableBuilder, projection, 47144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa ContactsColumns.LAST_STATUS_UPDATE_ID); 47154928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 47164928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setTables(tableBuilder.toString()); 47174928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentPhoneOnlyFrequentProjectionMap); 47184928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 47194928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 47204928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.STARRED + "=0 OR " + Contacts.STARRED + " IS NULL", 47214928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa MimetypesColumns.MIMETYPE + " IN (" 47224928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + Phone.CONTENT_ITEM_TYPE + "', " 47234928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + SipAddress.CONTENT_ITEM_TYPE + "')")); 47244928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, null, null, null, null, null); 47254928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } else { 47264928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 47274928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 47284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 47294928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 47304928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa "(" + Contacts.STARRED + " =0 OR " + Contacts.STARRED + " IS NULL)", 47314928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.IS_USER_PROFILE + "=0")); 47324928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, 47334928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa null, Contacts._ID, null, null, null); 47344928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } 4735d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 4736d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 47372f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String unionQuery = 47382f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, 47392f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa STREQUENT_ORDER_BY, STREQUENT_LIMIT); 47402f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 47412f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Here, we need to use selection / selectionArgs (supplied from users) "twice", 47422f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // as we want them both for starred items and for frequently contacted items. 47432f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // 47442f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // e.g. if the user specify selection = "starred =?" and selectionArgs = "0", 47452f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // the resultant SQL should be like: 47462f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 47472f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 47482f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 47492f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] doubledSelectionArgs = null; 47502f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (selectionArgs != null) { 47512f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final int length = selectionArgs.length; 47522f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa doubledSelectionArgs = new String[length * 2]; 47537d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, 0, length); 47547d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, length, length); 47552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 47562f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 47572f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa Cursor cursor = db.rawQuery(unionQuery, doubledSelectionArgs); 47582f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (cursor != null) { 47592f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa cursor.setNotificationUri(getContext().getContentResolver(), 4760d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 4761d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 47622f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa return cursor; 4763d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 4764d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 476545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa case CONTACTS_FREQUENT: { 476645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 476745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 4768363bdaba2994539e1a3a2342a9fcf223604d69eaDaisuke Miyakawa qb.appendWhere(Contacts.IS_USER_PROFILE + "=0"); 476945ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa groupBy = Contacts._ID; 477045ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa if (!TextUtils.isEmpty(sortOrder)) { 477145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY + ", " + sortOrder; 477245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } else { 477345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY; 477445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 477545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa break; 477645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 477745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 4778ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_GROUP: { 4779763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 4780b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 478171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 47824a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 4783b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4784b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 4785b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4786b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 478724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 478824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 478924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 479024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(Contacts.IS_USER_PROFILE + "=1"); 479124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 479224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 479324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 479424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: { 479524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 479624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForEntities(qb, uri, projection); 479724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + Contacts.IS_USER_PROFILE + "=1"); 479824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 479924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 480024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 480124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: { 480224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 480324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 480424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 480524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 480624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 480724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 480824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA_ID: { 480924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 481024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 481124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 481224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + Data._ID + "=? AND " 481324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 481424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 481524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 481624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 481724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: { 481824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 4819ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 482024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.setProjectionMap(sContactsVCardProjectionMap); 482124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(Contacts.IS_USER_PROFILE + "=1"); 482224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 482324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 482424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 4825a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_DATA: { 48264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 482782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 48284da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 48294da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 48306bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 48316bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 483200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 4833a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 48343653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4835afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 483682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 48374da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 48384da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 48393653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 48403653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov break; 48413653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov } 48423653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 4843a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_ENTITIES: { 4844a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4845a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 4846a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 4847a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 4848a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 4849a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4850a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4851a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ENTITIES: 4852a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ID_ENTITIES: { 4853a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 4854a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov int segmentCount = pathSegments.size(); 4855a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount < 4) { 4856a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 4857a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov "Missing a lookup key", uri)); 4858a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4859a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lookupKey = pathSegments.get(2); 4860a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount == 5) { 4861a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4862a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4863a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(lookupQb, uri, projection); 4864a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 4865a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4866a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4867a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4868a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.CONTACT_ID, contactId, 4869a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.LOOKUP_KEY, lookupKey); 4870a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 4871a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 4872a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4873a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4874a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4875a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 4876a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 4877a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 4878a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + Contacts.Entity.CONTACT_ID + "=?"); 4879a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 4880a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4881a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 48823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 48833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 48843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 48853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 48873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 48883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 48893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 48903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemsColumns.CONCRETE_ID + "=?"); 48913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 48923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 48943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_LIMIT: { 48956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro MatrixCursor cursor = new MatrixCursor(new String[]{StreamItems.MAX_ITEMS}, 1); 48966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro cursor.addRow(new Object[]{MAX_STREAM_ITEMS_PER_RAW_CONTACT}); 48973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return cursor; 48983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 49003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 49013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 49023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 49033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 49043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 49053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 49063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 49073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 49083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 49093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?"); 49103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 49113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 49123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 49133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 49143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 49153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 49163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 49173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemPhotoId); 49183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 49193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=? AND " + 49203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=?"); 49213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 49223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 49233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4924f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case PHOTO_DIMENSIONS: { 4925f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro MatrixCursor cursor = new MatrixCursor( 4926f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM}, 4927f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1); 4928f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cursor.addRow(new Object[]{mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim}); 4929f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return cursor; 4930f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 4931f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 49324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case PHONES: { 493382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 493489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 49352815f58f72f109790585931f601a63ddc02536a5Evan Millar break; 49362815f58f72f109790585931f601a63ddc02536a5Evan Millar } 49372815f58f72f109790585931f601a63ddc02536a5Evan Millar 493848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: { 493982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 49404da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 494148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 49424da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 494348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 494448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 494548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 4946ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES_FILTER: { 494746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 494846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 494946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 495046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_CALL; 495146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 495246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 495389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 4954ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 49554a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 49564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4957a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(" AND ("); 49585e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 495945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov boolean hasCondition = false; 49605e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov boolean orNeeded = false; 49615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov String normalizedName = NameNormalizer.normalize(filterParam); 49625e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (normalizedName.length() > 0) { 4963155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(Data.RAW_CONTACT_ID + " IN " + 4964155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 4965155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 4966155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 4967155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 4968155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 4969155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 49702352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 4971155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 49725e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov orNeeded = true; 497345d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 49745e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49755e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 4976892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String number = PhoneNumberUtils.normalizeNumber(filterParam); 4977892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (!TextUtils.isEmpty(number)) { 49785e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (orNeeded) { 49795e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(" OR "); 49805e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49815e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(Data._ID + 4982892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID 4983892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " FROM " + Tables.PHONE_LOOKUP 4984892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 4985892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append(number); 4986892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append("%')"); 498745d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 498845d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov } 498945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov 499045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov if (!hasCondition) { 499145d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // If it is neither a phone number nor a name, the query should return 499245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // an empty cursor. Let's ensure that. 499345d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov sb.append("0"); 49945e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49955e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 4996a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 4997ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 49985e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = PhoneColumns.NORMALIZED_NUMBER + "," + RawContacts.CONTACT_ID; 4999a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 500046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 500146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 500246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + PHONE_FILTER_SORT_ORDER; 500346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 500446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = PHONE_FILTER_SORT_ORDER; 500546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 5006a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 5007ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5008ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5009ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 50104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case EMAILS: { 501182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 501289c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 50134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov break; 50144a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 50154a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 501648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: { 501782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50184da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 50194da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'" 50204da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + " AND " + Data._ID + "=?"); 502148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 502248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 502348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 50245e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_LOOKUP: { 502582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 502689c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 50274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov if (uri.getPathSegments().size() > 2) { 502808768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String email = uri.getLastPathSegment(); 502908768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String address = mDbHelper.extractAddressFromEmailAddress(email); 503008768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, address); 503108768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)"); 50324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 5033ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5034ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5035ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 50365e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_FILTER: { 503746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 503846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 503946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 504046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT; 504146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 504246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 504307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov String filterParam = null; 50447d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa 504507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 504607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = uri.getLastPathSegment(); 504707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (TextUtils.isEmpty(filterParam)) { 504807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = null; 504907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 505007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 50515e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 505207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (filterParam == null) { 505307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov // If the filter is unspecified, return nothing 505407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov qb.appendWhere(" AND 0"); 505507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } else { 505607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov StringBuilder sb = new StringBuilder(); 505707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append(" AND " + Data._ID + " IN ("); 505807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append( 505907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov "SELECT " + Data._ID + 506007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov " FROM " + Tables.DATA + 50612a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov " WHERE " + DataColumns.MIMETYPE_ID + "="); 50622a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(mDbHelper.getMimeTypeIdForEmail()); 50632a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(" AND " + Data.DATA1 + " LIKE "); 506407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 506520938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov if (!filterParam.contains("@")) { 5066155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append( 5067155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " UNION SELECT " + Data._ID + 5068155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.DATA + 5069155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE +" + DataColumns.MIMETYPE_ID + "="); 5070155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(mDbHelper.getMimeTypeIdForEmail()); 5071155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(" AND " + Data.RAW_CONTACT_ID + " IN " + 5072155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 5073155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 5074155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 5075155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 5076155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 5077155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 50782352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 5079155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 50805e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 50815e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 5082a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 50835e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 50845e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = Email.DATA + "," + RawContacts.CONTACT_ID; 5085a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 508646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 508746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 508846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + EMAIL_FILTER_SORT_ORDER; 50897d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } else { 50907d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa sortOrder = EMAIL_FILTER_SORT_ORDER; 50917d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } 5092a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 50935e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov break; 50945e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 50955e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 5096ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 509782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 509889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 509989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 5100ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5101ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5102ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 510348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 510482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 51054da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 510648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 510748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 51084da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 510948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 511048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 511148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 51125ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 5113763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 51144b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki profileRestrictionColumnName = RawContacts.RAW_CONTACT_IS_USER_PROFILE; 51154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 51164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 51174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 51185ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 51195ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 5120afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 5121763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 51224da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 51234da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 51244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 51254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 51264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 51275ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 51285ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 512982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 51304da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 51314da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?"); 51324b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki profileRestrictionColumnName = RawContacts.RAW_CONTACT_IS_USER_PROFILE; 513324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 513424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 513524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 51363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 51373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5138afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 51393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 51403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 51413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=?"); 51423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 51433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 514424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 514524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 514624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 514724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 514824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 514924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 515024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 515124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 515224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: { 515324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 515424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = ContentUris.parseId(uri); 515524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 515624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 515724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 515824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts._ID + "=?"); 515924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 516024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 516124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 516224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 516324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 516424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 516524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 516624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 516724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 516824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + Data.RAW_CONTACT_ID + "=?"); 516924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 517024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 517124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 517224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_ENTITIES: { 517324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 517424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 517524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 517624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawEntities(qb, uri); 517724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 517824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts._ID + "=?"); 5179e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5180e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5181e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 5182e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey case DATA: { 518382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 51844b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki profileRestrictionColumnName = RawContacts.RAW_CONTACT_IS_USER_PROFILE; 5185e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5186e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5187e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 51884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case DATA_ID: { 518924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = ContentUris.parseId(uri); 5190afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForData(db, dataId, false); 519182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 51924da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 51934da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 5194a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov break; 5195a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov } 5196a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov 5197a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 51984a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 5199a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton if (TextUtils.isEmpty(sortOrder)) { 5200a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Default the sort order to something reasonable so we get consistent 5201a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // results when callers don't request an ordering 5202892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sortOrder = " length(lookup.normalized_number) DESC"; 5203a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5204a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5205e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : ""; 5206e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov String numberE164 = PhoneNumberUtils.formatNumberToE164(number, 5207e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov mDbHelper.getCurrentCountryIso()); 5208892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String normalizedNumber = 5209892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov PhoneNumberUtils.normalizeNumber(number); 5210892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov mDbHelper.buildPhoneLookupAndContactQuery(qb, normalizedNumber, numberE164); 5211e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov qb.setProjectionMap(sPhoneLookupProjectionMap); 5212e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov // Phone lookup cannot be combined with a selection 5213e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selection = null; 5214e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selectionArgs = null; 5215a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 5216a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5217a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5218ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 5219ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5220ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 522143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 5222ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5223ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5224ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5225ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 5226ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5227ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 52284da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 52294da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Groups._ID + "=?"); 5230ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5231ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5232ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5233ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 5234f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa final boolean returnGroupCountPerAccount = 5235f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa readBooleanQueryParameter(uri, Groups.PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT, 5236f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa false); 5237f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa qb.setTables(Views.GROUPS + " AS " + Tables.GROUPS); 5238f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa qb.setProjectionMap(returnGroupCountPerAccount ? 5239f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa sGroupsSummaryProjectionMapWithGroupCountPerAccount 5240f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa : sGroupsSummaryProjectionMap); 524143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 5242f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa groupBy = GroupsColumns.CONCRETE_ID; 5243ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5244ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5245ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5246b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 52470c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS); 5248b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 5249b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 5250b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 5251b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 525231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 5253d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 52542d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov String filter = null; 52552d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 52562d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov filter = uri.getPathSegments().get(3); 52572d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov } 525831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 5259d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov if (limit != null) { 5260d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov maxSuggestions = Integer.parseInt(limit); 526131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 526231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 526331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 526431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 52655b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ArrayList<AggregationSuggestionParameter> parameters = null; 52665b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov List<String> query = uri.getQueryParameters("query"); 52675b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov if (query != null && !query.isEmpty()) { 52685b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters = new ArrayList<AggregationSuggestionParameter>(query.size()); 52695b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov for (String parameter : query) { 52705b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov int offset = parameter.indexOf(':'); 52715b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters.add(offset == -1 52725b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ? new AggregationSuggestionParameter( 527376dfa406e2cde19c824983c37fc92c1c5bf63eecDaniel Lehmann AggregationSuggestions.PARAMETER_MATCH_NAME, 52745b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter) 52755b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov : new AggregationSuggestionParameter( 52765b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(0, offset), 52775b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(offset + 1))); 52785b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 52795b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 52805b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 5281763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 52827581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov 52837581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov return mContactAggregator.queryAggregationSuggestions(qb, projection, contactId, 52845b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov maxSuggestions, filter, parameters); 528531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 528631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 5287eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 5288eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setTables(Tables.SETTINGS); 5289eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setProjectionMap(sSettingsProjectionMap); 529043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, false); 5291e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5292e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // When requesting specific columns, this query requires 5293e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // late-binding of the GroupMembership MIME-type. 5294b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final String groupMembershipMimetypeId = Long.toString(mDbHelper 5295e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 529682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 5297b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.isInProjection(projection, Settings.UNGROUPED_COUNT)) { 5298e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5299e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 530082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 5301b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.isInProjection(projection, Settings.UNGROUPED_WITH_PHONES)) { 5302e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5303e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 5304e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5305eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 5306eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 5307eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 530882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 53090a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 53105ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 53115ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 53125ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 531382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES_ID: { 53140a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 53154da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 53164da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(DataColumns.CONCRETE_ID + "=?"); 53175ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 53185ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 53195ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 5320c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: { 5321174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchSuggestionsQuery( 5322174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, uri, projection, limit); 5323c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5324c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 5325c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: { 53262d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill String lookupKey = uri.getLastPathSegment(); 5327174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String filter = getQueryParameter( 5328174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov uri, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 5329174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchShortcutRefresh( 5330174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, projection, lookupKey, filter); 5331c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5332c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 53331b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS: 5334ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 53351b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 53361b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 53371b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 53381b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_WITH_PHONES: 5339ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 53401b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 53411b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1"); 53421b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 53431b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 53441b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_FAVORITES: 5345ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 53461b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 53471b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.STARRED + "=1"); 53481b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 53491b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 53501b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_GROUP_NAME: 5351ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 53521b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 535371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 53541b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 53551b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 53561b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 535746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITIES: { 5358a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 535946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 536046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 536146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 536246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITY_ID: { 536346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5364a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 53654da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 53664da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 536746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 536846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 536946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 537009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov case PROVIDER_STATUS: { 537109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return queryProviderStatus(uri, projection); 537209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 537309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5374d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES : { 5375d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5376d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5377d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5378d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5379d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 5380d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID : { 5381385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov long id = ContentUris.parseId(uri); 5382d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5383d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5384385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(id)); 5385d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.appendWhere(Directory._ID + "=?"); 5386d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5387d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5388d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 53897a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov case COMPLETE_NAME: { 53907a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return completeName(uri, projection); 53917a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 53927a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 53934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 5394f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 5395c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov sortOrder, limit); 53964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 53974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 539809e69522745551522c55dff27424496f255def46Daniel Lehmann qb.setStrict(true); 53997f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov 54004b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki if (profileRestrictionColumnName != null) { 54014b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki // This check is very slow and most of the rows will pass though this check, so 54024b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki // it should be put after user's selection, so SQLite won't do this check first. 54034b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki selection = appendProfileRestriction(uri, profileRestrictionColumnName, 54044b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki suppressProfileCheck, selection); 54054b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki } 54064b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki 5407ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov Cursor cursor = 5408ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit); 5409ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) { 5410ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov cursor = bundleLetterCountExtras(cursor, db, qb, selection, selectionArgs, sortOrder); 5411ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5412ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov return cursor; 54135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 54145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection, 54165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String selection, String[] selectionArgs, String sortOrder, String groupBy, 54175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String limit) { 5418038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana if (projection != null && projection.length == 1 5419038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana && BaseColumns._COUNT.equals(projection[0])) { 5420038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana qb.setProjectionMap(sCountProjectionMap); 5421038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana } 54225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null, 54235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sortOrder, limit); 54244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 54254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 54264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 54274f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 54284f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 54294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 543009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov /** 543109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov * Creates a single-row cursor containing the current status of the provider. 543209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov */ 543309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private Cursor queryProviderStatus(Uri uri, String[] projection) { 543409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 543509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov RowBuilder row = cursor.newRow(); 543609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov for (int i = 0; i < projection.length; i++) { 543709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov if (ProviderStatus.STATUS.equals(projection[i])) { 543809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mProviderStatus); 543909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } else if (ProviderStatus.DATA1.equals(projection[i])) { 544009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mEstimatedStorageRequirement); 544109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 544209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 544309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return cursor; 544409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 544509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5446a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** 5447a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * Runs the query with the supplied contact ID and lookup ID. If the query succeeds, 5448a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * it returns the resulting cursor, otherwise it returns null and the calling 5449a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * method needs to resolve the lookup key and rerun the query. 5450a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov */ 5451a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private Cursor queryWithContactIdAndLookupKey(SQLiteQueryBuilder lookupQb, 5452a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteDatabase db, Uri uri, 5453a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection, String selection, String[] selectionArgs, 5454a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String sortOrder, String groupBy, String limit, 5455a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn, long contactId, String lookupKeyColumn, String lookupKey) { 5456a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] args; 5457a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (selectionArgs == null) { 5458a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[2]; 5459a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } else { 5460a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[selectionArgs.length + 2]; 5461a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 5462a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5463a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[0] = String.valueOf(contactId); 5464a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[1] = Uri.encode(lookupKey); 5465a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(contactIdColumn + "=? AND " + lookupKeyColumn + "=?"); 5466a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = query(db, lookupQb, projection, selection, args, sortOrder, 5467a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov groupBy, limit); 5468a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c.getCount() != 0) { 5469a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5470a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5471a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5472a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov c.close(); 5473a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return null; 5474a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 547509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5476bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov private static final class AddressBookIndexQuery { 5477bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String LETTER = "letter"; 5478bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String TITLE = "title"; 5479bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String COUNT = "count"; 5480ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5481bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String[] COLUMNS = new String[] { 5482bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov LETTER, TITLE, COUNT 5483ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov }; 5484ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5485bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_LETTER = 0; 5486bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_TITLE = 1; 5487bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_COUNT = 2; 5488bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 548924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The first letter of the sort key column is what is used for the index headings, except 549024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // in the case of the user's profile, in which case it is empty. 549124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro public static final String SECTION_HEADING_TEMPLATE = 549224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "(CASE WHEN %1$s=1 THEN '' ELSE SUBSTR(%2$s,1,1) END)"; 549324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5494de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa public static final String ORDER_BY = LETTER + " COLLATE " + PHONEBOOK_COLLATOR_NAME; 5495ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5496ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5497ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov /** 5498ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * Computes counts by the address book index titles and adds the resulting tally 5499ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * to the returned cursor as a bundle of extras. 5500ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov */ 5501ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov private Cursor bundleLetterCountExtras(Cursor cursor, final SQLiteDatabase db, 5502ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov SQLiteQueryBuilder qb, String selection, String[] selectionArgs, String sortOrder) { 5503ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortKey; 5504ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5505ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // The sort order suffix could be something like "DESC". 5506ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // We want to preserve it in the query even though we will change 5507ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // the sort column itself. 5508ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortOrderSuffix = ""; 5509ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (sortOrder != null) { 551024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 551124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // If the sort order contains one of the "is_profile" columns, we need to strip it out 551224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // first. 551324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (sortOrder.contains(Contacts.IS_USER_PROFILE) 551424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro || sortOrder.contains(RawContacts.RAW_CONTACT_IS_USER_PROFILE)) { 551524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String[] splitOrderClauses = sortOrder.split(","); 551624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro StringBuilder rejoinedClause = new StringBuilder(); 551724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro for (String orderClause : splitOrderClauses) { 551824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!orderClause.contains(Contacts.IS_USER_PROFILE) 551924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro && !orderClause.contains(RawContacts.RAW_CONTACT_IS_USER_PROFILE)) { 552024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (rejoinedClause.length() > 0) { 552124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro rejoinedClause.append(", "); 552224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 552324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro rejoinedClause.append(orderClause.trim()); 552424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 552524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 552624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sortOrder = rejoinedClause.toString(); 552724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 552824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5529ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int spaceIndex = sortOrder.indexOf(' '); 5530ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (spaceIndex != -1) { 5531ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder.substring(0, spaceIndex); 5532ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortOrderSuffix = sortOrder.substring(spaceIndex); 5533ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5534ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder; 5535ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5536ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5537ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = Contacts.SORT_KEY_PRIMARY; 5538ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5539ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5540bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String locale = getLocale().toString(); 5541ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov HashMap<String, String> projectionMap = Maps.newHashMap(); 554224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 554324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The user profile column varies depending on the view. 5544ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann String profileColumn = qb.getTables().contains(Views.CONTACTS) 554524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro ? Contacts.IS_USER_PROFILE 554624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro : RawContacts.RAW_CONTACT_IS_USER_PROFILE; 554724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String sectionHeading = String.format( 554824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro AddressBookIndexQuery.SECTION_HEADING_TEMPLATE, profileColumn, sortKey); 5549bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov projectionMap.put(AddressBookIndexQuery.LETTER, 555024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sectionHeading + " AS " + AddressBookIndexQuery.LETTER); 5551bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5552bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov /** 5553bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * Use the GET_PHONEBOOK_INDEX function, which is an android extension for SQLite3, 5554bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * to map the first letter of the sort key to a character that is traditionally 5555bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * used in phonebooks to represent that letter. For example, in Korean it will 5556bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * be the first consonant in the letter; for Japanese it will be Hiragana rather 5557bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * than Katakana. 5558bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov */ 5559ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.TITLE, 556024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "GET_PHONEBOOK_INDEX(" + sectionHeading + ",'" + locale + "')" 5561bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov + " AS " + AddressBookIndexQuery.TITLE); 5562ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.COUNT, 5563ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov "COUNT(" + Contacts._ID + ") AS " + AddressBookIndexQuery.COUNT); 5564ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov qb.setProjectionMap(projectionMap); 5565ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5566f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs, 5567ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY, null /* having */, 5568ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY + sortOrderSuffix); 5569ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5570ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov try { 5571f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov int groupCount = indexCursor.getCount(); 5572ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String titles[] = new String[groupCount]; 5573ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int counts[] = new int[groupCount]; 5574bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int indexCount = 0; 5575bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String currentTitle = null; 5576bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5577bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // Since GET_PHONEBOOK_INDEX is a many-to-1 function, we may end up 5578bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // with multiple entries for the same title. The following code 5579bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // collapses those duplicates. 5580ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov for (int i = 0; i < groupCount; i++) { 5581f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.moveToNext(); 5582bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String title = indexCursor.getString(AddressBookIndexQuery.COLUMN_TITLE); 5583bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int count = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT); 5584bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount == 0 || !TextUtils.equals(title, currentTitle)) { 5585bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles[indexCount] = currentTitle = title; 5586bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount] = count; 5587bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov indexCount++; 5588bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } else { 5589bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount - 1] += count; 5590bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5591bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5592bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5593bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount < groupCount) { 5594bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String[] newTitles = new String[indexCount]; 5595bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(titles, 0, newTitles, 0, indexCount); 5596bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles = newTitles; 5597bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5598bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int[] newCounts = new int[indexCount]; 5599bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(counts, 0, newCounts, 0, indexCount); 5600bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts = newCounts; 5601ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5602ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5603e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return new AddressBookCursor((CrossProcessCursor) cursor, titles, counts); 5604ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } finally { 5605f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.close(); 5606ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5607ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5608ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 56092d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill /** 561092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Returns the contact Id for the contact identified by the lookupKey. 561192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Robust against changes in the lookup key: if the key has changed, will 561292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * look up the contact by the raw contact IDs or name encoded in the lookup 561392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * key. 56142d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill */ 56152d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) { 56165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey key = new ContactLookupKey(); 56175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments = key.parse(lookupKey); 56185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 561992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov long contactId = -1; 562092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_SOURCE_ID)) { 562192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdBySourceIds(db, segments); 562292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 562392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 562492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 562592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 562692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 562792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov boolean hasRawContactIds = 562892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID); 562992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds) { 563092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdByRawContactIds(db, segments); 563192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 563292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 563392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 563492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 563592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 563692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds 563792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME)) { 56385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = lookupContactIdByDisplayNames(db, segments); 56395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 56425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private interface LookupBySourceIdQuery { 564543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 56465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 56485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 564943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 56505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 56515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.SOURCE_ID 56525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 56535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 565543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 56565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 56575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int SOURCE_ID = 3; 56585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long lookupContactIdBySourceIds(SQLiteDatabase db, 56615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments) { 56625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 56635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(RawContacts.SOURCE_ID + " IN ("); 56645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 56655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 566692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID) { 56675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 56685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 56695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 56725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 56735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS, 56755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 56765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 56775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 567843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 567943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 56805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME); 56815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 568243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 56835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID); 56845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 56855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 568692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID 568792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 56885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(sourceId)) { 56895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID); 56905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 56915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 56955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 56965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 56995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 570192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByRawContactIdQuery { 570243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 57035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 57045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 57055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 570643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 57075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 570892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts._ID, 57095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 57105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 57115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 571243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 57135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 571492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ID = 3; 57155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 571792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByRawContactIds(SQLiteDatabase db, 571892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 571992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 572092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(RawContacts._ID + " IN ("); 57215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 57225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 572392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 572492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(segment.rawContactId); 572592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(","); 57265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 572892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 572992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 57305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 573192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov Cursor c = db.query(LookupByRawContactIdQuery.TABLE, LookupByRawContactIdQuery.COLUMNS, 573292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.toString(), null, null, null, null); 573392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov try { 573492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov while (c.moveToNext()) { 573543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = c.getString( 573643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro LookupByRawContactIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 573792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountName = c.getString(LookupByRawContactIdQuery.ACCOUNT_NAME); 573892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int accountHashCode = 573943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 574092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String rawContactId = c.getString(LookupByRawContactIdQuery.ID); 574192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 574292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 574392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID 574492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 574592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && segment.rawContactId.equals(rawContactId)) { 574692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov segment.contactId = c.getLong(LookupByRawContactIdQuery.CONTACT_ID); 574792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov break; 574892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 574992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 575092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 575192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } finally { 575292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov c.close(); 57535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 575592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return getMostReferencedContactId(segments); 575692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 575792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 575892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByDisplayNameQuery { 575992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS; 576092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 576192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String COLUMNS[] = { 576292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.CONTACT_ID, 576343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 576492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 576592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov NameLookupColumns.NORMALIZED_NAME 576692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov }; 576792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 576892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int CONTACT_ID = 0; 576943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 577092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_NAME = 2; 577192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int NORMALIZED_NAME = 3; 577292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 577392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 577492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByDisplayNames(SQLiteDatabase db, 577592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 57765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 57775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(NameLookupColumns.NORMALIZED_NAME + " IN ("); 57785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 57795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 578092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 578192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 57825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 57835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 57845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 57875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY 57885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov + " AND " + RawContacts.CONTACT_ID + " NOT NULL"); 57895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 57905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS, 57915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 57925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 57935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 579443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 579543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE_AND_DATA_SET); 57965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME); 57975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 579843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 57995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME); 58005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 58015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 580292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if ((segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 580392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) 580492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 58055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(name)) { 58065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID); 58075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 58085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 58125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 58135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 58165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 581892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private boolean lookupKeyContainsType(ArrayList<LookupKeySegment> segments, int lookupType) { 581992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 582092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 582192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == lookupType) { 582292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return true; 582392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 582492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 582592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 582692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return false; 582792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 582892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 5829ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateLookupKeyForRawContact(SQLiteDatabase db, long rawContactId) { 5830ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov mContactAggregator.updateLookupKeyForRawContact(db, rawContactId); 5831ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov } 5832ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov 58335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov /** 58345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov * Returns the contact ID that is mentioned the highest number of times. 58355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov */ 58365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) { 58375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Collections.sort(segments); 58385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long bestContactId = -1; 58405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int bestRefCount = 0; 58415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = -1; 58435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int count = 0; 58445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = segments.size(); 58465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segmentCount; i++) { 58475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 58485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId != -1) { 58495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId == contactId) { 58505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count++; 58515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 58525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 58535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestContactId = contactId; 58545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestRefCount = count; 58555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = segment.contactId; 58575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count = 1; 58585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 58625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 58635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 58645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return bestContactId; 58655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 5868763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 5869763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar String[] projection) { 58704928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 58712f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 58722f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 58732f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 58744928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * @param includeDataUsageStat true when the table should include DataUsageStat table. 58754928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Note that this uses INNER JOIN instead of LEFT OUTER JOIN, so some of data in Contacts 58764928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * may be dropped. 58772f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 58782f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 58794928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa String[] projection, boolean includeDataUsageStat) { 588082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 5881ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 58822f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 58832f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Just for frequently contacted contacts in Strequent Uri handling. 58844928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (includeDataUsageStat) { 58852f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa sb.append(" INNER JOIN " + 5886ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA_USAGE_STAT + " AS " + Tables.DATA_USAGE_STAT + 58872f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa " ON (" + 58882f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DbQueryUtils.concatenateClauses( 58892f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DataUsageStatColumns.CONCRETE_TIMES_USED + " > 0", 58904928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) + 58912f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa ")"); 58922f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 58932f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 58947ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 58957ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 5896916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setTables(sb.toString()); 5897916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionMap); 5898916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov } 5899916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 5900916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** 5901916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * Finds name lookup records matching the supplied filter, picks one arbitrary match per 5902916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * contact and joins that with other contacts tables. 5903916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov */ 5904916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private void setTablesAndProjectionMapForContactsWithSnippet(SQLiteQueryBuilder qb, Uri uri, 59057ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov String[] projection, String filter, long directoryId) { 59067ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov 59077ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5908ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 5909916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 591003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (filter != null) { 591103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov filter = filter.trim(); 591203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 591303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 591430cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov if (TextUtils.isEmpty(filter) || (directoryId != -1 && directoryId != Directory.DEFAULT)) { 591530cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov sb.append(" JOIN (SELECT NULL AS " + SearchSnippetColumns.SNIPPET + " WHERE 0)"); 59165e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } else { 59175e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov appendSearchIndexJoin(sb, uri, projection, filter); 59185e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 59197ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 59207ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 592103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setTables(sb.toString()); 592203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionWithSnippetMap); 592303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 5924916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 592503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private void appendSearchIndexJoin( 592603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov StringBuilder sb, Uri uri, String[] projection, String filter) { 5927916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 5928174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET)) { 592903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String[] args = null; 593003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String snippetArgs = 593103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 593203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (snippetArgs != null) { 593303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov args = snippetArgs.split(","); 593403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 593503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 59365e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String startMatch = args != null && args.length > 0 ? args[0] 59375e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_START_MATCH; 59385e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String endMatch = args != null && args.length > 1 ? args[1] 59395e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_END_MATCH; 59405e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String ellipsis = args != null && args.length > 2 ? args[2] 59415e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_ELLIPSIS; 59425e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 59435e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 59445e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 5945174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin( 5946174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb, filter, true, startMatch, endMatch, ellipsis, maxTokens); 5947174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 5948174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin(sb, filter, false, null, null, null, 0); 5949174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5950174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5951174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 5952174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public void appendSearchIndexJoin(StringBuilder sb, String filter, 5953174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean snippetNeeded, String startMatch, String endMatch, String ellipsis, 5954174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int maxTokens) { 5955174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isEmailAddress = false; 5956174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String emailAddress = null; 5957174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isPhoneNumber = false; 5958174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String phoneNumber = null; 5959174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String numberE164 = null; 5960174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 59613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // If the query consists of a single word, we can do snippetizing after-the-fact for a 59623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // performance boost. 59633716f1447ceb21180d1301790eabd8b9453f486dDave Santoro boolean singleTokenSearch = filter.split(QUERY_TOKENIZER_REGEX).length == 1; 59643716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 5965174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (filter.indexOf('@') != -1) { 5966174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov emailAddress = mDbHelper.extractAddressFromEmailAddress(filter); 5967174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isEmailAddress = !TextUtils.isEmpty(emailAddress); 5968174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 5969174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isPhoneNumber = isPhoneNumber(filter); 597004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (isPhoneNumber) { 597104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann phoneNumber = PhoneNumberUtils.normalizeNumber(filter); 597204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann numberE164 = PhoneNumberUtils.formatNumberToE164(phoneNumber, 597304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann mDbHelper.getCountryIso()); 597404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 5975174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5976174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 5977174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(" JOIN (SELECT " + SearchIndexColumns.CONTACT_ID + " AS snippet_contact_id"); 5978174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (snippetNeeded) { 59795e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(", "); 59805e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 59813d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 59825e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 598304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Email.ADDRESS + ")"); 598404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + Tables.DATA_JOIN_RAW_CONTACTS); 598504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 598604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID + " AND " + Email.ADDRESS + " LIKE "); 598704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann DatabaseUtils.appendEscapedSQLString(sb, filter + "%"); 598804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 59893d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 59903d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(","); 59913716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 59923716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 59933716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 59943716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 59953716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 59963716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 59973716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 59983d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(")"); 59993d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 60003d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 60013d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 600204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Phone.NUMBER + ")"); 600304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + 600404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann Tables.DATA_JOIN_RAW_CONTACTS + " JOIN " + Tables.PHONE_LOOKUP); 600504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" ON " + DataColumns.CONCRETE_ID); 600604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID); 600704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 600804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID); 600904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" AND " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 601004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(phoneNumber); 601104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 601204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(numberE164)) { 601304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" OR " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 601404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(numberE164); 601504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 601604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 601704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 60185e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 60195e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 60203716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 60213716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 60223716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 60233716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 60243716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 60253716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 60263716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 60275e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 602803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 602904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann final String normalizedFilter = NameNormalizer.normalize(filter); 603004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(normalizedFilter)) { 60313716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 60323716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 60333716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 60343716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 60353716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("(CASE WHEN EXISTS (SELECT 1 FROM "); 60363716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.RAW_CONTACTS + " AS rc INNER JOIN "); 60373716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.NAME_LOOKUP + " AS nl ON (rc." + RawContacts._ID); 60383716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=nl." + NameLookupColumns.RAW_CONTACT_ID); 60393716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") WHERE nl." + NameLookupColumns.NORMALIZED_NAME); 60403716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" GLOB '" + normalizedFilter + "*' AND "); 60413716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("nl." + NameLookupColumns.NAME_TYPE + "="); 60423716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(NameLookupType.NAME_COLLATION_KEY + " AND "); 60433716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 60443716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=rc." + RawContacts.CONTACT_ID); 60453716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") THEN NULL ELSE "); 60463716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 60473716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" END)"); 60483716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 604904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } else { 605004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("NULL"); 605104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 605203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 60535e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" AS " + SearchSnippetColumns.SNIPPET); 60545e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 605503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 60565e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" FROM " + Tables.SEARCH_INDEX); 60575e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" WHERE "); 60585e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(Tables.SEARCH_INDEX + " MATCH "); 60595e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 60602352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, "\"" + sanitizeMatch(filter) + "*\""); 60613d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 60622352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, 606304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann "\"" + sanitizeMatch(filter) + "*\" OR \"" + phoneNumber + "*\"" 60642352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov + (numberE164 != null ? " OR \"" + numberE164 + "\"" : "")); 606503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 60662352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filter) + "*"); 60679c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov } 606803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov sb.append(") ON (" + Contacts._ID + "=snippet_contact_id)"); 6069a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov } 6070a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov 60712352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov private String sanitizeMatch(String filter) { 60722352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov // TODO more robust preprocessing of match expressions 60732352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov return filter.replace('-', ' ').replace('\"', ' '); 60742352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov } 60752352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov 60765e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov private void appendSnippetFunction( 60775e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov StringBuilder sb, String startMatch, String endMatch, String ellipsis, int maxTokens) { 60785e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append("snippet(" + Tables.SEARCH_INDEX + ","); 60795e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 60805e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 60815e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 60825e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 60835e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, ellipsis); 60845e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 60855e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov // The index of the column used for the snippet, "content" 60865e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(",1,"); 60875e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(maxTokens); 60885e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 60895e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 60905e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 6091763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) { 6092763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar StringBuilder sb = new StringBuilder(); 6093ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.RAW_CONTACTS); 6094763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setTables(sb.toString()); 6095763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setProjectionMap(sRawContactsProjectionMap); 609643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 6097763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar } 6098763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar 6099a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForRawEntities(SQLiteQueryBuilder qb, Uri uri) { 6100ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.RAW_ENTITIES); 6101a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sRawEntityProjectionMap); 610243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 610346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 610446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 610582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 610682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String[] projection, boolean distinct) { 610746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, distinct, null); 610846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 610946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 611046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 611146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @param usageType when non-null {@link Tables#DATA_USAGE_STAT} is joined with the specified 611246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type. 611346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 611446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 611546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String[] projection, boolean distinct, Integer usageType) { 611682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6117ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 611882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov sb.append(" data"); 611982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov 6120a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID); 6121a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6122a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6123a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 61243296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey 612546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (usageType != null) { 612646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa appendDataUsageStatJoin(sb, usageType, DataColumns.CONCRETE_ID); 612746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 612846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 612982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov qb.setTables(sb.toString()); 6130f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov 6131f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov boolean useDistinct = distinct 6132f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov || !mDbHelper.isInProjection(projection, DISTINCT_DATA_PROHIBITING_COLUMNS); 6133f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setDistinct(useDistinct); 6134f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setProjectionMap(useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap); 613543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 6136ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov } 6137ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov 61380a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb, 61390a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String[] projection) { 61400a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6141ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 61420a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" data"); 6143a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6144a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 61450a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6146a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6147a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sStatusUpdatesProjectionMap); 6148a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6149a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 61503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItems(SQLiteQueryBuilder qb) { 61511dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.STREAM_ITEMS 61521dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.RAW_CONTACTS + " ON (" 61531dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemsColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 61541dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.CONTACTS + " ON (" 61551dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + RawContactsColumns.CONCRETE_CONTACT_ID + "=" + ContactsColumns.CONCRETE_ID + ")"); 61563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemsProjectionMap); 61573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 61583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 61593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItemPhotos(SQLiteQueryBuilder qb) { 61601dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.PHOTO_FILES 61611dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.STREAM_ITEM_PHOTOS + " ON (" 61621dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_PHOTO_FILE_ID + "=" 61631dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + PhotoFilesColumns.CONCRETE_ID 61641dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.STREAM_ITEMS + " ON (" 61651dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=" 61661dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemsColumns.CONCRETE_ID + ")"); 61673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemPhotosProjectionMap); 61683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 61693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 6170a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForEntities(SQLiteQueryBuilder qb, Uri uri, 6171a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection) { 6172a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6173ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.ENTITIES); 6174a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" data"); 6175a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6176a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts.Entity.CONTACT_ID); 6177a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6178a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, Contacts.Entity.DATA_ID); 6179a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, Contacts.Entity.DATA_ID); 6180a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6181a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6182a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sEntityProjectionMap); 618343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 6184a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6185a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6186a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactStatusUpdateJoin(StringBuilder sb, String[] projection, 6187a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lastStatusUpdateIdColumn) { 6188a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, 6189a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS, 6190a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_RES_PACKAGE, 6191a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_ICON, 6192a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_LABEL, 6193a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_TIMESTAMP)) { 6194a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " " 6195a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.ALIAS + 6196a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + lastStatusUpdateIdColumn + "=" 6197a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")"); 61980a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6199a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 62000a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6201a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataStatusUpdateJoin(StringBuilder sb, String[] projection, 6202a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 6203b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov if (mDbHelper.isInProjection(projection, 62040a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS, 62050a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_RES_PACKAGE, 62060a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_ICON, 62070a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_LABEL, 62080a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_TIMESTAMP)) { 62090a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + 6210a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "=" 6211a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + dataIdColumn + ")"); 62120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6213a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6214a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 621546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void appendDataUsageStatJoin(StringBuilder sb, int usageType, String dataIdColumn) { 621646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" LEFT OUTER JOIN " + Tables.DATA_USAGE_STAT + 621746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" + dataIdColumn + 621846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " AND " + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" + usageType + ")"); 621946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 622046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 6221a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactPresenceJoin(StringBuilder sb, String[] projection, 6222a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn) { 6223a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, 6224a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_PRESENCE, Contacts.CONTACT_CHAT_CAPABILITY)) { 6225a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + 6226a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + contactIdColumn + " = " 6227a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + ")"); 6228a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6229a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6230a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6231a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataPresenceJoin(StringBuilder sb, String[] projection, 6232a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 6233a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, Data.PRESENCE, Data.CHAT_CAPABILITY)) { 6234a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE + 6235a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdates.DATA_ID + "=" + dataIdColumn + ")"); 6236a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6237a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6238a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 623924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private boolean appendLocalDirectorySelectionIfNeeded(SQLiteQueryBuilder qb, long directoryId) { 6240385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directoryId == Directory.DEFAULT) { 6241385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY); 624224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 6243385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directoryId == Directory.LOCAL_INVISIBLE){ 6244385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " NOT IN " + Tables.DEFAULT_DIRECTORY); 624524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 624624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 624724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return false; 624824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 624924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 62504b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki private String appendProfileRestriction(Uri uri, String profileColumn, 62514b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki boolean suppressProfileCheck, String originalSelection) { 62524b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki if (shouldIncludeProfile(uri, suppressProfileCheck)) { 62534b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki return originalSelection; 62544b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki } else { 62554b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki final String SELECTION = "(" + profileColumn + " IS NULL OR " + profileColumn + "=0)"; 62564b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki if (TextUtils.isEmpty(originalSelection)) { 62574b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki return SELECTION; 62584b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki } else { 62594b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki StringBuilder sb = new StringBuilder(); 62604b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki sb.append("("); 62614b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki sb.append(originalSelection); 62624b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki sb.append(") AND "); 62634b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki sb.append(SELECTION); 62644b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki return sb.toString(); 62654b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki } 6266385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } 6267385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } 6268385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov 62696ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private String prependProfileSortIfNeeded(Uri uri, String sortOrder, 62706ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean suppressProfileCheck) { 62716ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (shouldIncludeProfile(uri, suppressProfileCheck)) { 627224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (TextUtils.isEmpty(sortOrder)) { 627324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return Contacts.IS_USER_PROFILE + " DESC"; 627424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else { 627524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return Contacts.IS_USER_PROFILE + " DESC, " + sortOrder; 627624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 627724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 627824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return sortOrder; 627924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 628024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 62816ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private boolean shouldIncludeProfile(Uri uri, boolean suppressProfileCheck) { 628224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The user's profile may be returned alongside other contacts if it was requested and 628324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // the calling application has permission to read profile data. 6284377850d2dfd28eaf1b22273a50cfe066f6667ab9Dave Santoro boolean profileRequested = readBooleanQueryParameter(uri, ContactsContract.ALLOW_PROFILE, 628524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro false); 62866ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (profileRequested && !suppressProfileCheck) { 628724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 628824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 628924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return profileRequested; 629024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 629124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 629243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri, 629343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro boolean includeDataSet) { 6294f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6295f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 629643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 6297e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6298e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6299e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6300e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 6301fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6302fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6303e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6304e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6305e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6306e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6307e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6308e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 630943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String toAppend = RawContacts.ACCOUNT_NAME + "=" 63104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + DatabaseUtils.sqlEscapeString(accountName) + " AND " 63114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + RawContacts.ACCOUNT_TYPE + "=" 631243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + DatabaseUtils.sqlEscapeString(accountType); 631343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (includeDataSet) { 631443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (dataSet == null) { 631543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro toAppend += " AND " + RawContacts.DATA_SET + " IS NULL"; 631643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } else { 631743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro toAppend += " AND " + RawContacts.DATA_SET + "=" + 631843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro DatabaseUtils.sqlEscapeString(dataSet); 631943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 632043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 632143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro qb.appendWhere(toAppend); 63224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } else { 63234a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere("1"); 63244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 63254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 63264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 6327e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong private String appendAccountToSelection(Uri uri, String selection) { 6328f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6329f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 633043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 6331e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6332e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6333e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6334e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 6335fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6336fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6337e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6338e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6339e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6340e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6341e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6342e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 6343e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "=" 6344e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountName) + " AND " 6345e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + RawContacts.ACCOUNT_TYPE + "=" 6346e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountType)); 634743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!TextUtils.isEmpty(dataSet)) { 634843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selectionSb.append(" AND " + RawContacts.DATA_SET + "=") 634943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .append(DatabaseUtils.sqlEscapeString(dataSet)); 635043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 6351e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong if (!TextUtils.isEmpty(selection)) { 6352e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(" AND ("); 6353e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(selection); 6354e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(')'); 6355e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6356e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selectionSb.toString(); 6357e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } else { 6358e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selection; 6359e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6360e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6361e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong 63627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 6363c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * Gets the value of the "limit" URI query parameter. 6364c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * 6365c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * @return A string containing a non-negative integer, or <code>null</code> if 6366c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * the parameter is not set, or is set to an invalid value. 6367c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov */ 6368f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private String getLimit(Uri uri) { 63692e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limitParam = getQueryParameter(uri, ContactsContract.LIMIT_PARAM_KEY); 6370c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (limitParam == null) { 6371c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6372c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6373c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov // make sure that the limit is a non-negative integer 6374c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov try { 6375c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov int l = Integer.parseInt(limitParam); 6376c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (l < 0) { 6377c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6378c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6379c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6380c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return String.valueOf(l); 6381c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } catch (NumberFormatException ex) { 6382c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6383c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6384c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6385c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6386c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 6387b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov @Override 6388f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 6389415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6390f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mode.equals("r")) { 6391f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mReadAccessLatch); 6392f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6393f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mWriteAccessLatch); 6394f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6395415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6396b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov int match = sUriMatcher.match(uri); 6397b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov switch (match) { 6398a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 6399afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 640024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6401afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 6402afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro return openPhotoAssetFile(db, uri, mode, 640324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Data._ID + "=" + Contacts.PHOTO_ID + " AND " + 640424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContacts.CONTACT_ID + "=?", 640524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(rawContactId)}); 6406e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6407b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6408f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: { 6409f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6410f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6411f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact ID can only be read."); 6412f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6413afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6414f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 6415afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6416afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = db.query(Tables.CONTACTS, 6417f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{Contacts.PHOTO_FILE_ID}, 6418f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID + "=?", new String[]{String.valueOf(contactId)}, 6419f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, null); 6420f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6421f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6422f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(0); 6423f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6424f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6425f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6426f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6427f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6428f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6429f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6430f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: { 6431f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6432f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6433f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact lookup key can only be read."); 6434f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6435f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro List<String> pathSegments = uri.getPathSegments(); 6436f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int segmentCount = pathSegments.size(); 6437f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount < 4) { 6438f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6439f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Missing a lookup key", uri)); 6440f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6441afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6442f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String lookupKey = pathSegments.get(2); 6443f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Contacts.PHOTO_FILE_ID}; 6444f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount == 5) { 6445f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(pathSegments.get(3)); 6446afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6447f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 6448f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 6449afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 6450f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro projection, null, null, null, null, null, 6451f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 6452f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c != null) { 6453f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6454f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6455f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6456f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6457f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6458f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6459f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6460f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6461f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6462f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6463f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6464f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 6465afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 6466afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6467afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = qb.query(db, projection, Contacts._ID + "=?", 6468f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(contactId)}, null, null, null); 6469f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6470f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6471f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6472f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6473f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6474f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6475f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6476f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6477f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6478f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: { 6479f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6480f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean writeable = !mode.equals("r"); 6481afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6482afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, writeable); 6483f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6484f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Find the primary photo data record for this raw contact. 6485f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6486f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Data._ID, Photo.PHOTO_FILE_ID}; 6487f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 6488afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = qb.query(db, projection, 6489f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?", 6490f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(rawContactId), Photo.CONTENT_ITEM_TYPE}, 6491f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, Data.IS_PRIMARY + " DESC"); 6492f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long dataId = 0; 6493f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = 0; 6494f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6495f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c.getCount() >= 1) { 6496f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6497f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro dataId = c.getLong(0); 6498f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro photoFileId = c.getLong(1); 6499f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6500f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6501f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6502f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6503f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6504f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If writeable, open a writeable file descriptor that we can monitor. 6505f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // When the caller finishes writing content, we'll process the photo and 6506f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // update the data record. 6507f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (writeable) { 6508f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForWrite(rawContactId, dataId, uri, mode); 6509f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6510f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6511f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6512f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6513f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6514f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: { 6515f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = ContentUris.parseId(uri); 6516f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6517f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6518f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by key can only be read."); 6519f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6520f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6521f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6522f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6523e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov case DATA_ID: { 6524afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 652524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = Long.parseLong(uri.getPathSegments().get(1)); 6526afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForData(db, dataId, false); 6527afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro return openPhotoAssetFile(db, uri, mode, 6528e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov Data._ID + "=? AND " + Data.MIMETYPE + "='" + Photo.CONTENT_ITEM_TYPE + "'", 652924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(dataId)}); 6530d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6531d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6532fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case PROFILE_AS_VCARD: { 6533fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // When opening a contact as file, we pass back contents as a 6534fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // vCard-encoded stream. We build into a local buffer first, 6535fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // then pipe into MemoryFile once the exact size is known. 6536fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6537fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6538fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen return buildAssetFileDescriptor(localStream); 6539fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 654042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 6541fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case CONTACTS_AS_VCARD: { 654242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // When opening a contact as file, we pass back contents as a 654342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // vCard-encoded stream. We build into a local buffer first, 654442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // then pipe into MemoryFile once the exact size is known. 654542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6546fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6547f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 654842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 654942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 655042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 655149d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov SQLiteDatabase db = mDbHelper.getReadableDatabase(); 655242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKeys = uri.getPathSegments().get(2); 655342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String[] loopupKeyList = lookupKeys.split(":"); 655442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final StringBuilder inBuilder = new StringBuilder(); 6555fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Uri queryUri = Contacts.CONTENT_URI; 655642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann int index = 0; 6557fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen 6558d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // SQLite has limits on how many parameters can be used 6559d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // so the IDs are concatenated to a query string here instead 656042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann for (String lookupKey : loopupKeyList) { 656142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann if (index == 0) { 6562d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append("("); 656342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } else { 6564d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append(","); 656542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 656624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 6567afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 656824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro inBuilder.append(contactId); 6569fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (mProfileIdCache.profileContactId == contactId) { 6570fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen queryUri = queryUri.buildUpon().appendQueryParameter( 6571377850d2dfd28eaf1b22273a50cfe066f6667ab9Dave Santoro ContactsContract.ALLOW_PROFILE, "true").build(); 6572fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 657342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann index++; 657442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 657542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann inBuilder.append(')'); 657642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String selection = Contacts._ID + " IN " + inBuilder.toString(); 6577d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6578d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // When opening a contact as file, we pass back contents as a 6579d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // vCard-encoded stream. We build into a local buffer first, 6580d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // then pipe into MemoryFile once the exact size is known. 6581d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6582fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(queryUri, localStream, selection, null); 6583f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 6584d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6585b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6586b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov default: 6587fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new FileNotFoundException(mDbHelper.exceptionMessage("File does not exist", 6588fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov uri)); 6589b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6590b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6591b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6592afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private AssetFileDescriptor openPhotoAssetFile(SQLiteDatabase db, Uri uri, String mode, 6593afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro String selection, String[] selectionArgs) 6594e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throws FileNotFoundException { 6595e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov if (!"r".equals(mode)) { 6596e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throw new FileNotFoundException(mDbHelper.exceptionMessage("Mode " + mode 6597e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov + " not supported.", uri)); 6598e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6599e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6600e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov String sql = 6601ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann "SELECT " + Photo.PHOTO + " FROM " + Views.DATA + 6602e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov " WHERE " + selection; 660308ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood try { 6604f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6605f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert DatabaseUtils.blobFileDescriptorForQuery(db, sql, selectionArgs)); 660608ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } catch (SQLiteDoneException e) { 660708ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood // this will happen if the DB query returns no rows (i.e. contact does not exist) 660808ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood throw new FileNotFoundException(uri.toString()); 660908ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } 6610e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6611e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6612f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6613f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a display photo from the photo store for reading. 6614f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoFileId The display photo file ID 6615f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor that allows the file to be read. 6616f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @throws FileNotFoundException If no photo file for the given ID exists. 6617f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6618f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForRead(long photoFileId) 6619f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throws FileNotFoundException { 6620f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoStore.Entry entry = mPhotoStore.get(photoFileId); 6621f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 6622f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return makeAssetFileDescriptor( 6623f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(new File(entry.path), 6624f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.MODE_READ_ONLY), 6625f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro entry.size); 6626f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6627f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 6628f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new FileNotFoundException("No photo file found for ID " + photoFileId); 6629f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6630f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6631f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6632f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6633f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a file descriptor for a photo to be written. When the caller completes writing 6634f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to the file (closing the output stream), the image will be parsed out and processed. 6635f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If processing succeeds, the given raw contact ID's primary photo record will be 6636f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * populated with the inserted image (if no primary photo record exists, the data ID can 6637f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * be left as 0, and a new data record will be inserted). 6638f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rawContactId Raw contact ID this photo entry should be associated with. 6639f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param dataId Data ID for a photo mimetype that will be updated with the inserted 6640f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * image. May be set to 0, in which case the inserted image will trigger creation 6641f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * of a new primary photo image data row for the raw contact. 6642f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param uri The URI being used to access this file. 6643f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param mode Read/write mode string. 6644f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor the caller can use to write an image file for the 6645f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact. 6646f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6647f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForWrite(long rawContactId, long dataId, Uri uri, 6648f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String mode) { 6649f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6650f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return new AssetFileDescriptor(new MonitoredParcelFileDescriptor(rawContactId, dataId, 6651f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(File.createTempFile("img", null), 6652f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentResolver.modeToMode(uri, mode))), 6653f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 0, AssetFileDescriptor.UNKNOWN_LENGTH); 6654f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException ioe) { 6655f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Could not create temp image file in mode " + mode); 6656f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return null; 6657f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6658f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6659f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6660f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6661f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Parcel file descriptor wrapper that monitors when the file is closed. 6662f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If the file contains a valid image, the image is either inserted into the given 6663f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact or updated in the given data row. 6664f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6665f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private class MonitoredParcelFileDescriptor extends ParcelFileDescriptor { 6666f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mRawContactId; 6667f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mDataId; 6668f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private MonitoredParcelFileDescriptor(long rawContactId, long dataId, 6669f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor descriptor) { 6670f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro super(descriptor); 6671f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mRawContactId = rawContactId; 6672f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDataId = dataId; 6673f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6674f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6675f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro @Override 6676f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public void close() throws IOException { 6677f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6678f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check to see whether a valid image was written out. 6679f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Bitmap b = BitmapFactory.decodeFileDescriptor(getFileDescriptor()); 6680f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (b != null) { 6681f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoProcessor processor = new PhotoProcessor(b, mMaxDisplayPhotoDim, 6682f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim); 6683f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6684f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Store the compressed photo in the photo store. 6685f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = mPhotoStore.insert(processor); 6686f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6687f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Depending on whether we already had a data row to attach the photo to, 6688f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // do an update or insert. 6689f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mDataId != 0) { 6690f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Update the data record with the new photo. 6691f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 6692f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6693f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6694f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6695f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6696f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6697f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6698f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6699f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6700f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro update(ContentUris.withAppendedId(Data.CONTENT_URI, mDataId), updateValues, 6701f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null); 6702f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6703f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Insert a new primary data record with the photo. 6704f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues insertValues = new ContentValues(); 6705f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6706f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6707f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6708f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6709f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 6710f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.IS_PRIMARY, 1); 6711f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6712f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6713f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6714f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6715f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insert(RawContacts.CONTENT_URI.buildUpon() 6716f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(String.valueOf(mRawContactId)) 6717f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(RawContacts.Data.CONTENT_DIRECTORY).build(), 6718f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues); 6719f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6720f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6721f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6722f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro super.close(); 6723f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6724f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6725f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6726f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6727d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile"; 6728d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6729d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6730f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert * Returns an {@link AssetFileDescriptor} backed by the 6731d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * contents of the given {@link ByteArrayOutputStream}. 6732d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6733f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) { 6734d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey try { 6735d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey stream.flush(); 6736d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6737d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final byte[] byteData = stream.toByteArray(); 6738d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6739f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6740f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert ParcelFileDescriptor.fromData(byteData, CONTACT_MEMORY_FILE_NAME), 6741f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert byteData.length); 6742d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } catch (IOException e) { 6743ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert Log.w(TAG, "Problem writing stream into an ParcelFileDescriptor: " + e.toString()); 6744ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert return null; 6745d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6746d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6747d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6748f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd) { 6749f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor(fd, AssetFileDescriptor.UNKNOWN_LENGTH); 6750f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6751f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6752f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd, long length) { 6753f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return fd != null ? new AssetFileDescriptor(fd, 0, length) : null; 6754f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6755f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6756d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6757d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * Output {@link RawContacts} matching the requested selection in the vCard 6758d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * format to the given {@link OutputStream}. This method returns silently if 6759d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * any errors encountered. 6760d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6761fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen private void outputRawContactsAsVCard(Uri uri, OutputStream stream, 6762fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen String selection, String[] selectionArgs) { 6763d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final Context context = this.getContext(); 6764dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen int vcardconfig = VCardConfig.VCARD_TYPE_DEFAULT; 6765fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if(uri.getBooleanQueryParameter( 6766fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, false)) { 6767dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen vcardconfig |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT; 6768dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen } 67697a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa final VCardComposer composer = 6770dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen new VCardComposer(context, vcardconfig, false); 6771108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Writer writer = null; 6772108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6773108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer = new BufferedWriter(new OutputStreamWriter(stream)); 6774fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (!composer.init(uri, selection, selectionArgs, null)) { 6775108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "Failed to init VCardComposer"); 6776108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa return; 6777108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6778d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6779108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa while (!composer.isAfterLast()) { 6780108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.write(composer.createOneEntry()); 6781108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6782108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6783108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.e(TAG, "IOException: " + e); 6784108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } finally { 6785108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa composer.terminate(); 6786108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa if (writer != null) { 6787108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6788108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.close(); 6789108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6790108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "IOException during closing output stream: " + e); 6791108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6792d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6793d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6794d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6795b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 67964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 67974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 6798415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6799415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov waitForAccess(mReadAccessLatch); 6800415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6801a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 68024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 6803b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS: 6804be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return Contacts.CONTENT_TYPE; 68052d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill case CONTACTS_LOOKUP: 6806b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_ID: 6807b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_LOOKUP_ID: 680824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 6809b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_ITEM_TYPE; 6810f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: 681142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: 681224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 6813f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey return Contacts.CONTENT_VCARD_TYPE; 6814f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov case CONTACTS_ID_PHOTO: 6815f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: 6816f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6817f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: 6818f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: 6819f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: 6820f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return "image/jpeg"; 6821b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS: 682224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 6823be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return RawContacts.CONTENT_TYPE; 6824b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS_ID: 682524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 6826b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return RawContacts.CONTENT_ITEM_TYPE; 6827f481f22a9323fe338672f99b88b26c5f0725cd42David Brown case DATA: 682824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 6829f481f22a9323fe338672f99b88b26c5f0725cd42David Brown return Data.CONTENT_TYPE; 6830508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 6831b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getDataMimeType(ContentUris.parseId(uri)); 683248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES: 683348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_TYPE; 683448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 683548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_ITEM_TYPE; 68369005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov case PHONE_LOOKUP: 68379005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov return PhoneLookup.CONTENT_TYPE; 683848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS: 683948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_TYPE; 684048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 684148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_ITEM_TYPE; 684248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS: 684348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_TYPE; 684448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: 684548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_ITEM_TYPE; 6846b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 6847b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_TYPE; 6848b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 6849b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_ITEM_TYPE; 6850b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case SETTINGS: 6851b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Settings.CONTENT_TYPE; 6852b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 6853b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_TYPE; 6854c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: 6855c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SUGGEST_MIME_TYPE; 6856c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: 6857c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SHORTCUT_MIME_TYPE; 6858d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES: 6859d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_TYPE; 6860d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID: 6861d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_ITEM_TYPE; 686261efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov default: 686361efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov return mLegacyApiSupport.getType(uri); 68644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 68654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 68667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 686709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov public String[] getDefaultProjection(Uri uri) { 686809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov final int match = sUriMatcher.match(uri); 686909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov switch (match) { 687009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS: 687109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP: 687209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_ID: 687309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP_ID: 687409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 687524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 687609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsProjectionMap.getColumnNames(); 687709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 68788727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov case CONTACTS_ID_ENTITIES: 687924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: 68808727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov return sEntityProjectionMap.getColumnNames(); 68818727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov 688209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_VCARD: 688309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_MULTI_VCARD: 688424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 688509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsVCardProjectionMap.getColumnNames(); 688609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 688709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS: 688809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS_ID: 688924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 689024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 689109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sRawContactsProjectionMap.getColumnNames(); 689209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 689309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DATA_ID: 689409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES: 689509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES_ID: 689609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS: 689709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS_ID: 689809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS: 689909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS_ID: 690024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 690109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDataProjectionMap.getColumnNames(); 690209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 690309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONE_LOOKUP: 690409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sPhoneLookupProjectionMap.getColumnNames(); 690509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 690609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 690709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 690809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sAggregationExceptionsProjectionMap.getColumnNames(); 690909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 691009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case SETTINGS: 691109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sSettingsProjectionMap.getColumnNames(); 691209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 691309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES: 691409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES_ID: 691509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDirectoryProjectionMap.getColumnNames(); 691609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 691709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov default: 691809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return null; 691909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 692009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 692109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 6922f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private class StructuredNameLookupBuilder extends NameLookupBuilder { 6923f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6924f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov public StructuredNameLookupBuilder(NameSplitter splitter) { 6925f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov super(splitter); 6926f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6927f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6928f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 6929f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected void insertNameLookup(long rawContactId, long dataId, int lookupType, 6930f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov String name) { 693178fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.insertNameLookup(rawContactId, dataId, lookupType, name); 6932f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6933f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6934f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 6935f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected String[] getCommonNicknameClusters(String normalizedName) { 6936d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); 6937f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6938f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6939f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 69402d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) { 6941d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov sb.append("(" + 6942d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov "SELECT DISTINCT " + RawContacts.CONTACT_ID + 6943d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 6944d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " JOIN " + Tables.NAME_LOOKUP + 6945d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " ON(" + RawContactsColumns.CONCRETE_ID + "=" 6946d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov + NameLookupColumns.RAW_CONTACT_ID + ")" + 6947d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " WHERE normalized_name GLOB '"); 6948e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(NameNormalizer.normalize(filterParam)); 6949916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov sb.append("*' AND " + NameLookupColumns.NAME_TYPE + 6950916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov " IN(" + CONTACT_LOOKUP_NAME_TYPES + "))"); 6951e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 6952e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 69539a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov public boolean isPhoneNumber(String filter) { 69549a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean atLeastOneDigit = false; 69559a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov int len = filter.length(); 69569a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov for (int i = 0; i < len; i++) { 69579a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov char c = filter.charAt(i); 69589a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (c >= '0' && c <= '9') { 69599a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov atLeastOneDigit = true; 69609a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } else if (c != '*' && c != '#' && c != '+' && c != 'N' && c != '.' && c != ';' 69619a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov && c != '-' && c != '(' && c != ')' && c != ' ') { 69629a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return false; 69639a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 69649a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 69659a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return atLeastOneDigit; 69669a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 69679a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 69684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** 69697a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * Takes components of a name from the query parameters and returns a cursor with those 69707a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * components as well as all missing components. There is no database activity involved 69717a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * in this so the call can be made on the UI thread. 69727a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov */ 69737a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private Cursor completeName(Uri uri, String[] projection) { 69747a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (projection == null) { 69757a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov projection = sDataProjectionMap.getColumnNames(); 69767a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 69777a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69787a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ContentValues values = new ContentValues(); 6979f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataRowHandlerForStructuredName handler = (DataRowHandlerForStructuredName) 6980f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov getDataRowHandler(StructuredName.CONTENT_ITEM_TYPE); 69817a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69827a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov copyQueryParamsToContentValues(values, uri, 69837a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.DISPLAY_NAME, 69847a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PREFIX, 69857a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.GIVEN_NAME, 69867a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.MIDDLE_NAME, 69877a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.FAMILY_NAME, 69887a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.SUFFIX, 69897a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_NAME, 69907a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_FAMILY_NAME, 69917a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_MIDDLE_NAME, 69927a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_GIVEN_NAME 69937a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ); 69947a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69957a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov handler.fixStructuredNameComponents(values, values); 69967a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69977a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 69987a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov Object[] row = new Object[projection.length]; 69997a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 70007a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov row[i] = values.get(projection[i]); 70017a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 70027a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov cursor.addRow(row); 70037a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return cursor; 70047a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 70057a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 70067a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private void copyQueryParamsToContentValues(ContentValues values, Uri uri, String... columns) { 70077a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (String column : columns) { 70087a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov String param = uri.getQueryParameter(column); 70097a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (param != null) { 70107a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov values.put(column, param); 70117a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 70127a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 70137a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 70147a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 70157a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 70167a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov /** 70174a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov * Inserts an argument at the beginning of the selection arg list. 70184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov */ 70194a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private String[] insertSelectionArg(String[] selectionArgs, String arg) { 7020b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 7021b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 7022b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 7023b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 7024b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 70254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov newSelectionArgs[0] = arg; 70264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length); 7027b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 7028b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 7029b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 7030caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 70315e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar private String[] appendProjectionArg(String[] projection, String arg) { 70325e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection == null) { 70335e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return null; 70345e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 70355e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar final int length = projection.length; 70365e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar String[] newProjection = new String[length + 1]; 70375e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar System.arraycopy(projection, 0, newProjection, 0, length); 70385e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar newProjection[length] = arg; 70395e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return newProjection; 70405e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 70415e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 7042caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov protected Account getDefaultAccount() { 7043caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov AccountManager accountManager = AccountManager.get(getContext()); 7044caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov try { 70455f1f4a062ac34d75d2dbf586702cbeb121cf09caDmitri Plotnikov Account[] accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE); 7046caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov if (accounts != null && accounts.length > 0) { 7047caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov return accounts[0]; 7048caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 7049caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } catch (Throwable e) { 70506f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov Log.e(TAG, "Cannot determine the default account for contacts compatibility", e); 7051caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 70526f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov return null; 7053caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 7054f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 705573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov /** 705643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Returns true if the specified account type and data set is writable. 705773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov */ 705843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro protected boolean isWritableAccountWithDataSet(String accountTypeAndDataSet) { 705943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (accountTypeAndDataSet == null) { 7060bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov return true; 7061bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov } 7062bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov 706343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Boolean writable = mAccountWritability.get(accountTypeAndDataSet); 706473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable != null) { 706573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 706673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 706773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 7068627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov IContentService contentService = ContentResolver.getContentService(); 7069627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 707043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO(dsantoro): Need to update this logic to allow for sub-accounts. 7071627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) { 7072627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov if (ContactsContract.AUTHORITY.equals(sync.authority) && 707343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountTypeAndDataSet.equals(sync.accountType)) { 707473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = sync.supportsUploading(); 707573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov break; 7076627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7077627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7078627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } catch (RemoteException e) { 7079627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov Log.e(TAG, "Could not acquire sync adapter types"); 7080627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 708173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 708273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable == null) { 708373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = false; 708473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 708573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 708643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mAccountWritability.put(accountTypeAndDataSet, writable); 708773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 7088627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7089b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov 7090d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 7091f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter, 7092f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean defaultValue) { 7093f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7094f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov // Manually parse the query, which is much faster than calling uri.getQueryParameter 7095f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 7096f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 7097f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 7098f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7099f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7100f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = query.indexOf(parameter); 7101f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 7102f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 7103f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7104f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7105f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameter.length(); 7106f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7107f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return !matchQueryParameter(query, index, "=0", false) 7108f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && !matchQueryParameter(query, index, "=false", true); 7109f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7110f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7111f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private static boolean matchQueryParameter(String query, int index, String value, 7112f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean ignoreCase) { 7113f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int length = value.length(); 7114f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return query.regionMatches(ignoreCase, index, value, 0, length) 7115f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && (query.length() == index + length || query.charAt(index + length) == '&'); 7116f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7117f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7118f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /** 7119f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * A fast re-implementation of {@link Uri#getQueryParameter} 7120f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov */ 7121f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static String getQueryParameter(Uri uri, String parameter) { 7122f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 7123f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 7124f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7125f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7126f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7127f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int queryLength = query.length(); 7128f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int parameterLength = parameter.length(); 7129f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7130f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String value; 7131f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = 0; 7132f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov while (true) { 7133f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index = query.indexOf(parameter, index); 7134f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 7135f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 71365fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 71375fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa 71385fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // Should match against the whole parameter instead of its suffix. 71395fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // e.g. The parameter "param" must not be found in "some_param=val". 71405fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (index > 0) { 71415fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa char prevChar = query.charAt(index - 1); 71425fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (prevChar != '?' && prevChar != '&') { 71435fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // With "some_param=val1¶m=val2", we should find second "param" occurrence. 71445fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa index += parameterLength; 71455fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa continue; 71465fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 7147f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7148f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7149f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameterLength; 7150f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7151f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (queryLength == index) { 7152f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7153f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7154f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7155f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query.charAt(index) == '=') { 7156f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index++; 7157f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov break; 7158f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7159f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7160f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7161f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int ampIndex = query.indexOf('&', index); 7162f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (ampIndex == -1) { 7163f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index); 7164f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } else { 7165f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index, ampIndex); 7166f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7167f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7168f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return Uri.decode(value); 7169f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 71705dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 71710dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov protected boolean isAggregationUpgradeNeeded() { 71720dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov if (!mContactAggregator.isEnabled()) { 71730dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return false; 71740dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 71750dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 71760dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_AGGREGATION_ALGORITHM, "1")); 71770dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return version < PROPERTY_AGGREGATION_ALGORITHM_VERSION; 71780dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 71790dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 7180bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void upgradeAggregationAlgorithmInBackground() { 71810dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // This upgrade will affect very few contacts, so it can be performed on the 71820dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // main thread during the initial boot after an OTA 71830dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 71840dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Upgrading aggregation algorithm"); 71850dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int count = 0; 71860dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long start = SystemClock.currentThreadTimeMillis(); 71870dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 718849d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov mDb = mDbHelper.getWritableDatabase(); 71890dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.beginTransaction(); 71900dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Cursor cursor = mDb.query(true, 71910dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Tables.RAW_CONTACTS + " r1 JOIN " + Tables.RAW_CONTACTS + " r2", 71920dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov new String[]{"r1." + RawContacts._ID}, 71930dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov "r1." + RawContacts._ID + "!=r2." + RawContacts._ID + 71940dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.CONTACT_ID + "=r2." + RawContacts.CONTACT_ID + 71950dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.ACCOUNT_NAME + "=r2." + RawContacts.ACCOUNT_NAME + 719643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND r1." + RawContacts.ACCOUNT_TYPE + "=r2." + RawContacts.ACCOUNT_TYPE + 719743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND r1." + RawContacts.DATA_SET + "=r2." + RawContacts.DATA_SET, 71980dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov null, null, null, null, null); 71990dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 72000dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov while (cursor.moveToNext()) { 72010dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long rawContactId = cursor.getLong(0); 72020dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, 72030dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 72040dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov count++; 72050dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 72060dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 72070dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov cursor.close(); 72080dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 7209bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateInTransaction(mTransactionContext, mDb); 7210bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 72110dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.setTransactionSuccessful(); 72120dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDbHelper.setProperty(PROPERTY_AGGREGATION_ALGORITHM, 72130dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov String.valueOf(PROPERTY_AGGREGATION_ALGORITHM_VERSION)); 72140dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 72150dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.endTransaction(); 72160dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long end = SystemClock.currentThreadTimeMillis(); 72170dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Aggregation algorithm upgraded for " + count 72180dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov + " contacts, in " + (end - start) + "ms"); 72190dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 72200dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 72219a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 72229a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov /* Visible for testing */ 72239a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean isPhone() { 72249a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (!sIsPhoneInitialized) { 72259a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhone = new TelephonyManager(getContext()).isVoiceCapable(); 72269a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhoneInitialized = true; 72279a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 72289a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return sIsPhone; 72299a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 723046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 723146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private boolean handleDataUsageFeedback(Uri uri) { 723246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final long currentTimeMillis = System.currentTimeMillis(); 723346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 723446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] ids = uri.getLastPathSegment().trim().split(","); 723546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ArrayList<Long> dataIds = new ArrayList<Long>(); 723646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 723746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (String id : ids) { 723846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa dataIds.add(Long.valueOf(id)); 723946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 724046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final boolean successful; 724146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (TextUtils.isEmpty(usageType)) { 724246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.w(TAG, "Method for data usage feedback isn't specified. Ignoring."); 724346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = false; 724446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 724546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = updateDataUsageStat(dataIds, usageType, currentTimeMillis) > 0; 724646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 724746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 724846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Handle old API. This doesn't affect the result of this entire method. 724946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] questionMarks = new String[ids.length]; 725046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Arrays.fill(questionMarks, "?"); 725146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = Data._ID + " IN (" + TextUtils.join(",", questionMarks) + ")"; 725246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final Cursor cursor = mDb.query( 7253ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA, 725446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { Data.CONTACT_ID }, 725546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa where, ids, null, null, null); 725646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 725746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa while (cursor.moveToNext()) { 725846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mSelectionArgs1[0] = cursor.getString(0); 725946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa ContentValues values2 = new ContentValues(); 726046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values2.put(Contacts.LAST_TIME_CONTACTED, currentTimeMillis); 726146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.update(Tables.CONTACTS, values2, Contacts._ID + "=?", mSelectionArgs1); 726246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 726346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 726446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 726546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 726646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 726746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 726846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 726946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return successful; 727046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 727146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 727246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 727346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Update {@link Tables#DATA_USAGE_STAT}. 727446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * 727546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @return the number of rows affected. 727646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 7277f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa @VisibleForTesting 7278f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa /* package */ int updateDataUsageStat( 7279f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa List<Long> dataIds, String type, long currentTimeMillis) { 728046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final int typeInt = sDataUsageTypeMap.get(type); 728146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = DataUsageStatColumns.DATA_ID + " =? AND " 728246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT + " =?"; 728346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] columns = 728446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { DataUsageStatColumns._ID, DataUsageStatColumns.TIMES_USED }; 728546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ContentValues values = new ContentValues(); 728646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (Long dataId : dataIds) { 728746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] args = new String[] { dataId.toString(), String.valueOf(typeInt) }; 728846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.beginTransaction(); 728946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 729046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final Cursor cursor = mDb.query(Tables.DATA_USAGE_STAT, columns, where, args, 729146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa null, null, null); 729246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 729346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (cursor.getCount() > 0) { 729446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!cursor.moveToFirst()) { 729546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.e(TAG, 729646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa "moveToFirst() failed while getAccount() returned non-zero."); 729746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 729846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 729946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, cursor.getInt(1) + 1); 730046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 730146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.update(Tables.DATA_USAGE_STAT, values, 730246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns._ID + " =?", 730346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { cursor.getString(0) }); 730446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 730546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 730646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 730746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.DATA_ID, dataId); 730846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.USAGE_TYPE_INT, typeInt); 730946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, 1); 731046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 731146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.insert(Tables.DATA_USAGE_STAT, null, values); 731246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 731346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.setTransactionSuccessful(); 731446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 731546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 731646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 731746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 731846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.endTransaction(); 731946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 732046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 732146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 732246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return dataIds.size(); 732346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 732446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 732546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 732646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Returns a sort order String for promoting data rows (email addresses, phone numbers, etc.) 732746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * associated with a primary account. The primary account should be supplied from applications 732846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * with {@link ContactsContract#PRIMARY_ACCOUNT_NAME} and 732946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * {@link ContactsContract#PRIMARY_ACCOUNT_TYPE}. Null will be returned when the primary 733046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * account isn't available. 733146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 733246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private String getAccountPromotionSortOrder(Uri uri) { 733346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountName = 733446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME); 733546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountType = 733646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE); 733746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 733846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Data rows associated with primary account should be promoted. 733946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountName)) { 734046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa StringBuilder sb = new StringBuilder(); 734146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append("(CASE WHEN " + RawContacts.ACCOUNT_NAME + "="); 734246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountName); 734346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountType)) { 734446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 734546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountType); 734646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 734746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" THEN 0 ELSE 1 END)"); 734846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return sb.toString(); 734946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 735046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return null; 735146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 735246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 73534f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 7354