ContactsProvider2.java revision 4928b8c8c7a49ec088884cd9d330eeecc811dca9
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; 145f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.FileDescriptor; 146f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.FileInputStream; 147b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException; 148f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.FileOutputStream; 149d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.IOException; 150d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.OutputStream; 151108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.OutputStreamWriter; 152108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.Writer; 15342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.text.SimpleDateFormat; 1547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList; 15546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawaimport java.util.Arrays; 1565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections; 15742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.util.Date; 158b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap; 1590e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.HashSet; 1605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List; 161622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkeyimport java.util.Locale; 162b5a4add17815167d20a90645779df34cdf45280dFred Quintanaimport java.util.Map; 1630e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.Set; 164ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch; 1654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/** 1674f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications 1684f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}. 1694f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 1705b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanapublic class ContactsProvider2 extends SQLiteContentProvider implements OnAccountsUpdateListener { 171caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 172bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov private static final String TAG = "ContactsProvider"; 173bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov 174bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE); 1754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 17615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_INITIALIZE = 0; 17715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_OPEN_WRITE_ACCESS = 1; 17815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS = 2; 17915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_ACCOUNTS = 3; 18015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_LOCALE = 4; 18115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM = 5; 18205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_SEARCH_INDEX = 6; 18305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_PROVIDER_STATUS = 7; 18405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_DIRECTORIES = 8; 18505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_CHANGE_LOCALE = 9; 186f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int BACKGROUND_TASK_CLEANUP_PHOTOS = 10; 187619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** Default for the maximum number of returned aggregation suggestions. */ 1893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DEFAULT_MAX_SUGGESTIONS = 5; 1903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 1913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Limit for the maximum number of social stream items to store under a raw contact. */ 1923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int MAX_STREAM_ITEMS_PER_RAW_CONTACT = 5; 1933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 194f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Rate limit (in ms) for photo cleanup. Do it at most once per day. */ 195f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_CLEANUP_RATE_LIMIT = 24 * 60 * 60 * 1000; 196f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1973d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /** 198b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov * Property key for the legacy contact import version. The need for a version 1993d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov * as opposed to a boolean flag is that if we discover bugs in the contact import process, 2003d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov * we can trigger re-import by incrementing the import version. 2013d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov */ 202b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov private static final String PROPERTY_CONTACTS_IMPORTED = "contacts_imported_v1"; 203b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov private static final int PROPERTY_CONTACTS_IMPORT_VERSION = 1; 20451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov private static final String PREF_LOCALE = "locale"; 2053d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2060dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final String PROPERTY_AGGREGATION_ALGORITHM = "aggregation_v2"; 2070dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final int PROPERTY_AGGREGATION_ALGORITHM_VERSION = 2; 2080dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 2090e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate"; 2100e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff 211a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 2124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2132f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 2142f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * Used to insert a column into strequent results, which enables SQL to sort the list using 2152f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * the total times contacted. See also {@link #sStrequentFrequentProjectionMap}. 2162f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 2172f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private static final String TIMES_USED_SORT_COLUMN = "times_used_sort"; 2185e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 219d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, " 2202f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa + TIMES_USED_SORT_COLUMN + " DESC, " 2219b43551f1ce33b79141772737a262ce609bd0cebMegha Joshi + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 222d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final String STREQUENT_LIMIT = 223d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE " 224d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov + Contacts.STARRED + "=1) + 25"; 225d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov 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; 2654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2665ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS = 2002; 2675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_ID = 2003; 2685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_DATA = 2004; 26946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITY_ID = 2005; 270f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_DISPLAY_PHOTO = 2006; 271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS = 2007; 2724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2736bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 2746bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 275ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 27648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_ID = 3003; 27748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_FILTER = 3004; 27848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS = 3005; 27948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_ID = 3006; 28048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_LOOKUP = 3007; 28148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_FILTER = 3008; 28248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS = 3009; 28348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS_ID = 3010; 284a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2856bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 2866bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 287b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 288b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 289b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 29082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES = 7000; 29182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES_ID = 7001; 2921f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 29331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 29431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 295eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey private static final int SETTINGS = 9000; 296eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 297ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 298ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 299ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 300ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 30135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 302b5a4add17815167d20a90645779df34cdf45280dFred Quintana private static final int SYNCSTATE_ID = 11001; 30335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 304c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SUGGESTIONS = 12001; 305c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SHORTCUT = 12002; 306c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 3071b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS = 14000; 3081b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001; 3091b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002; 3101b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003; 3111b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 31246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITIES = 15001; 31346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 31409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private static final int PROVIDER_STATUS = 16001; 31509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 316d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES = 17001; 317d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES_ID = 17002; 318d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 3197a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private static final int COMPLETE_NAME = 18000; 3207a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 32124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE = 19000; 32224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_ENTITIES = 19001; 32324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA = 19002; 32424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA_ID = 19003; 32524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_AS_VCARD = 19004; 32624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS = 19005; 32724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID = 19006; 32824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_DATA = 19007; 32924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_ENTITIES = 19008; 33024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 33146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final int DATA_USAGE_FEEDBACK_ID = 20001; 33246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 3333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS = 21000; 3343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_PHOTOS = 21001; 3353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID = 21002; 3363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS = 21003; 3373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS_ID = 21004; 3383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_LIMIT = 21005; 3393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 340f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int DISPLAY_PHOTO = 22000; 341f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_DIMENSIONS = 22001; 342f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 343dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID = 344dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 345dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME 346dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "=" + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 347dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE 348dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "=" + RawContactsColumns.CONCRETE_ACCOUNT_TYPE 349dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND " + Groups.FAVORITES + " != 0"; 350dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 351dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID = 352dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 353dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 354dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 355dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 356dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND " 357dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + Groups.AUTO_ADD + " != 0"; 358dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 359dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String[] PROJECTION_GROUP_ID 360dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana = new String[]{Tables.GROUPS + "." + Groups._ID}; 361dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 362dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_GROUPMEMBERSHIP_DATA = DataColumns.MIMETYPE_ID + "=? " 363dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.GROUP_ROW_ID + "=? " 364dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.RAW_CONTACT_ID + "=?"; 365dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 366dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_STARRED_FROM_RAW_CONTACTS = 367dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana "SELECT " + RawContacts.STARRED 368dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " FROM " + Tables.RAW_CONTACTS + " WHERE " + RawContacts._ID + "=?"; 369dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 370e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public class AddressBookCursor extends CursorWrapper implements CrossProcessCursor { 371e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov private final CrossProcessCursor mCursor; 372e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov private final Bundle mBundle; 373e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 374e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public AddressBookCursor(CrossProcessCursor cursor, String[] titles, int[] counts) { 375e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov super(cursor); 376e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mCursor = cursor; 377e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle = new Bundle(); 378e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle.putStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES, titles); 379e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle.putIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, counts); 380e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 381e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 382e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 383e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public Bundle getExtras() { 384e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mBundle; 385e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 386e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 387e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 388e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public void fillWindow(int pos, CursorWindow window) { 389e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mCursor.fillWindow(pos, window); 390e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 391e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 392e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 393e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public CursorWindow getWindow() { 394e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mCursor.getWindow(); 395e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 396e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 397e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 398e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public boolean onMove(int oldPosition, int newPosition) { 399e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mCursor.onMove(oldPosition, newPosition); 400e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 401e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 402e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 403d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private interface DataContactsQuery { 404f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov public static final String TABLE = "data " 405f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) " 406f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)"; 40767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 40867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 4096cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov RawContactsColumns.CONCRETE_ID, 4106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_TYPE, 4116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_NAME, 4123cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 413f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov ContactsColumns.CONCRETE_ID 414ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 415ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 416d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov public static final int RAW_CONTACT_ID = 0; 4176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_TYPE = 1; 4186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_NAME = 2; 4196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int DATA_ID = 3; 4206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int CONTACT_ID = 4; 421ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 4221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 423f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov interface RawContactsQuery { 42419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String TABLE = Tables.RAW_CONTACTS; 42519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 42619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String[] COLUMNS = new String[] { 427ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.DELETED, 428ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 429ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_NAME, 43019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka }; 43119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 43219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int DELETED = 0; 433ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_TYPE = 1; 434ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_NAME = 2; 43519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 43619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 437c76cdd0723b99f478c9ba5329d14a971cd8dfb3dCostin Manolache public static final String DEFAULT_ACCOUNT_TYPE = "com.google"; 438caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 43971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov /** Sql where statement for filtering on groups. */ 44071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov private static final String CONTACTS_IN_GROUP_SELECT = 44171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov Contacts._ID + " IN " 44271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + RawContacts.CONTACT_ID 44371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.RAW_CONTACTS 44471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN " 44571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 44671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.DATA_JOIN_MIMETYPES 44771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 44871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 44971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + Tables.GROUPS + "." + Groups._ID 45071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.GROUPS 45171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Groups.TITLE + "=?)))"; 45271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov 453a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating DIRTY flag on multiple raw contacts */ 454a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_DIRTY_SQL = 455a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 456a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.DIRTY + "=1" + 457a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 458a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 459a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating VERSION on multiple raw contacts */ 460a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL = 461a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 462a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.VERSION + " = " + RawContacts.VERSION + " + 1" + 463a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 464a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 465c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Current contacts - those contacted within the last 3 days (in seconds) 466c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_CURRENT = 3 * 24 * 60 * 60; 467c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 468c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Recent contacts - those contacted within the last 30 days (in seconds) 469c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_RECENT = 30 * 24 * 60 * 60; 470c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 471f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa private static final String TIME_SINCE_LAST_USED = 472f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa "(strftime('%s', 'now') - " + DataUsageStatColumns.LAST_TIME_USED + "/1000)"; 473f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa 474c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov /* 475c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * Sorting order for email address suggestions: first starred, then the rest. 4762262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * second in_visible_group, then the rest. 4772262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * Within the four (starred/unstarred, in_visible_group/not-in_visible_group) groups 4782262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * - three buckets: very recently contacted, then fairly 479c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * recently contacted, then the rest. Within each of the bucket - descending count 48046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * of times contacted (both for data row and for contact row). If all else fails, alphabetical. 48146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * (Super)primary email address is returned before other addresses for the same contact. 482c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov */ 483c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final String EMAIL_FILTER_SORT_ORDER = 4842262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa Contacts.STARRED + " DESC, " 4852262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa + Contacts.IN_VISIBLE_GROUP + " DESC, " 486f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + "(CASE WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_CURRENT 48746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 0 " 488f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + " WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_RECENT 48946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 1 " 49046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " ELSE 2 END), " 49146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.TIMES_USED + " DESC, " 49246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Contacts.DISPLAY_NAME + ", " 49346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Data.CONTACT_ID + ", " 494c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_SUPER_PRIMARY + " DESC, " 495c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_PRIMARY + " DESC"; 49646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 49746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** Currently same as {@link #EMAIL_FILTER_SORT_ORDER} */ 49846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final String PHONE_FILTER_SORT_ORDER = EMAIL_FILTER_SORT_ORDER; 499c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 500916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Name lookup types used for contact filtering */ 501916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private static final String CONTACT_LOOKUP_NAME_TYPES = 502916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.NAME_COLLATION_KEY + "," + 503916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.EMAIL_BASED_NICKNAME + "," + 50492ddc5cdc4d89ee2c6e861ae7b3a3a913ffa0100Dmitri Plotnikov NameLookupType.NICKNAME; 505916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 506f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov /** 507f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * If any of these columns are used in a Data projection, there is no point in 508f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * using the DISTINCT keyword, which can negatively affect performance. 509f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov */ 510f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov private static final String[] DISTINCT_DATA_PROHIBITING_COLUMNS = { 511f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data._ID, 512f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.RAW_CONTACT_ID, 513f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.NAME_RAW_CONTACT_ID, 514f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 515f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 516f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.DIRTY, 517f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.NAME_VERIFIED, 518f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.SOURCE_ID, 519f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.VERSION, 520f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov }; 521916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 522f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsColumns = ProjectionMap.builder() 523f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CUSTOM_RINGTONE) 524f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME) 525f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_ALTERNATIVE) 526f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_SOURCE) 527f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.IN_VISIBLE_GROUP) 528f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LAST_TIME_CONTACTED) 529f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LOOKUP_KEY) 530f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME) 531f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME_STYLE) 532f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHOTO_ID) 533f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .add(Contacts.PHOTO_FILE_ID) 5343d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_URI) 5353d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_THUMBNAIL_URI) 536f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SEND_TO_VOICEMAIL) 537f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_ALTERNATIVE) 538f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_PRIMARY) 539f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.STARRED) 540f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.TIMES_CONTACTED) 541cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 542f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 543f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 544f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsPresenceColumns = ProjectionMap.builder() 545f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 546f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE) 547f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 548f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 549f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 550f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 551f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 552f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 553f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 554f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 555f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 556f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 557f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 558f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 559f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 560f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 561f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSnippetColumns = ProjectionMap.builder() 56203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov .add(SearchSnippetColumns.SNIPPET) 563f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 564f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 565f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactColumns = ProjectionMap.builder() 566f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_NAME) 567f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_TYPE) 568f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DIRTY) 569f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.NAME_VERIFIED) 570f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SOURCE_ID) 571f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.VERSION) 572f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 573f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 574f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactSyncColumns = ProjectionMap.builder() 575f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC1) 576f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC2) 577f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC3) 578f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC4) 579f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 580f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 581f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataColumns = ProjectionMap.builder() 582f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA1) 583f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA2) 584f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA3) 585f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA4) 586f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA5) 587f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA6) 588f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA7) 589f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA8) 590f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA9) 591f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA10) 592f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA11) 593f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA12) 594f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA13) 595f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA14) 596f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA15) 597f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA_VERSION) 598f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_PRIMARY) 599f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_SUPER_PRIMARY) 600f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.MIMETYPE) 601f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RES_PACKAGE) 602f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC1) 603f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC2) 604f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC3) 605f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC4) 606f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(GroupMembership.GROUP_SOURCE_ID) 607f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 608f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 609f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactPresenceColumns = ProjectionMap.builder() 610f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 611f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.PRESENCE) 612f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 613f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.CHAT_CAPABILITY) 614f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 615f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 616f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 617f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 618f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 619f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 620f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 621f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 622f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 623f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 624f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 625f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 626f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataPresenceColumns = ProjectionMap.builder() 627f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.PRESENCE, Tables.PRESENCE + "." + StatusUpdates.PRESENCE) 628f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CHAT_CAPABILITY, Tables.PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 629f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS, StatusUpdatesColumns.CONCRETE_STATUS) 630f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_TIMESTAMP, StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 631f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_RES_PACKAGE, StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 632f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_LABEL, StatusUpdatesColumns.CONCRETE_STATUS_LABEL) 633f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_ICON, StatusUpdatesColumns.CONCRETE_STATUS_ICON) 634f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 635f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 636038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana /** Contains just BaseColumns._COUNT */ 637f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sCountProjectionMap = ProjectionMap.builder() 638f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(BaseColumns._COUNT, "COUNT(*)") 639f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 640f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 641e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov /** Contains just the contacts columns */ 642f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionMap = ProjectionMap.builder() 643f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts._ID) 644f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 645f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.NAME_RAW_CONTACT_ID) 64624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 647f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 648f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsPresenceColumns) 649f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 650f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 651916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Contains just the contacts columns */ 652f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionWithSnippetMap = ProjectionMap.builder() 653f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 654f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sSnippetColumns) 655f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 656916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6575e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar /** Used for pushing starred contacts to the top of a times contacted list **/ 658f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentStarredProjectionMap = ProjectionMap.builder() 659f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 6602f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 661f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 662f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 663f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder() 664f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 6652f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, "SUM(" + DataUsageStatColumns.CONCRETE_TIMES_USED + ")") 666f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 667f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 6684928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 6694928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 6704928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. Right now Starred part just returns NULL for 6714928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * those data columns (frequent part should return real ones in data table). 6724928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 6734928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyStarredProjectionMap 6744928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 6754928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 6764928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 6774928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER, "NULL") 6784928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE, "NULL") 6794928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL, "NULL") 6804928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 6814928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 6824928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 6834928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 6844928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. We hard-code {@link Contacts#IS_USER_PROFILE} to NULL, 6854928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * because sContactsProjectionMap specifies a field that doesn't exist in the view behind the 6864928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * query that uses this projection map. 6874928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 6884928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyFrequentProjectionMap 6894928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 6904928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 6914928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, DataUsageStatColumns.CONCRETE_TIMES_USED) 6924928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER) 6934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE) 6944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL) 6954928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Contacts.IS_USER_PROFILE, "NULL") 6964928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 6974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 698f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey /** Contains just the contacts vCard columns */ 699f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsVCardProjectionMap = ProjectionMap.builder() 700fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen .add(Contacts._ID) 701f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME + " || '.vcf'") 702f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.SIZE, "NULL") 703f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 704f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 705ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov /** Contains just the raw contacts columns */ 706f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactsProjectionMap = ProjectionMap.builder() 707f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 708f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 709f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 710f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_PRIMARY) 711f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_ALTERNATIVE) 712f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_SOURCE) 713f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME) 714f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME_STYLE) 715f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_PRIMARY) 716f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_ALTERNATIVE) 717f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.TIMES_CONTACTED) 718f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.LAST_TIME_CONTACTED) 719f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CUSTOM_RINGTONE) 720f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SEND_TO_VOICEMAIL) 721f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 722f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.AGGREGATION_MODE) 72324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 724f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 725f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 726f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 727f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 728a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the raw entity view*/ 729f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawEntityProjectionMap = ProjectionMap.builder() 730f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 731f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 732f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.Entity.DATA_ID) 733f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 734f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 73524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 736f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 737f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 738f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 739f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 740f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 741a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the contact entity view*/ 742f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sEntityProjectionMap = ProjectionMap.builder() 743f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity._ID) 744f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.CONTACT_ID) 745f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.RAW_CONTACT_ID) 746f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DATA_ID) 747f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.NAME_RAW_CONTACT_ID) 748f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DELETED) 74924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 750f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 751f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 752f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 753f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 754f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 755f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 756f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 757f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** Contains columns from the data view */ 759f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataProjectionMap = ProjectionMap.builder() 760f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID) 761f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RAW_CONTACT_ID) 762f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CONTACT_ID) 763f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.NAME_RAW_CONTACT_ID) 76424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 765f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 766f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 767f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 768f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 769f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 770f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 771f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7725e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov /** Contains columns from the data view */ 773f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDistinctDataProjectionMap = ProjectionMap.builder() 774f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID, "MIN(" + Data._ID + ")") 775f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 77624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 777f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 778f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 779f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 780f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 781f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 782f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7839261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data and contacts columns, for joined tables */ 784f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sPhoneLookupProjectionMap = ProjectionMap.builder() 785f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup._ID, "contacts_view." + Contacts._ID) 786f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LOOKUP_KEY, "contacts_view." + Contacts.LOOKUP_KEY) 787f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.DISPLAY_NAME, "contacts_view." + Contacts.DISPLAY_NAME) 788f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LAST_TIME_CONTACTED, "contacts_view." + Contacts.LAST_TIME_CONTACTED) 789f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TIMES_CONTACTED, "contacts_view." + Contacts.TIMES_CONTACTED) 790f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.STARRED, "contacts_view." + Contacts.STARRED) 791f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.IN_VISIBLE_GROUP, "contacts_view." + Contacts.IN_VISIBLE_GROUP) 792f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.PHOTO_ID, "contacts_view." + Contacts.PHOTO_ID) 7933d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_URI, "contacts_view." + Contacts.PHOTO_URI) 7943d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_THUMBNAIL_URI, "contacts_view." + Contacts.PHOTO_THUMBNAIL_URI) 795f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.CUSTOM_RINGTONE, "contacts_view." + Contacts.CUSTOM_RINGTONE) 796f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.HAS_PHONE_NUMBER, "contacts_view." + Contacts.HAS_PHONE_NUMBER) 797f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.SEND_TO_VOICEMAIL, "contacts_view." + Contacts.SEND_TO_VOICEMAIL) 798f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.NUMBER, Phone.NUMBER) 799f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TYPE, Phone.TYPE) 800f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LABEL, Phone.LABEL) 8012530512f639c4979fd7371c7dd25dd67e8118124Bai Tao .add(PhoneLookup.NORMALIZED_NUMBER, Phone.NORMALIZED_NUMBER) 802f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 803f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 804ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 805f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsProjectionMap = ProjectionMap.builder() 806f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups._ID) 807f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_NAME) 808f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_TYPE) 809f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SOURCE_ID) 810f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DIRTY) 811f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.VERSION) 812f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.RES_PACKAGE) 813f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE) 814f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE_RES) 815f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.GROUP_VISIBLE) 816f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYSTEM_ID) 817f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DELETED) 818f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.NOTES) 8191cdfc9dacc136e99d3c0bc5b4212bc3c973be337Daniel Lehmann .add(Groups.ACTION) 8201cdfc9dacc136e99d3c0bc5b4212bc3c973be337Daniel Lehmann .add(Groups.ACTION_URI) 821f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SHOULD_SYNC) 822f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.FAVORITES) 823f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.AUTO_ADD) 824c039cfb78c40730483fd71178df63ada5826a315Dmitri Plotnikov .add(Groups.GROUP_IS_READ_ONLY) 825f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC1) 826f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC2) 827f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC3) 828f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC4) 829f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 830f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 831ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains {@link Groups} columns along with summary details */ 832f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsSummaryProjectionMap = ProjectionMap.builder() 833f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sGroupsProjectionMap) 834f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_COUNT, 835f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID 836f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS 837f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP 838f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + Clauses.BELONGS_TO_GROUP 839f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ")") 840f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_WITH_PHONES, 841f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID 842f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS 843f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP 844f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + Clauses.BELONGS_TO_GROUP 845f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + Contacts.HAS_PHONE_NUMBER + ")") 846f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 847f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 848373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov /** Contains the agg_exceptions columns */ 849f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sAggregationExceptionsProjectionMap = ProjectionMap.builder() 850f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id") 851f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.TYPE) 852f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID1) 853f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID2) 854f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 855f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 856eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey /** Contains the agg_exceptions columns */ 857f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSettingsProjectionMap = ProjectionMap.builder() 858f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_NAME) 859f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_TYPE) 860f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_VISIBLE) 861f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.SHOULD_SYNC) 862f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ANY_UNSYNCED, 863f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN MIN(" + Settings.SHOULD_SYNC 864f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ",(SELECT " 865f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "(CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL" 866f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 867f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE MIN(" + Groups.SHOULD_SYNC + ")" 868f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)" 869f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.GROUPS 870f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 871f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_NAME 872f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 873f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_TYPE + "))=0" 874f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 875f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE 0" 876f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)") 877f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_COUNT, 878f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 879f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 880f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 881f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 882f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 883f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 884f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_WITH_PHONES, 885f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 886f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 887f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 888f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Contacts.HAS_PHONE_NUMBER 889f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 890f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 891f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 892f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 893f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 89482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov /** Contains StatusUpdates columns */ 895f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStatusUpdatesProjectionMap = ProjectionMap.builder() 896f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PresenceColumns.RAW_CONTACT_ID) 897f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.DATA_ID, DataColumns.CONCRETE_ID) 898f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_ACCOUNT) 899f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_HANDLE) 900f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PROTOCOL) 901f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 902f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // properly enforce uniqueness of null values 903f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CUSTOM_PROTOCOL, 904f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL + "=''" 905f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN NULL" 906f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END)") 907f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PRESENCE) 908f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CHAT_CAPABILITY) 909f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS) 910f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_TIMESTAMP) 911f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_RES_PACKAGE) 912f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_ICON) 913f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_LABEL) 914f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 915f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 9163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Contains StreamItems columns */ 9173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemsProjectionMap = ProjectionMap.builder() 9183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems._ID, StreamItemsColumns.CONCRETE_ID) 9193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(RawContacts.CONTACT_ID) 9203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_PACKAGE) 9223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_ICON) 9233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_LABEL) 9243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TEXT) 9253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TIMESTAMP) 9263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.COMMENTS) 9273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.ACTION) 9283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.ACTION_URI) 9293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemPhotosProjectionMap = ProjectionMap.builder() 9323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos._ID, StreamItemPhotosColumns.CONCRETE_ID) 9333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.STREAM_ITEM_ID) 9353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.SORT_INDEX) 9366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_FILE_ID) 9376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_URI, 9386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro "'" + DisplayPhoto.CONTENT_URI + "'||'/'||" + StreamItemPhotos.PHOTO_FILE_ID) 9393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.ACTION, StreamItemPhotosColumns.CONCRETE_ACTION) 9403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.ACTION_URI, StreamItemPhotosColumns.CONCRETE_ACTION_URI) 9411dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.HEIGHT) 9421dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.WIDTH) 9431dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.FILESIZE) 9443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9461b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov /** Contains Live Folders columns */ 947f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sLiveFoldersProjectionMap = ProjectionMap.builder() 948f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders._ID, Contacts._ID) 949f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders.NAME, Contacts.DISPLAY_NAME) 950f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // TODO: Put contact photo back when we have a way to display a default icon 951f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // for contacts without a photo 952f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // .add(LiveFolders.ICON_BITMAP, Photos.DATA) 953f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 954f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 955d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** Contains {@link Directory} columns */ 956f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDirectoryProjectionMap = ProjectionMap.builder() 957f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory._ID) 958f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.PACKAGE_NAME) 959f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.TYPE_RESOURCE_ID) 960f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DISPLAY_NAME) 961f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DIRECTORY_AUTHORITY) 962f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_TYPE) 963f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_NAME) 964f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.EXPORT_SUPPORT) 965778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.SHORTCUT_SUPPORT) 966778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.PHOTO_SUPPORT) 967f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 9687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 9699705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // where clause to update the status_updates table 9709705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE = 9719705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID + 9729705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE + 9739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE "; 9749705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 9752526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private static final String[] EMPTY_STRING_ARRAY = new String[0]; 9762526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 977bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 978bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Notification ID for failure to import contacts. 979bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 980bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private static final int LEGACY_IMPORT_FAILED_NOTIFICATION = 1; 98151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 98203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_START_MATCH = "["; 98303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_END_MATCH = "]"; 98403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_ELLIPSIS = "..."; 98503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final int DEFAULT_SNIPPET_ARG_MAX_TOKENS = -10; 98603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 9879a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhoneInitialized; 9889a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhone; 9899a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 990f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov private StringBuilder mSb = new StringBuilder(); 9911129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs1 = new String[1]; 9921129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs2 = new String[2]; 9932526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private ArrayList<String> mSelectionArgs = Lists.newArrayList(); 9942526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 995f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private Account mAccount; 996f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 99746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 99846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Stores mapping from type Strings exposed via {@link DataUsageFeedback} to 99946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type integers in {@link DataUsageStatColumns}. 100046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 100146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final Map<String, Integer> sDataUsageTypeMap; 100246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 10034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 10044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 1005a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 1006d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 1007d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 1008a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA); 1009a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES); 10103653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", 10113653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 10122d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", 10132d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov AGGREGATION_SUGGESTIONS); 1014a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO); 1015f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", 1016f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_ID_DISPLAY_PHOTO); 10173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", 10183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_ID_STREAM_ITEMS); 1019c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER); 10205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER); 10215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP); 10222149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA); 10235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID); 10242149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", 10252149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov CONTACTS_LOOKUP_ID_DATA); 1026f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", 1027f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_DISPLAY_PHOTO); 1028f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo", 1029f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_ID_DISPLAY_PHOTO); 1030a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities", 1031a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ENTITIES); 1032a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities", 1033a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ID_ENTITIES); 10343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items", 10353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_STREAM_ITEMS); 10363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items", 10373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_ID_STREAM_ITEMS); 1038f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD); 103942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*", 104042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann CONTACTS_AS_MULTI_VCARD); 10415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT); 1042ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*", 1043ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov CONTACTS_STREQUENT_FILTER); 10445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP); 10453653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 10465ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); 10475ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); 10485ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA); 1049f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/display_photo", 1050f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro RAW_CONTACTS_ID_DISPLAY_PHOTO); 105146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ENTITY_ID); 10523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items", 10533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RAW_CONTACTS_ID_STREAM_ITEMS); 105446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 105546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES); 1056b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 10574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 10584f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 1059ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 106048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID); 10615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER); 1062ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 10634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS); 106448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID); 10651dac83b8fa58944acfd00f44e717a7dddc659d2dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP); 10665e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP); 10675e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER); 10684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER); 1069ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 107048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID); 107146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** "*" is in CSV form with data ids ("123,456,789") */ 107246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/usagefeedback/*", DATA_USAGE_FEEDBACK_ID); 10731f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1074ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 1075ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 1076ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 1077ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 107835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 1079b5a4add17815167d20a90645779df34cdf45280dFred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#", 1080b5a4add17815167d20a90645779df34cdf45280dFred Quintana SYNCSTATE_ID); 108135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1082a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 1083b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 1084b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 1085b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 1086b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 10874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1088eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS); 1089eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 109082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES); 109182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID); 10921f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1093c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, 1094c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 1095c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 1096c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 10972d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 1098c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SHORTCUT); 1099c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 11001b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts", 11011b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS); 11021b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*", 11031b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_GROUP_NAME); 11041b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones", 11051b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_WITH_PHONES); 11061b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites", 11071b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_FAVORITES); 110809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 110909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS); 1110d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1111d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES); 1112d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID); 11137a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 11147a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME); 111524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 111624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile", PROFILE); 111724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/entities", PROFILE_ENTITIES); 111824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data", PROFILE_DATA); 111924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data/#", PROFILE_DATA_ID); 112024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/as_vcard", PROFILE_AS_VCARD); 112124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts", PROFILE_RAW_CONTACTS); 112224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#", 112324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID); 112424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/data", 112524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_DATA); 112624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/entity", 112724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_ENTITIES); 112846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 11293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items", STREAM_ITEMS); 11303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/photo", STREAM_ITEMS_PHOTOS); 11313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#", STREAM_ITEMS_ID); 11323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo", STREAM_ITEMS_ID_PHOTOS); 11333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo/#", 11343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann STREAM_ITEMS_ID_PHOTOS_ID); 11353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items_limit", STREAM_ITEMS_LIMIT); 11363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 1137f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "display_photo/*", DISPLAY_PHOTO); 1138f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS); 1139f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 114046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa HashMap<String, Integer> tmpTypeMap = new HashMap<String, Integer>(); 114146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_CALL, DataUsageStatColumns.USAGE_TYPE_INT_CALL); 114246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, 114346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT); 114446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, 114546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT); 114646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sDataUsageTypeMap = Collections.unmodifiableMap(tmpTypeMap); 114719a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov } 114819a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov 1149d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static class DirectoryInfo { 1150d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String authority; 1151d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountName; 1152d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountType; 1153d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 1154d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1155d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 1156d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Cached information about contact directories. 1157d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 11584458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private HashMap<String, DirectoryInfo> mDirectoryCache = new HashMap<String, DirectoryInfo>(); 11594458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private boolean mDirectoryCacheValid = false; 1160d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 11613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 1162ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov * An entry in group id cache. It maps the combination of (account type, account name 1163ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov * and source id) to group row id. 1164ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov */ 1165e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov public static class GroupIdCacheEntry { 1166ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType; 1167ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName; 1168ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String sourceId; 1169ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov long groupId; 1170ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov } 1171a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov 1172e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // We don't need a soft cache for groups - the assumption is that there will only 1173e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // be a small number of contact groups. The cache is keyed off source id. The value 1174e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // is a list of groups with this group id. 1175e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap(); 1176e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov 117724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 117824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Cached information about the contact ID and raw contact IDs that make up the user's 117924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile entry. 118024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 118124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static class ProfileIdCache { 118224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean inited; 118324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long profileContactId; 118424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Set<Long> profileRawContactIds = Sets.newHashSet(); 118524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Set<Long> profileDataIds = Sets.newHashSet(); 118624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 118724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 118824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Initializes the cache of profile contact and raw contact IDs. Does nothing if 118924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * the cache is already initialized (unless forceRefresh is set to true). 119024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param db The contacts database. 119124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forceRefresh Whether to force re-initialization of the cache. 119224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 119324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void init(SQLiteDatabase db, boolean forceRefresh) { 119424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!inited || forceRefresh) { 119524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileContactId = 0; 119624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactIds.clear(); 119724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileDataIds.clear(); 119824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Cursor c = db.rawQuery("SELECT " + 119924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_CONTACT_ID + "," + 120024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "," + 120124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro DataColumns.CONCRETE_ID + 120224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro " FROM " + Tables.RAW_CONTACTS + " JOIN " + Tables.ACCOUNTS + " ON " + 120324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "=" + 120424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro AccountsColumns.PROFILE_RAW_CONTACT_ID + 120524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro " JOIN " + Tables.DATA + " ON " + 120624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "=" + DataColumns.CONCRETE_RAW_CONTACT_ID, 120724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro null); 120824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro try { 120924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro while (c.moveToNext()) { 121024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (profileContactId == 0) { 121124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileContactId = c.getLong(0); 121224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 121324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactIds.add(c.getLong(1)); 121424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileDataIds.add(c.getLong(2)); 121524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 121624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } finally { 121724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro c.close(); 121824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 121924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 122024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 122124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 122224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 122324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private ProfileIdCache mProfileIdCache; 122424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1225f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1226f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of display photos. Larger images will be scaled 1227f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to fit. 1228f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1229f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxDisplayPhotoDim; 1230f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1231f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1232f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of photo thumbnails. 1233f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1234f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxThumbnailPhotoDim; 1235f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12363cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private HashMap<String, DataRowHandler> mDataRowHandlers; 1237b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private ContactsDatabaseHelper mDbHelper; 123831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1239f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private PhotoStore mPhotoStore; 1240f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12414097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 1242f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private NameLookupBuilder mNameLookupBuilder; 1243315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov 1244622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private PostalSplitter mPostalSplitter; 1245622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey 124672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov private ContactDirectoryManager mContactDirectoryManager; 1247622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private ContactAggregator mContactAggregator; 1248f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 1249a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private GlobalSearchSupport mGlobalSearchSupport; 1250d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov private CommonNicknameCache mCommonNicknameCache; 1251f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov private SearchIndexManager mSearchIndexManager; 1252a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 125320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private ContentValues mValues = new ContentValues(); 125473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov private HashMap<String, Boolean> mAccountWritability = Maps.newHashMap(); 125520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 125609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private int mProviderStatus = ProviderStatus.STATUS_NORMAL; 12573826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private boolean mProviderStatusUpdateNeeded; 125809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private long mEstimatedStorageRequirement = 0; 125915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mReadAccessLatch; 126015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mWriteAccessLatch; 126115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private boolean mAccountUpdateListenerRegistered; 1262bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private boolean mOkToOpenAccess = true; 126373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 1264d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private TransactionContext mTransactionContext = new TransactionContext(); 1265de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov 12661a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey private boolean mVisibleTouched = false; 12671a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 126881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov private boolean mSyncToNetwork; 126981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 12704cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao private Locale mCurrentLocale; 12713826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private int mContactsAccountCount; 1272d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov 1273bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private HandlerThread mBackgroundThread; 1274bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private Handler mBackgroundHandler; 1275bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1276f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mLastPhotoCleanup = 0; 1277f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 12794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 1280de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov super.onCreate(); 1281ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov try { 1282ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return initialize(); 1283ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } catch (RuntimeException e) { 1284ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov Log.e(TAG, "Cannot start provider", e); 1285ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return false; 1286ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 1287ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 128835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1289ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov private boolean initialize() { 129015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov StrictMode.setThreadPolicy( 129115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 129215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 12933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Resources resources = getContext().getResources(); 1294f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxDisplayPhotoDim = resources.getInteger( 1295f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_display_photo_dim); 1296f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim = resources.getInteger( 1297f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_thumbnail_photo_dim); 12983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 129924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mProfileIdCache = new ProfileIdCache(); 1300b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper = (ContactsDatabaseHelper)getDatabaseHelper(); 130172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov mContactDirectoryManager = new ContactDirectoryManager(this); 1302a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov mGlobalSearchSupport = new GlobalSearchSupport(this); 1303f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mPhotoStore = new PhotoStore(getContext().getFilesDir(), mDbHelper); 130465ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov 1305bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // The provider is closed for business until fully initialized 130615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = new CountDownLatch(1); 130715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = new CountDownLatch(1); 130872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1309bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread = new HandlerThread("ContactsProviderWorker", 1310bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov Process.THREAD_PRIORITY_BACKGROUND); 1311bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread.start(); 1312bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler = new Handler(mBackgroundThread.getLooper()) { 1313bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov @Override 1314bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov public void handleMessage(Message msg) { 1315bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov performBackgroundTask(msg.what, msg.obj); 1316bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1317bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov }; 13182a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov 131915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_INITIALIZE); 1320bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1321bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 1322bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_LOCALE); 1323bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM); 132405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_SEARCH_INDEX); 1325bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_PROVIDER_STATUS); 132615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_OPEN_WRITE_ACCESS); 1327f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 13283826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 132949d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov return true; 13304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 13314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1332767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov /** 133351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * (Re)allocates all locale-sensitive structures. 133451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 133504b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov private void initForDefaultLocale() { 133615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 133715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mLegacyApiSupport = new LegacyApiSupport(context, mDbHelper, this, mGlobalSearchSupport); 13384cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mCurrentLocale = getLocale(); 133904b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov mNameSplitter = mDbHelper.createNameSplitter(); 13404cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter); 13414cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mPostalSplitter = new PostalSplitter(mCurrentLocale); 134251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov mCommonNicknameCache = new CommonNicknameCache(mDbHelper.getReadableDatabase()); 1343cdd03b2ba03718a7fa85663a2438136284a1557cBai Tao ContactLocaleUtils.getIntance().setLocale(mCurrentLocale); 13445b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator = new ContactAggregator(this, mDbHelper, 134515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 13465b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 1347f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov mSearchIndexManager = new SearchIndexManager(this); 13485b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 1349bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers = new HashMap<String, DataRowHandler>(); 1350bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1351bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, 13526d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForEmail(context, mDbHelper, mContactAggregator)); 1353bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE, 13546d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForIm(context, mDbHelper, mContactAggregator)); 1355bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, 13566d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForOrganization(context, mDbHelper, mContactAggregator)); 1357bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, 13586d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForPhoneNumber(context, mDbHelper, mContactAggregator)); 1359bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, 13606d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForNickname(context, mDbHelper, mContactAggregator)); 1361bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE, 13626d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForStructuredName(context, mDbHelper, mContactAggregator, 1363bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mNameSplitter, mNameLookupBuilder)); 1364bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(StructuredPostal.CONTENT_ITEM_TYPE, 13656d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForStructuredPostal(context, mDbHelper, mContactAggregator, 1366bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mPostalSplitter)); 1367bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE, 13686d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForGroupMembership(context, mDbHelper, mContactAggregator, 1369bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mGroupIdCache)); 1370bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Photo.CONTENT_ITEM_TYPE, 1371f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new DataRowHandlerForPhoto(context, mDbHelper, mContactAggregator, mPhotoStore)); 13726d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov mDataRowHandlers.put(Note.CONTENT_ITEM_TYPE, 13736d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForNote(context, mDbHelper, mContactAggregator)); 1374bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1375bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1376bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /** 1377bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Visible for testing. 1378bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov */ 1379bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /* package */ PhotoPriorityResolver createPhotoPriorityResolver(Context context) { 1380bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov return new PhotoPriorityResolver(context); 1381bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1382bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1383bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task) { 1384bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendEmptyMessage(task); 1385bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1386bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1387bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task, Object arg) { 1388bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(task, arg)); 1389bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1390bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1391bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void performBackgroundTask(int task, Object arg) { 1392bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov switch (task) { 139315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_INITIALIZE: { 139415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov initForDefaultLocale(); 139515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch.countDown(); 139615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = null; 139715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov break; 139815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 139915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 140015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_OPEN_WRITE_ACCESS: { 1401bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (mOkToOpenAccess) { 140215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch.countDown(); 140315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = null; 1404bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1405bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1406bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1407bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1408bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS: { 1409bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isLegacyContactImportNeeded()) { 1410bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov importLegacyContactsInBackground(); 1411bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1412bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1413bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1414bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1415bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_ACCOUNTS: { 141615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 141715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (!mAccountUpdateListenerRegistered) { 141815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov AccountManager.get(context).addOnAccountsUpdatedListener(this, null, false); 141915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mAccountUpdateListenerRegistered = true; 142015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 142115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 142215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Account[] accounts = AccountManager.get(context).getAccounts(); 1423bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov boolean accountsChanged = updateAccountsInBackground(accounts); 1424bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateContactsAccountCount(accounts); 1425bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateDirectoriesInBackground(accountsChanged); 1426bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1427bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1428bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1429bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_LOCALE: { 1430bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateLocaleInBackground(); 1431bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1432bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1433bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1434fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov case BACKGROUND_TASK_CHANGE_LOCALE: { 1435fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov changeLocaleInBackground(); 1436fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov break; 1437fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1438fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1439bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM: { 1440bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isAggregationUpgradeNeeded()) { 1441bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov upgradeAggregationAlgorithmInBackground(); 1442bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1443bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1444bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1445bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 144605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_SEARCH_INDEX: { 144705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov updateSearchIndexInBackground(); 144805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov break; 144905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 145005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1451bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_PROVIDER_STATUS: { 1452bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateProviderStatus(); 1453bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1454bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1455bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1456bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_DIRECTORIES: { 1457bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (arg != null) { 1458bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.onPackageChanged((String) arg); 1459bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1460bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1461bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1462f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1463f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case BACKGROUND_TASK_CLEANUP_PHOTOS: { 1464f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check rate limit. 1465f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long now = System.currentTimeMillis(); 1466f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (now - mLastPhotoCleanup > PHOTO_CLEANUP_RATE_LIMIT) { 1467f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mLastPhotoCleanup = now; 1468f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupPhotoStore(); 1469f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro break; 1470f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1471f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1472bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 14734cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 14744cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao 147553fac8f99f3884c372c907a76766d27fa9e1d95fDmitri Plotnikov public void onLocaleChanged() { 14763826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 14773826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 14784f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov return; 14794f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov } 14804f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov 1481fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_CHANGE_LOCALE); 14824cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 148351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 148451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov /** 148551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * Verifies that the contacts database is properly configured for the current locale. 148651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * If not, changes the database locale to the current locale using an asynchronous task. 148751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * This needs to be done asynchronously because the process involves rebuilding 148851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * large data structures (name lookup, sort keys), which can take minutes on 148951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * a large set of contacts. 149051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 1491bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateLocaleInBackground() { 1492f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 1493f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov // The process is already running - postpone the change 1494f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov if (mProviderStatus == ProviderStatus.STATUS_CHANGING_LOCALE) { 1495f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov return; 1496f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov } 1497f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 149851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 149951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final String providerLocale = prefs.getString(PREF_LOCALE, null); 150051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final Locale currentLocale = mCurrentLocale; 150151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov if (currentLocale.toString().equals(providerLocale)) { 150251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov return; 150351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 150451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 150551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov int providerStatus = mProviderStatus; 150651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_CHANGING_LOCALE); 1507bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDbHelper.setLocale(this, currentLocale); 1508bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).apply(); 1509bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov setProviderStatus(providerStatus); 1510bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 151151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 1512fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov /** 1513fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov * Reinitializes the provider for a new locale. 1514fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov */ 1515fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov private void changeLocaleInBackground() { 1516fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Re-initializing the provider without stopping it. 1517fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Locking the database will prevent inserts/updates/deletes from 1518fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // running at the same time, but queries may still be running 1519fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // on other threads. Those queries may return inconsistent results. 1520fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov SQLiteDatabase db = mDbHelper.getWritableDatabase(); 1521fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.beginTransaction(); 1522fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov try { 1523fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov initForDefaultLocale(); 1524fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.setTransactionSuccessful(); 1525fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } finally { 1526fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.endTransaction(); 1527fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1528fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1529fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov updateLocaleInBackground(); 1530fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1531fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 153205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov protected void updateSearchIndexInBackground() { 153305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov mSearchIndexManager.updateIndex(); 153405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 153505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1536bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateDirectoriesInBackground(boolean rescan) { 1537bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanAllPackages(rescan); 153851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 153951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 15403826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateProviderStatus() { 15413826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 15423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 15433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return; 15443826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15453826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 15463826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mContactsAccountCount == 0 154749d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov && DatabaseUtils.queryNumEntries(mDbHelper.getReadableDatabase(), 154849d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Tables.CONTACTS, null) == 0) { 15493826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 15503826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } else { 15513826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 15523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15533826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15543826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 155531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* Visible for testing */ 1556f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro protected void cleanupPhotoStore() { 15576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro SQLiteDatabase db = mDbHelper.getWritableDatabase(); 15586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 15596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Assemble the set of photo store file IDs that are in use, and send those to the photo 1560f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // store. Any photos that aren't in that set will be deleted, and any photos that no 1561f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // longer exist in the photo store will be returned for us to clear out in the DB. 15626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = db.query(Views.DATA, new String[]{Data._ID, Photo.PHOTO_FILE_ID}, 1563f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.MIMETYPE + "=" + Photo.MIMETYPE + " AND " 1564f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro + Photo.PHOTO_FILE_ID + " IS NOT NULL", null, null, null, null); 15656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> usedPhotoFileIds = Sets.newHashSet(); 15666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToDataId = Maps.newHashMap(); 1567f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1568f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro while (c.moveToNext()) { 15696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = c.getLong(0); 15706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(1); 15716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 15726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToDataId.put(photoFileId, dataId); 15736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 15746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 15756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 15766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 15776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 15786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Also query for all social stream item photos. 15796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c = db.query(Tables.STREAM_ITEM_PHOTOS, 15806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{ 15816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos._ID, 15826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.STREAM_ITEM_ID, 15836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.PHOTO_FILE_ID 15846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro }, 15856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro null, null, null, null, null); 15866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToStreamItemPhotoId = Maps.newHashMap(); 15876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> streamItemPhotoIdToStreamItemId = Maps.newHashMap(); 15886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 15896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro while (c.moveToNext()) { 15906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = c.getLong(0); 15916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = c.getLong(1); 15926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(2); 15936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 15946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToStreamItemPhotoId.put(photoFileId, streamItemPhotoId); 15956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemPhotoIdToStreamItemId.put(streamItemPhotoId, streamItemId); 1596f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1597f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 1598f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 1599f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1600f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1601f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Run the photo store cleanup. 16026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> missingPhotoIds = mPhotoStore.cleanup(usedPhotoFileIds); 1603f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1604f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If any of the keys we're using no longer exist, clean them up. 16056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!missingPhotoIds.isEmpty()) { 1606f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 16076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro for (long missingPhotoId : missingPhotoIds) { 16086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToDataId.containsKey(missingPhotoId)) { 16096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = photoFileIdToDataId.get(missingPhotoId); 1610f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 1611f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.putNull(Photo.PHOTO_FILE_ID); 1612f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ops.add(ContentProviderOperation.newUpdate( 16136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentUris.withAppendedId(Data.CONTENT_URI, dataId)) 1614f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .withValues(updateValues).build()); 1615f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 16166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToStreamItemPhotoId.containsKey(missingPhotoId)) { 16176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For missing photos that were in stream item photos, just delete the stream 16186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // item photo. 16196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = photoFileIdToStreamItemPhotoId.get(missingPhotoId); 16206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = streamItemPhotoIdToStreamItemId.get(streamItemPhotoId); 16216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ops.add(ContentProviderOperation.newDelete( 16226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.CONTENT_URI.buildUpon() 16236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemId)) 16246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY) 16256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemPhotoId)) 16266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .build()).build()); 16276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 1628f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1629f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1630f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro applyBatch(ops); 1631f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (OperationApplicationException oae) { 1632f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Not a fatal problem (and we'll try again on the next cleanup). 1633f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Failed to clean up outdated photo references", oae); 1634f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1635f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1636f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1637f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1638f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* Visible for testing */ 1639de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov @Override 1640b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 1641b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return ContactsDatabaseHelper.getInstance(context); 164231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 164331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1644f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* package */ PhotoStore getPhotoStore() { 1645f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return mPhotoStore; 1646f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1647f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 164887614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxDisplayPhotoDim() { 164987614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxDisplayPhotoDim; 165087614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 165187614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 165287614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxThumbnailPhotoDim() { 165387614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxThumbnailPhotoDim; 165487614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 165587614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1656013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov /* package */ NameSplitter getNameSplitter() { 1657013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov return mNameSplitter; 1658013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov } 1659013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov 16605df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov /* package */ NameLookupBuilder getNameLookupBuilder() { 16615df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov return mNameLookupBuilder; 16625df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov } 16635df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov 16645dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov /* Visible for testing */ 1665ed78fd6df5e9f3a2d572162e5d374d1f4a625bddDmitri Plotnikov public ContactDirectoryManager getContactDirectoryManagerForTest() { 166672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov return mContactDirectoryManager; 166772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 166872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 166972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov /* Visible for testing */ 16705dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov protected Locale getLocale() { 16715dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov return Locale.getDefault(); 16725dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov } 16735dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 16743d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov protected boolean isLegacyContactImportNeeded() { 1675b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_CONTACTS_IMPORTED, "0")); 1676b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov return version < PROPERTY_CONTACTS_IMPORT_VERSION; 16773d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 16783d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1679568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov protected LegacyContactImporter getLegacyContactImporter() { 1680568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return new LegacyContactImporter(getContext(), this); 1681568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1682568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1683568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 1684bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Imports legacy contacts as a background task. 1685568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 1686bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private void importLegacyContactsInBackground() { 1687bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Importing legacy contacts"); 1688bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADING); 1689568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1690bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 1691bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDbHelper.setLocale(this, mCurrentLocale); 1692bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, mCurrentLocale.toString()).commit(); 1693568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1694bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov LegacyContactImporter importer = getLegacyContactImporter(); 1695bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (importLegacyContacts(importer)) { 1696bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportSuccess(); 1697bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } else { 1698bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportFailure(); 1699bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1700568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1701568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1702bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1703bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Unlocks the provider and declares that the import process is complete. 1704bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1705bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportSuccess() { 1706bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1707bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)getContext().getSystemService(Context.NOTIFICATION_SERVICE); 1708bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.cancel(LEGACY_IMPORT_FAILED_NOTIFICATION); 1709bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1710b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov // Store a property in the database indicating that the conversion process succeeded 1711b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov mDbHelper.setProperty(PROPERTY_CONTACTS_IMPORTED, 1712b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov String.valueOf(PROPERTY_CONTACTS_IMPORT_VERSION)); 1713bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 1714bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Completed import of legacy contacts"); 1715bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1716bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1717bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1718bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Announces the provider status and keeps the provider locked. 1719bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1720bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportFailure() { 1721bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Context context = getContext(); 1722bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1723bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); 1724bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1725bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // Show a notification 1726bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Notification n = new Notification(android.R.drawable.stat_notify_error, 1727bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_ticker), 1728bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov System.currentTimeMillis()); 1729bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.setLatestEventInfo(context, 1730bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_title), 1731bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_text), 1732bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov PendingIntent.getActivity(context, 0, new Intent(Intents.UI.LIST_DEFAULT), 0)); 1733bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; 1734bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1735bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.notify(LEGACY_IMPORT_FAILED_NOTIFICATION, n); 1736bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1737bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADE_OUT_OF_MEMORY); 1738bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Failed to import legacy contacts"); 1739bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1740bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // Do not let any database changes until this issue is resolved. 1741bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mOkToOpenAccess = false; 17423d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17433d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 17443d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /* Visible for testing */ 1745568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /* package */ boolean importLegacyContacts(LegacyContactImporter importer) { 17460e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff boolean aggregatorEnabled = mContactAggregator.isEnabled(); 17473d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov mContactAggregator.setEnabled(false); 17483d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov try { 1749bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (importer.importContacts()) { 1750bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1751bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // TODO aggregate all newly added raw contacts 1752bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mContactAggregator.setEnabled(aggregatorEnabled); 1753bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return true; 1754bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 17553d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } catch (Throwable e) { 17563d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov Log.e(TAG, "Legacy contact import failed", e); 17573d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 1758bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mEstimatedStorageRequirement = importer.getEstimatedStorageRequirement(); 1759bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return false; 17603d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17613d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1762a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 1763a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 1764a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 1765a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /* package */ void wipeData() { 1766b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.wipeData(); 1767f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mPhotoStore.clear(); 17683826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS; 1769a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 1770a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1771568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 177215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov * During intialization, this content provider will 1773568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * block all attempts to change contacts data. In particular, it will hold 1774568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * up all contact syncs. As soon as the import process is complete, all 1775568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * processes waiting to write to the provider are unblocked and can proceed 1776568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * to compete for the database transaction monitor. 1777568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 177815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private void waitForAccess(CountDownLatch latch) { 177915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (latch == null) { 178015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 178115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 178215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 178315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov while (true) { 178415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov try { 178515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov latch.await(); 178615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 178715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } catch (InterruptedException e) { 178815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Thread.currentThread().interrupt(); 1789ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov } 1790568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1791568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1792568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1793568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1794568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public Uri insert(Uri uri, ContentValues values) { 179515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1796568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.insert(uri, values); 1797568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1798568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1799568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1800568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 180115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (mWriteAccessLatch != null) { 1802bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // We are stuck trying to upgrade contacts db. The only update request 1803bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // allowed in this case is an update of provider status, which will trigger 1804bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // an attempt to upgrade contacts again. 1805bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov int match = sUriMatcher.match(uri); 1806bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (match == PROVIDER_STATUS) { 1807bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Integer newStatus = values.getAsInteger(ProviderStatus.STATUS); 1808bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (newStatus != null && newStatus == ProviderStatus.STATUS_UPGRADING) { 1809bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1810bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 1; 1811bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } else { 1812bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 0; 1813bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1814bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1815bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 181615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1817568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.update(uri, values, selection, selectionArgs); 1818568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1819568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1820568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1821568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int delete(Uri uri, String selection, String[] selectionArgs) { 182215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1823568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.delete(uri, selection, selectionArgs); 1824568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1825568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1826568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1827568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 1828568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov throws OperationApplicationException { 182915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1830568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.applyBatch(operations); 1831568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1832568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 18334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 18347b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov public int bulkInsert(Uri uri, ContentValues[] values) { 18357b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov waitForAccess(mWriteAccessLatch); 18367b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov return super.bulkInsert(uri, values); 18377b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov } 18387b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov 18397b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov @Override 1840285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void onBeginTransaction() { 1841bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1842b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "onBeginTransaction"); 1843b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1844285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.onBeginTransaction(); 18451ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana mContactAggregator.clearPendingAggregations(); 1846d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.clear(); 1847b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1848b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1849285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 1850285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 1851285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void beforeTransactionCommit() { 18521129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 1853bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1854b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "beforeTransactionCommit"); 1855b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1856285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.beforeTransactionCommit(); 1857b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 1858bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateInTransaction(mTransactionContext, mDb); 18591a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (mVisibleTouched) { 18601a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = false; 1861b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.updateAllVisible(); 18621a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey } 18633826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 1864bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 1865bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 18663826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatusUpdateNeeded) { 18673826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 18683826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = false; 18693826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 1870b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1871b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1872bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov private void updateSearchIndexInTransaction() { 1873bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov Set<Long> staleContacts = mTransactionContext.getStaleSearchIndexContactIds(); 1874bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov Set<Long> staleRawContacts = mTransactionContext.getStaleSearchIndexRawContactIds(); 1875bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov if (!staleContacts.isEmpty() || !staleRawContacts.isEmpty()) { 1876bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mSearchIndexManager.updateIndexForRawContacts(staleContacts, staleRawContacts); 1877bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mTransactionContext.clearSearchIndexUpdates(); 1878bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 1879bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 1880bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 1881b5a4add17815167d20a90645779df34cdf45280dFred Quintana private void flushTransactionalChanges() { 1882bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1883b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "flushTransactionChanges"); 1884b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 18851129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 188624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Determine whether we need to refresh the profile ID cache. 188724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean profileCacheRefreshNeeded = false; 188824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1889d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov for (long rawContactId : mTransactionContext.getInsertedRawContactIds()) { 18908ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(mDb, rawContactId); 1891bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.onRawContactInsert(mTransactionContext, mDb, rawContactId); 1892285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 1893b5a4add17815167d20a90645779df34cdf45280dFred Quintana 189424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Map<Long, Account> insertedProfileRawContactAccountMap = 189524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.getInsertedProfileRawContactIds(); 189624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!insertedProfileRawContactAccountMap.isEmpty()) { 189724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro for (long profileRawContactId : insertedProfileRawContactAccountMap.keySet()) { 189824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mDbHelper.updateRawContactDisplayName(mDb, profileRawContactId); 189924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mContactAggregator.onProfileRawContactInsert(mTransactionContext, mDb, 190024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactId, 190124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro insertedProfileRawContactAccountMap.get(profileRawContactId)); 190224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 190324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = true; 190424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 190524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1906d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov Set<Long> dirtyRawContacts = mTransactionContext.getDirtyRawContactIds(); 1907d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!dirtyRawContacts.isEmpty()) { 1908a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 1909a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL); 1910d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, dirtyRawContacts); 1911a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 1912a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mDb.execSQL(mSb.toString()); 191324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 191424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = profileCacheRefreshNeeded || 191524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro !Collections.disjoint(mProfileIdCache.profileRawContactIds, dirtyRawContacts); 1916a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov } 1917a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 1918d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov Set<Long> updatedRawContacts = mTransactionContext.getUpdatedRawContactIds(); 1919d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!updatedRawContacts.isEmpty()) { 1920a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 1921a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL); 1922d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, updatedRawContacts); 1923a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 1924a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mDb.execSQL(mSb.toString()); 192524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 192624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = profileCacheRefreshNeeded || 192724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro !Collections.disjoint(mProfileIdCache.profileRawContactIds, updatedRawContacts); 1928b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1929b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1930d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov for (Map.Entry<Long, Object> entry : mTransactionContext.getUpdatedSyncStates()) { 1931b5a4add17815167d20a90645779df34cdf45280dFred Quintana long id = entry.getKey(); 19329d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana if (mDbHelper.getSyncState().update(mDb, id, entry.getValue()) <= 0) { 19339d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana throw new IllegalStateException( 19349d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana "unable to update sync state, does it still exist?"); 19359d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana } 1936b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1937b5a4add17815167d20a90645779df34cdf45280dFred Quintana 193824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (profileCacheRefreshNeeded) { 193924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Force the profile ID cache to refresh. 194024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mProfileIdCache.init(mDb, true); 194124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 194224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1943d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.clear(); 1944b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1945b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1946a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** 1947a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * Appends comma separated ids. 1948a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * @param ids Should not be empty 1949a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov */ 1950d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private void appendIds(StringBuilder sb, Set<Long> ids) { 1951b5a4add17815167d20a90645779df34cdf45280dFred Quintana for (long id : ids) { 1952a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(id).append(','); 1953b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1954a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 1955a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.setLength(sb.length() - 1); // Yank the last comma 1956285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 1957285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 195824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 195924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given contact ID represents the user's personal profile - if it is, calls 196024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * a permission check (for writing the profile if forWrite is true, for reading the profile 196124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * otherwise). If the contact ID is not the user's profile, no check is executed. 1962afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 196324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param contactId The contact ID to be checked. 196424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 196524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 1966afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForContact(SQLiteDatabase db, long contactId, 1967afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro boolean forWrite) { 1968afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 196924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileContactId == contactId) { 197024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 197124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 197224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 197324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 197424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 197524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given raw contact ID is a member of the user's personal profile - if it 197624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * is, calls a permission check (for writing the profile if forWrite is true, for reading the 197724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile otherwise). If the raw contact ID is not in the user's profile, no check is 197824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * executed. 1979afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 198024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param rawContactId The raw contact ID to be checked. 198124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 198224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 1983afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForRawContact(SQLiteDatabase db, long rawContactId, 1984afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro boolean forWrite) { 1985afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 198624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileRawContactIds.contains(rawContactId)) { 198724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 198824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 198924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 199024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 199124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 199224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given data ID is a member of the user's personal profile - if it is, 199324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * calls a permission check (for writing the profile if forWrite is true, for reading the 199424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile otherwise). If the data ID is not in the user's profile, no check is executed. 1995afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 199624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param dataId The data ID to be checked. 199724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 199824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 1999afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForData(SQLiteDatabase db, long dataId, boolean forWrite) { 2000afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 200124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileDataIds.contains(dataId)) { 200224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 200324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 200424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 200524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 200624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 200724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Performs a permission check for WRITE_PROFILE or READ_PROFILE (depending on the parameter). 200824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * If the permission check fails, this will throw a SecurityException. 200924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 201024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 201124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void enforceProfilePermission(boolean forWrite) { 201224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String profilePermission = forWrite 201324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro ? "android.permission.WRITE_PROFILE" 201424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro : "android.permission.READ_PROFILE"; 201524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro getContext().enforceCallingOrSelfPermission(profilePermission, null); 201624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 201724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2018285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2019cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov protected void notifyChange() { 202081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov notifyChange(mSyncToNetwork); 202181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = false; 202281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 202381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 202481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov protected void notifyChange(boolean syncToNetwork) { 202581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null, 202681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov syncToNetwork); 2027cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov } 2028568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 202951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov protected void setProviderStatus(int status) { 20303826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != status) { 20313826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = status; 20323826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov getContext().getContentResolver().notifyChange(ProviderStatus.CONTENT_URI, null, false); 20333826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 203451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 203551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 2036f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public DataRowHandler getDataRowHandler(final String mimeType) { 20373cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataRowHandler handler = mDataRowHandlers.get(mimeType); 20383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (handler == null) { 20396d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov handler = new DataRowHandlerForCustomMimetype( 20406d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov getContext(), mDbHelper, mContactAggregator, mimeType); 20413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(mimeType, handler); 20423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 20433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return handler; 20443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 20453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 20464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 2047de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected Uri insertInTransaction(Uri uri, ContentValues values) { 2048bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 20491129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Log.v(TAG, "insertInTransaction: " + uri + " " + values); 2050b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2051f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2052f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 2053f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 2054f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2055a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 2056a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 205735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2058a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 205935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 2060b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov id = mDbHelper.getSyncState().insert(mDb, values); 206135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 206235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2063d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 2064d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov insertContact(values); 20656bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 20666bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 20676bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 206824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 206924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro throw new UnsupportedOperationException( 207024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "The profile contact is created automatically"); 207124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 207224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 20735ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 207424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter, false); 2075f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2076a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2077a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2078a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 20795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 20805ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 2081f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2082f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2083a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2084a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2085a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 20863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 20873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItems.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 20883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 20893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 20903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 20913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 20923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 209324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 209424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(true); 209524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter, true); 209624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mSyncToNetwork |= !callerIsSyncAdapter; 209724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 209824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 209924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2100a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case DATA: { 2101f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2102f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2103a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2104a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2105a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2106ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 2107f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov id = insertGroup(uri, values, callerIsSyncAdapter); 2108f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2109ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2110ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2111ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2112eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 21135aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey id = insertSettings(uri, values); 211443880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 2115eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 2116eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 2117eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 211882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 211982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov id = insertStatusUpdate(values); 21201f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 21211f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 21221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 21233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 21243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 21253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 21293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 21303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 21313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 21353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 21363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItemPhotos.STREAM_ITEM_ID, uri.getPathSegments().get(1)); 21373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 21383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2142a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 214381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 2144f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 2145a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2146a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 21487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 21497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 21507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2151de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return ContentUris.withAppendedId(uri, id); 2152a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2153a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2154a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2155e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * If account is non-null then store it in the values. If the account is 2156e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * already specified in the values then it must be consistent with the 2157e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * account, if it is non-null. 2158e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * 2159e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param uri Current {@link Uri} being operated on. 2160e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param values {@link ContentValues} to read and possibly update. 2161e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when only one of 2162e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_NAME} or 2163e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the 2164e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * other undefined. 2165e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME} 2166e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between 2167e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * the given {@link Uri} and {@link ContentValues}. 21687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 2169e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException { 2170f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 2171f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 2172e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 2173f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2174f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME); 2175f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 2176e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialValues = TextUtils.isEmpty(valueAccountName) 2177e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey ^ TextUtils.isEmpty(valueAccountType); 2178e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2179e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri || partialValues) { 2180e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 2181fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 2182fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 2183e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2184e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2185e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 2186e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 2187e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validUri = !TextUtils.isEmpty(accountName); 2188e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validValues = !TextUtils.isEmpty(valueAccountName); 2189e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2190e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validValues && validUri) { 2191e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Check that accounts match when both present 2192e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean accountMatch = TextUtils.equals(accountName, valueAccountName) 2193e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey && TextUtils.equals(accountType, valueAccountType); 2194e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (!accountMatch) { 2195fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 2196fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "When both specified, ACCOUNT_NAME and ACCOUNT_TYPE must match", uri)); 2197e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2198e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validUri) { 2199e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Fill values from Uri when not present 2200f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_NAME, accountName); 2201f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_TYPE, accountType); 2202e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validValues) { 2203f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountName = valueAccountName; 2204f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountType = valueAccountType; 2205e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else { 2206e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return null; 2207f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 2208f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2209e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Use cached Account object when matches, otherwise create 2210f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mAccount == null 2211f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.name.equals(accountName) 2212f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.type.equals(accountType)) { 2213f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mAccount = new Account(accountName, accountType); 2214035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 2215f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2216e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return mAccount; 22177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 22187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 22197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 2220d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov * Inserts an item in the contacts table 22216bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 22226bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 22236bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 22246bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 2225d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private long insertContact(ContentValues values) { 2226de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new UnsupportedOperationException("Aggregate contacts are created automatically"); 22276bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 22286bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 22296bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 223024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Inserts an item in the raw contacts table 2231a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2232f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param uri the values for the new row 2233f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param values the account this contact should be associated with. may be null. 2234dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana * @param callerIsSyncAdapter 223524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forProfile Whether this raw contact is being inserted into the user's profile. 2236a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2237a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 223824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private long insertRawContact(Uri uri, ContentValues values, boolean callerIsSyncAdapter, 223924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean forProfile) { 2240f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2241f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2242f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 2243f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2244e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final Account account = resolveAccount(uri, mValues); 22457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 22463d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov if (values.containsKey(RawContacts.DELETED) 22473d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov && values.getAsInteger(RawContacts.DELETED) != 0) { 2248f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 22493d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 22503d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2251f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov long rawContactId = mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, mValues); 2252f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = RawContacts.AGGREGATION_MODE_DEFAULT; 225324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (forProfile) { 225424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Profile raw contacts should never be aggregated by the aggregator; they are always 225524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // aggregated under a single profile contact. 225624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro aggregationMode = RawContacts.AGGREGATION_MODE_DISABLED; 225724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else if (mValues.containsKey(RawContacts.AGGREGATION_MODE)) { 2258f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov aggregationMode = mValues.getAsInteger(RawContacts.AGGREGATION_MODE); 2259f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 2260f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov mContactAggregator.markNewForAggregation(rawContactId, aggregationMode); 2261285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 226224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (forProfile) { 226324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Trigger creation of the user profile Contact (or association with the existing one) 226424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // at the end of the transaction. 226524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.profileRawContactInserted(rawContactId, account); 226624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else { 226724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Trigger creation of a Contact based on this RawContact at the end of transaction 226824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.rawContactInserted(rawContactId, account); 226924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 2270f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2271dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 2272dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 2273dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long starred = values.getAsLong(RawContacts.STARRED); 2274dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (starred != null && starred != 0) { 2275dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred != 0); 2276dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2277dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2278dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 22793826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 2280023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov return rawContactId; 2281a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2282a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2283dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void addAutoAddMembership(long rawContactId) { 2284dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID, 2285dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2286dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2287dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2288dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2289dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2290dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2291dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private Long findGroupByRawContactId(String selection, long rawContactId) { 2292dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Cursor c = mDb.query(Tables.GROUPS + "," + Tables.RAW_CONTACTS, PROJECTION_GROUP_ID, 2293dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, 2294dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}, 2295dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana null /* groupBy */, null /* having */, null /* orderBy */); 2296dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 2297dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (c.moveToNext()) { 2298dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return c.getLong(0); 2299dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2300dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return null; 2301dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 2302dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana c.close(); 2303dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2304dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2305dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2306dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void updateFavoritesMembership(long rawContactId, boolean isStarred) { 2307dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID, 2308dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2309dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2310dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (isStarred) { 2311dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2312dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2313dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana deleteDataGroupMembership(rawContactId, groupId); 2314dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2315dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2316dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2317dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2318dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void insertDataGroupMembership(long rawContactId, long groupId) { 2319dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ContentValues groupMembershipValues = new ContentValues(); 2320dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.GROUP_ROW_ID, groupId); 2321dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 2322dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(DataColumns.MIMETYPE_ID, 2323dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 2324dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDb.insert(Tables.DATA, null, groupMembershipValues); 2325dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2326dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2327dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void deleteDataGroupMembership(long rawContactId, long groupId) { 2328dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final String[] selectionArgs = { 2329dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)), 2330dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(groupId), 2331dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(rawContactId)}; 2332dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDb.delete(Tables.DATA, SELECTION_GROUPMEMBERSHIP_DATA, selectionArgs); 2333dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2334dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2335a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2336a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 2337a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2338a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 2339a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2340a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 2341f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private long insertData(ContentValues values, boolean callerIsSyncAdapter) { 2342a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 2343de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.clear(); 2344de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.putAll(values); 234567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 2346de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID); 234720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 234824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // If the data being inserted belongs to the user's profile entry, check for the 234924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // WRITE_PROFILE permission before proceeding. 2350afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 235124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2352de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace package with internal mapping 2353de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String packageName = mValues.getAsString(Data.RES_PACKAGE); 2354de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (packageName != null) { 2355b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 2356de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 2357de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 2358508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 2359de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace mimetype with internal mapping 2360de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String mimeType = mValues.getAsString(Data.MIMETYPE); 2361de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (TextUtils.isEmpty(mimeType)) { 2362de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new IllegalArgumentException(Data.MIMETYPE + " is required"); 2363de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 23644097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 2365b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.getMimeTypeId(mimeType)); 2366de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 2367a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2368a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2369d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov id = rowHandler.insert(mDb, mTransactionContext, rawContactId, mValues); 2370f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2371d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 2372a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2373d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.rawContactUpdated(rawContactId); 2374a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 23754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 23764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 23773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 23783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_items table. The account is checked against the 23793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account in the raw contact for which the stream item is being inserted. If the 23803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * new stream item results in more stream items under this raw contact than the limit, 23813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest one will be deleted (note that if the stream item inserted was the 23823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * oldest, it will be immediately deleted, and this will return 0). 23833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 23843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 23853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 23863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return the stream item _ID of the newly created row, or 0 if it was not created 23873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 23883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItem(Uri uri, ContentValues values) { 23893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 23903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 23913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 23923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 23933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = mValues.getAsLong(StreamItems.RAW_CONTACT_ID); 23943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 23953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If the data being inserted belongs to the user's profile entry, check for the 23963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // WRITE_PROFILE permission before proceeding. 2397afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 23983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 23993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 24003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 24013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 24023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream items table. 24046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 24056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 24066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 24073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Insert the new stream item. 24086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro id = mDb.insert(Tables.STREAM_ITEMS, null, mValues); 24096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (id == -1) { 24106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insertion failed. 24116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 24126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check to see if we're over the limit for stream items under this raw contact. 24153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // It's possible that the inserted stream item is older than the the existing 24163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // ones, in which case it may be deleted immediately (resetting the ID to 0). 24173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = cleanUpOldStreamItems(rawContactId, id); 24183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 24203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_item_photos table. The account is checked against 24243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the account in the raw contact that owns the stream item being modified. 24253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 24263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 24273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 24286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return the stream item photo _ID of the newly created row, or 0 if there was an issue 24296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * with processing the photo or creating the row 24303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 24313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItemPhoto(Uri uri, ContentValues values) { 24323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 24333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 24343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 24353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = mValues.getAsLong(StreamItemPhotos.STREAM_ITEM_ID); 24373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemId != 0) { 24383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = lookupRawContactIdForStreamId(streamItemId); 24393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If the data being inserted belongs to the user's profile entry, check for the 24413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // WRITE_PROFILE permission before proceeding. 2442afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 24433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 24453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 24463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 24473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream item 24496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 24506802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 24516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 24523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 24546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(mValues, false)) { 24556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insert the stream item photo. 24566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro id = mDb.insert(Tables.STREAM_ITEM_PHOTOS, null, mValues); 24576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 24603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Processes the photo contained in the {@link ContactsContract.StreamItemPhotos#PHOTO} 24646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * field of the given values, attempting to store it in the photo store. If successful, 24656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * the resulting photo file ID will be added to the values for insert/update in the table. 24666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * <p> 24676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * If updating, it is valid for the picture to be empty or unspecified (the function will 24686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * still return true). If inserting, a valid picture must be specified. 24696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param values The content values provided by the caller. 24706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param forUpdate Whether this photo is being processed for update (vs. insert). 24716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return Whether the insert or update should proceed. 24726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 24736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro private boolean processStreamItemPhoto(ContentValues values, boolean forUpdate) { 24746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!values.containsKey(StreamItemPhotos.PHOTO)) { 24756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 24766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro byte[] photoBytes = values.getAsByteArray(StreamItemPhotos.PHOTO); 24786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoBytes == null) { 24796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 24806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 24826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 24836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 24846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = mPhotoStore.insert(new PhotoProcessor(photoBytes, 24851dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim, true), true); 24866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileId != 0) { 24876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.put(StreamItemPhotos.PHOTO_FILE_ID, photoFileId); 24886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(StreamItemPhotos.PHOTO); 24896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return true; 24906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 24916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Couldn't store the photo, return 0. 24926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert"); 24936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 24946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } catch (IOException ioe) { 24966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert", ioe); 24976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 24986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 25016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 25023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Looks up the raw contact ID that owns the specified stream item. 25033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param streamItemId The ID of the stream item. 25043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The associated raw contact ID, or -1 if no such stream item exists. 25053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long lookupRawContactIdForStreamId(long streamItemId) { 25073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = -1; 25083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = mDb.query(Tables.STREAM_ITEMS, new String[]{StreamItems.RAW_CONTACT_ID}, 25093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems._ID + "=?", new String[]{String.valueOf(streamItemId)}, 25103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c.moveToFirst()) { 25133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann rawContactId = c.getLong(0); 25143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 25163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 25173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return rawContactId; 25193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given raw contact ID is owned by the given account. 25233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account is null, this will return true iff the raw contact 25243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * is also associated with the "null" account. 25253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 25263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account does not match, this will throw a security exception. 25273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 25283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to check for. 25293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void enforceModifyingAccount(Account account, long rawContactId) { 25313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String accountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 25323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + "=? AND " 25333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + "=?"; 25343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String noAccountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 25353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " IS NULL AND " 25363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " IS NULL"; 25373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c; 25383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (account != null) { 25393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContactsColumns.CONCRETE_ID}, 25403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann accountSelection, 25413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(rawContactId), mAccount.name, mAccount.type}, 25423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 25443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContactsColumns.CONCRETE_ID}, 25453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann noAccountSelection, new String[]{String.valueOf(rawContactId)}, 25463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if(c.getCount() == 0) { 25503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new SecurityException("Caller account does not match raw contact ID " 25513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + rawContactId); 25523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 25543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 25553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream items matches up with the given 25603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 25613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 25623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 25633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 25643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 25653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item IDs that would be included in this selection. 25663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItems(Account account, String selection, 25683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 25693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = Lists.newArrayList(); 25703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 25713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 25723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = qb.query(mDb, 25733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{StreamItems._ID, StreamItems.RAW_CONTACT_ID}, 25743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 25753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 25773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemIds.add(c.getLong(0)); 25783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 25803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 25813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 25833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 25843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds; 25863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream item photos matches up with the given 25903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 25913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 25923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 25933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 25943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 25953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item photo IDs that would be included in this selection. 25963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItemPhotos(Account account, String selection, 25983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 25993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemPhotoIds = Lists.newArrayList(); 26003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 26013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 26023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = qb.query(mDb, new String[]{StreamItemPhotos._ID, StreamItems.RAW_CONTACT_ID}, 26033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 26043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 26063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemPhotoIds.add(c.getLong(0)); 26073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 26093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 26103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemPhotoIds; 26153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Queries the database for stream items under the given raw contact. If there are 26193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * more entries than {@link ContactsProvider2#MAX_STREAM_ITEMS_PER_RAW_CONTACT}, 26203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest entries (as determined by timestamp) will be deleted. 26213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to examine for stream items. 26223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param insertedStreamItemId The ID of the stream item that was just inserted, 26233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * prompting this cleanup. Callers may pass 0 if no insertion prompted the 26243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * cleanup. 26253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The ID of the inserted stream item if it still exists after cleanup; 26263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 0 otherwise. 26273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long cleanUpOldStreamItems(long rawContactId, long insertedStreamItemId) { 26293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long postCleanupInsertedStreamId = insertedStreamItemId; 26303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = mDb.query(Tables.STREAM_ITEMS, new String[]{StreamItems._ID}, 26313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 26323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, StreamItems.TIMESTAMP + " DESC, " + StreamItems._ID + " DESC"); 26333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int streamItemCount = c.getCount(); 26353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemCount <= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 26363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Still under the limit - nothing to clean up! 26373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return insertedStreamItemId; 26383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 26393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToLast(); 26403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.getPosition() >= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 26413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = c.getLong(0); 26423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (insertedStreamItemId == streamItemId) { 26433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // The stream item just inserted is being deleted. 26443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann postCleanupInsertedStreamId = 0; 26453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(c.getLong(0)); 26473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToPrevious(); 26483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return postCleanupInsertedStreamId; 26543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2656ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateRawContactDisplayName(SQLiteDatabase db, long rawContactId) { 26578ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(db, rawContactId); 2658d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov } 2659d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov 26609261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 266120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov * Delete data row by row so that fixing of primaries etc work correctly. 266220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov */ 2663f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) { 266420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 266520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2666de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 2667de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 2668f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, 2669f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov selection, selectionArgs, null); 2670de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov try { 2671de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov while(c.moveToNext()) { 2672f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 267324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 267424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for write profile permission if the data belongs to the profile. 2675afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 267624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2677f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 2678a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2679d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov count += rowHandler.delete(mDb, mTransactionContext, c); 2680f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2681d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 268288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov } 268320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 268420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 2685de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov c.close(); 268620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 268720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 268820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 268920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 269020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 269188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov /** 269288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov * Delete a data row provided that it is one of the allowed mime types. 269388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov */ 269420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov public int deleteData(long dataId, String[] allowedMimeTypes) { 2695f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 269688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 269788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 26984da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 2699f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, Data._ID + "=?", 27004da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1, null); 2701f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 270220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 270320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!c.moveToFirst()) { 270420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 270520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 270620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2707f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 270820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean valid = false; 270920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov for (int i = 0; i < allowedMimeTypes.length; i++) { 271020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.equals(mimeType, allowedMimeTypes[i])) { 271120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov valid = true; 271220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 271320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 271420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 271520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 271620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!valid) { 27177a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana throw new IllegalArgumentException("Data type mismatch: expected " 271820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov + Lists.newArrayList(allowedMimeTypes)); 271920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 272020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 272124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for write profile permission if the data belongs to the profile. 272224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 2723afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 272424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2725a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2726d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov return rowHandler.delete(mDb, mTransactionContext, c); 272720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 272820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 272920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 273020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 273120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 273220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov /** 2733ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 2734ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 2735f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2736f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2737f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2738f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2739e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final Account account = resolveAccount(uri, mValues); 2740ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2741ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 2742f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String packageName = mValues.getAsString(Groups.RES_PACKAGE); 274367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 2744f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 274567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 2746f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.remove(Groups.RES_PACKAGE); 2747ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2748dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final boolean isFavoritesGroup = mValues.getAsLong(Groups.FAVORITES) != null 2749dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ? mValues.getAsLong(Groups.FAVORITES) != 0 2750dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana : false; 2751dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2752f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2753f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(Groups.DIRTY, 1); 275473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 275573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 2756f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov long result = mDb.insert(Tables.GROUPS, Groups.TITLE, mValues); 2757ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2758dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && isFavoritesGroup) { 2759dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // add all starred raw contacts to this group 2760dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String selection; 2761dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs; 2762dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (account == null) { 2763dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + " IS NULL AND " 2764dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContacts.ACCOUNT_TYPE + " IS NULL"; 2765dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = null; 2766dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2767dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + "=? AND " 2768dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContacts.ACCOUNT_TYPE + "=?"; 2769dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = new String[]{account.name, account.type}; 2770dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2771dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Cursor c = mDb.query(Tables.RAW_CONTACTS, 2772dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{RawContacts._ID, RawContacts.STARRED}, 2773dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, selectionArgs, null, null, null); 2774892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov try { 2775892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov while (c.moveToNext()) { 2776892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (c.getLong(1) != 0) { 2777892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov final long rawContactId = c.getLong(0); 2778892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov insertDataGroupMembership(rawContactId, result); 2779d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 2780892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } 2781dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2782892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } finally { 2783892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov c.close(); 2784dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2785dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2786dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2787f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mValues.containsKey(Groups.GROUP_VISIBLE)) { 27881a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2789ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey } 2790ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2791ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey return result; 2792ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2793ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 27945aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private long insertSettings(Uri uri, ContentValues values) { 2795e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final long id = mDb.insert(Tables.SETTINGS, null, values); 27965aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey 27971a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 27981a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2799e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 28001a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 2801e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return id; 2802e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 2803e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 2804ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 280582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov * Inserts a status update. 28061f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 280782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov public long insertStatusUpdate(ContentValues values) { 280882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov final String handle = values.getAsString(StatusUpdates.IM_HANDLE); 28090a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL); 28104dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov String customProtocol = null; 28114dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov 28120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) { 281382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL); 28144dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov if (TextUtils.isEmpty(customProtocol)) { 28154dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov throw new IllegalArgumentException( 28164dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM"); 28174dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov } 28181f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 28191f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2820dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long rawContactId = -1; 2821dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long contactId = -1; 282282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov Long dataId = values.getAsLong(StatusUpdates.DATA_ID); 28236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountType = null; 28246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountName = null; 2825f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov mSb.setLength(0); 28262526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.clear(); 2827dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (dataId != null) { 2828dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the contact info for the given data row. 2829dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 28302526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(Tables.DATA + "." + Data._ID + "=?"); 28312526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(dataId)); 28321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 2833dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the data row to attach this presence update to 2834dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 28350a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(handle) || protocol == null) { 28360a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required"); 28370a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 28380a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 2839dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // TODO: generalize to allow other providers to match against email 2840dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol; 2841dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 28422a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov String mimeTypeIdIm = String.valueOf(mDbHelper.getMimeTypeIdForIm()); 2843dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (matchEmail) { 28442a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov String mimeTypeIdEmail = String.valueOf(mDbHelper.getMimeTypeIdForEmail()); 2845f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 2846f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise 2847f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the "OR" conjunction confuses it and it switches to a full scan of 2848f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the raw_contacts table. 2849f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 2850f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // This code relies on the fact that Im.DATA and Email.DATA are in fact the same 2851f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // column - Data.DATA1 28522526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + " IN (?,?)" + 28532526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Data.DATA1 + "=?" + 28542526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND ((" + DataColumns.MIMETYPE_ID + "=? AND " + Im.PROTOCOL + "=?"); 28552526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 28562526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 28572526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 28582526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 28592526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 2860dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 28612526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 28622526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 2863dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 28642526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=?))"); 28652526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 2866dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } else { 28672526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + "=?" + 28682526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.PROTOCOL + "=?" + 28692526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.DATA + "=?"); 28702526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 28712526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 28722526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 2873dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 28742526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 28752526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 2876dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 2877dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 28781f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 287982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.DATA_ID)) { 28802526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + DataColumns.CONCRETE_ID + "=?"); 28812526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(values.getAsString(StatusUpdates.DATA_ID)); 2882dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 288370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 288470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 28851f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 28861f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 2887de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 28882526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null, 28894394086494fe7909aaca70f56fb4bb08beebf303Dmitri Plotnikov Clauses.CONTACT_VISIBLE + " DESC, " + Data.RAW_CONTACT_ID); 28901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 289167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataId = cursor.getLong(DataContactsQuery.DATA_ID); 28925ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID); 28936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountType = cursor.getString(DataContactsQuery.ACCOUNT_TYPE); 28946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountName = cursor.getString(DataContactsQuery.ACCOUNT_NAME); 2895e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 28961f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 28971f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 28981f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 28991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 29001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 290131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 290231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 290331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 29041f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 29051f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 290682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.PRESENCE)) { 2907a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (customProtocol == null) { 2908a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 2909a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // properly enforce uniqueness of null values 2910a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov customProtocol = ""; 2911a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 2912a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 2913a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.clear(); 291482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.DATA_ID, dataId); 2915a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId); 2916a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.CONTACT_ID, contactId); 291782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PROTOCOL, protocol); 291882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 291982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_HANDLE, handle); 292082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.IM_ACCOUNT)) { 292182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT)); 2922a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 292382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PRESENCE, 292482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov values.getAsString(StatusUpdates.PRESENCE)); 2925aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori mValues.put(StatusUpdates.CHAT_CAPABILITY, 2926aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori values.getAsString(StatusUpdates.CHAT_CAPABILITY)); 29271f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2928a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // Insert the presence update 2929a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mDb.replace(Tables.PRESENCE, null, mValues); 2930a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 2931e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 29320a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 293382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.STATUS)) { 293482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String status = values.getAsString(StatusUpdates.STATUS); 29350a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE); 29360a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov Integer labelResource = values.getAsInteger(StatusUpdates.STATUS_LABEL); 29370a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 29380a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(resPackage) 29390a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov && (labelResource == null || labelResource == 0) 29400a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov && protocol != null) { 29410a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov labelResource = Im.getProtocolLabelResource(protocol); 29420a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 29430a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 29440a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov Long iconResource = values.getAsLong(StatusUpdates.STATUS_ICON); 29450a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov // TODO compute the default icon based on the protocol 29460a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 2947a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (TextUtils.isEmpty(status)) { 294878fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.deleteStatusUpdate(dataId); 2949a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } else { 29506802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP); 29516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (timestamp != null) { 29526802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mDbHelper.replaceStatusUpdate(dataId, timestamp, status, resPackage, 29536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro iconResource, labelResource); 29546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 29556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mDbHelper.insertStatusUpdate(dataId, status, resPackage, iconResource, 29566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro labelResource); 29576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 29586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 29596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For forward compatibility with the new stream item API, insert this status update 29606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // there as well. If we already have a stream item from this source, update that 29616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // one instead of inserting a new one (since the semantics of the old status update 29626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // API is to only have a single record). 29636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (rawContactId != -1 && !TextUtils.isEmpty(status)) { 29646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentValues streamItemValues = new ContentValues(); 29656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 29666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TEXT, status); 29676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.COMMENTS, ""); 29686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_PACKAGE, resPackage); 29696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_ICON, iconResource); 29706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_LABEL, labelResource); 29716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TIMESTAMP, 29726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro timestamp == null ? System.currentTimeMillis() : timestamp); 29736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 29746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Note: The following is basically a workaround for the fact that status 29756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates didn't do any sort of account enforcement, while social stream item 29766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates do. We can't expect callers of the old API to start passing account 29776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // information along, so we just populate the account params appropriately for 29786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // the raw contact. 29796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (accountName != null && accountType != null) { 29806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_NAME, accountName); 29816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_TYPE, accountType); 29826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 29836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 29846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Check for an existing stream item from this source, and insert or update. 29856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Uri streamUri = StreamItems.CONTENT_URI; 29866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = query(streamUri, new String[]{StreamItems._ID}, 29876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", 29886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{String.valueOf(rawContactId)}, null); 29896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 29906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (c.getCount() > 0) { 29916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.moveToFirst(); 29926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro update(ContentUris.withAppendedId(streamUri, c.getLong(0)), 29936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues, null, null); 29946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 29956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro insert(streamUri, streamItemValues); 29966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 29976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 29986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 29996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 3002e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3003e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3004bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov 3005a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (contactId != -1) { 3006f4015ab9ab7c26b766b5331fbf6655b8c54877eaDmitri Plotnikov mContactAggregator.updateLastStatusUpdateId(contactId); 3007a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3008a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3009a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov return dataId; 30101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 30111f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 30124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3013de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 3014bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3015b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "deleteInTransaction: " + uri); 3016b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3017b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3018f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3019f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 3020508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 3021508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 302235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 3023b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().delete(mDb, selection, selectionArgs); 302435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3025b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: 3026b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3027b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3028b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3029b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().delete(mDb, selectionWithId, selectionArgs); 3030b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3031cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov case CONTACTS: { 3032cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov // TODO 3033cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return 0; 3034cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3035cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3036d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3037d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 3038dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 30396bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 30406bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 30419fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP: { 30422e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 30432e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 30442e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 3045fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 3046fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 30472e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 30482e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 30492e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final long contactId = lookupContactIdByLookupKey(mDb, lookupKey); 3050dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 30512e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 30522e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 30539fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP_ID: { 30549fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // lookup contact by id and lookup key to see if they still match the actual record 30559fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final List<String> pathSegments = uri.getPathSegments(); 30569fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final String lookupKey = pathSegments.get(2); 30579fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 30589fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann setTablesAndProjectionMapForContacts(lookupQb, uri, null); 3059a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 30609fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann String[] args; 30619fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (selectionArgs == null) { 30629fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[2]; 30639fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 30649fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[selectionArgs.length + 2]; 30659fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 30669fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 30679fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args[0] = String.valueOf(contactId); 306860de6f6c3c70e53b603a47b0efc80993353a8368Daniel Lehmann args[1] = Uri.encode(lookupKey); 30699fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?"); 30709fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 30719fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann Cursor c = query(db, lookupQb, null, selection, args, null, null, null); 30729fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann try { 30739fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (c.getCount() == 1) { 30749fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // contact was unmodified so go ahead and delete it 3075dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 30769fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 30779fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // row was changed (e.g. the merging might have changed), we got multiple 30789fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // rows or the supplied selection filtered the record out 30799fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann return 0; 30809fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 30819fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } finally { 30829fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann c.close(); 30839fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 30849fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 30859fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann 30862971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case RAW_CONTACTS: { 30872971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 3088fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov Cursor c = mDb.query(Tables.RAW_CONTACTS, 3089fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov new String[]{RawContacts._ID, RawContacts.CONTACT_ID}, 3090e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 30912971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 30922971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 30932971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = c.getLong(0); 3094fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov long contactId = c.getLong(1); 3095fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov numDeletes += deleteRawContact(rawContactId, contactId, 3096fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 30972971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 30982971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 30992971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 31002971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31012971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 31022971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31032971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 31045ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 31052971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = ContentUris.parseId(uri); 3106fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return deleteRawContact(rawContactId, mDbHelper.getContactId(rawContactId), 3107fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 3108508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3109508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 311020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3111f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 3112944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong return deleteData(appendAccountToSelection(uri, selection), selectionArgs, 3113f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana callerIsSyncAdapter); 311420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 311520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 311648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 311748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 311848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 311948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3120508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 3121f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 31224da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 31234da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter); 3124ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3125ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3126ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3127f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 31285aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter); 31292971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31302971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 31312971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case GROUPS: { 31322971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 31332971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups._ID}, 3134e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 31352971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 31362971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 31375aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter); 31382971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31392971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 31402971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 31412971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 314281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (numDeletes > 0) { 3143f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 314481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 31452971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 3146508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3147508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 3148eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 314943880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3150e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs); 3151eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3152eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 315382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 31540a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov return deleteStatusUpdates(selection, selectionArgs); 31551f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 31561f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 31573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 31583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), selection, selectionArgs); 31603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 31623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 31633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), 31653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemsColumns.CONCRETE_ID + "=?", 31663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 31673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 31693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 31703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), selection, selectionArgs); 31723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 31743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 31753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 31773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 31783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), 31793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " 31803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + StreamItemPhotos.STREAM_ITEM_ID + "=?", 31813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 31823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 318481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 318581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 31863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return mLegacyApiSupport.delete(uri, selection, selectionArgs); 318781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3188508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 31894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 31904f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 31911c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) { 3192ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3193b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final long groupMembershipMimetypeId = mDbHelper 319494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 3195de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 319694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 319794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupId, null); 319894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 319994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana try { 3200f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 3201de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 320294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } else { 320394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.clear(); 320494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.put(Groups.DELETED, 1); 3205f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mValues.put(Groups.DIRTY, 1); 3206de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null); 320794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 320894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } finally { 32091a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 321094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 321194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 321294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 32135aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int deleteSettings(Uri uri, String selection, String[] selectionArgs) { 3214e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final int count = mDb.delete(Tables.SETTINGS, selection, selectionArgs); 32151a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3216e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3217e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3218e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3219dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int deleteContact(long contactId, boolean callerIsSyncAdapter) { 3220afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(mDb, contactId, true); 322196b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(contactId); 3222cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, 322396b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker RawContacts.CONTACT_ID + "=?", mSelectionArgs1, 322496b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker null, null, null); 3225cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov try { 3226cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov while (c.moveToNext()) { 3227cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov long rawContactId = c.getLong(0); 3228dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 3229cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3230cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } finally { 3231cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov c.close(); 3232cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3233cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 32343826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 32353826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3236cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return mDb.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 3237cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3238cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3239fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) { 3240afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 32413389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov mContactAggregator.invalidateAggregationExceptionCache(); 32423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 32433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3244f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 324514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null); 3246fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov int count = mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null); 3247fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov mContactAggregator.updateDisplayNameForContact(mDb, contactId); 3248fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return count; 324933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } else { 3250b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.removeContactIfSingleton(rawContactId); 3251dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 325233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 325333b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 325433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 32550a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private int deleteStatusUpdates(String selection, String[] selectionArgs) { 32569705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // delete from both tables: presence and status_updates 32579705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 32589705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (VERBOSE_LOGGING) { 32599705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori Log.v(TAG, "deleting data from status_updates for " + selection); 32609705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 32619705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mDb.delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection), 32629705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 32639705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mDb.delete(Tables.PRESENCE, selection, selectionArgs); 32640a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 32650a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 32663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItems(Uri uri, ContentValues values, String selection, 32673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 32683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream items to be deleted, and check that they belong 32693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // to the account. 32703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 32713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = enforceModifyingAccountForStreamItems( 32723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann account, selection, selectionArgs); 32733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 32753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann for (long streamItemId : streamItemIds) { 32763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(streamItemId); 32773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mVisibleTouched = true; 32803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds.size(); 32813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItem(long streamItemId) { 32843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 32853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItemPhotos(streamItemId); 32863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEMS, StreamItems._ID + "=?", 32873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 32883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(Uri uri, ContentValues values, String selection, 32913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 32923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream item photos to be deleted, and check that they 32933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // belong to the account. 32943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 32953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 32963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 32983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEM_PHOTOS, selection, selectionArgs); 32993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(long streamItemId) { 33023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 33033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEM_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID + "=?", 33043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 33053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 3307dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int markRawContactAsDeleted(long rawContactId, boolean callerIsSyncAdapter) { 330881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 330981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 3310cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.clear(); 3311cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DELETED, 1); 3312cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 3313cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1); 3314cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 3315cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3316dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return updateRawContact(rawContactId, mValues, callerIsSyncAdapter); 3317cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3318cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 33194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3320de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int updateInTransaction(Uri uri, ContentValues values, String selection, 3321de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov String[] selectionArgs) { 3322bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3323b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "updateInTransaction: " + uri); 3324b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3325b5a4add17815167d20a90645779df34cdf45280dFred Quintana 332635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 332700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 332800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 3329b5a4add17815167d20a90645779df34cdf45280dFred Quintana if (match == SYNCSTATE_ID && selection == null) { 3330b5a4add17815167d20a90645779df34cdf45280dFred Quintana long rowId = ContentUris.parseId(uri); 33311129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Object data = values.get(ContactsContract.SyncState.DATA); 3332d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.syncStateUpdated(rowId, data); 3333b5a4add17815167d20a90645779df34cdf45280dFred Quintana return 1; 3334b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3335b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3336f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3337f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 333800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 333935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 3340b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().update(mDb, values, 3341b5a4add17815167d20a90645779df34cdf45280dFred Quintana appendAccountToSelection(uri, selection), selectionArgs); 3342b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3343b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: { 3344b5a4add17815167d20a90645779df34cdf45280dFred Quintana selection = appendAccountToSelection(uri, selection); 3345b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3346b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3347b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3348b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().update(mDb, values, 3349b5a4add17815167d20a90645779df34cdf45280dFred Quintana selectionWithId, selectionArgs); 3350b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 335135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3352d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 3353dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter); 335400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 335500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 335600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3357d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3358dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(ContentUris.parseId(uri), values, callerIsSyncAdapter); 3359c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 3360c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 3361c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 336224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 336324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Restrict update to the user's profile. 336424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro StringBuilder profileSelection = new StringBuilder(); 336524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileSelection.append(Contacts.IS_USER_PROFILE + "=1"); 336624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(selection)) { 336724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileSelection.append(" AND (").append(selection).append(")"); 336824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 336924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro count = updateContactOptions(values, profileSelection.toString(), selectionArgs, 337024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro callerIsSyncAdapter); 337124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 337224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 337324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 33742e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP: 33752e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP_ID: { 33762e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 33772e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 33782e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 3379fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 3380fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 33812e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 33822e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 33832e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final long contactId = lookupContactIdByLookupKey(mDb, lookupKey); 3384dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(contactId, values, callerIsSyncAdapter); 33852e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey break; 33862e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 33872e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 33887d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh case RAW_CONTACTS_DATA: { 33897d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh final String rawContactId = uri.getPathSegments().get(1); 33907d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ") 33917d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh + (selection == null ? "" : " AND " + selection); 33927d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 33937d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter); 33947d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 33957d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh break; 33967d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh } 33977d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 339820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3399944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong count = updateData(uri, values, appendAccountToSelection(uri, selection), 3400f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 340181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3402f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 340381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 340420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 340520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3406c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 340748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 340848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 340948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 341048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3411f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter); 341281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3413f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 341481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 341500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 341600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 34177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 34185ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 34195ac5c70d1165309302ebcc931f51723e37d31e0bJeff Sharkey selection = appendAccountToSelection(uri, selection); 3420dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, selection, selectionArgs, callerIsSyncAdapter); 34217e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 34227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 34237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 34245ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 342533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 34264529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (selection != null) { 34274da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 34284da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov count = updateRawContacts(values, RawContacts._ID + "=?" 3429dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND(" + selection + ")", selectionArgs, 3430dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 34314529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } else { 34324da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 3433dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1, 3434dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 34354529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 34367e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 34377e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 34387e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 3439ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 34405aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, appendAccountToSelection(uri, selection), 3441f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 344281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3443f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 344481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3445ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3446ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3447ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3448ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3449ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 34504da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId)); 34514da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String selectionWithId = Groups._ID + "=? " 345273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov + (selection == null ? "" : " AND " + selection); 34535aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, selectionWithId, selectionArgs, 34545aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey callerIsSyncAdapter); 345581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3456f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 345781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3458ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3459ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3460ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3461127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 3462de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov count = updateAggregationException(mDb, values); 3463b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 3464b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3465b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 3466eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 3467e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey count = updateSettings(uri, values, appendAccountToSelection(uri, selection), 3468e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey selectionArgs); 346943880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3470eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 3471eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3472eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 34739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori case STATUS_UPDATES: { 34749705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori count = updateStatusUpdate(uri, values, selection, selectionArgs); 34759705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori break; 34769705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 34779705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 34783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 34793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, selection, selectionArgs); 34803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 34813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 34843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, StreamItemsColumns.CONCRETE_ID + "=?", 34853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 34863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 34873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 34903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, selection, selectionArgs); 34913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 34923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 34953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 34963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 34973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{streamItemId}); 34983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 34993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 35023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 35033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 35043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 35053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " + 35063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?", 35073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 35083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 351172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov case DIRECTORIES: { 3512bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanPackagesByUid(Binder.getCallingUid()); 351372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov count = 1; 3514d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 3515d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 3516d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 351746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa case DATA_USAGE_FEEDBACK_ID: { 351846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (handleDataUsageFeedback(uri)) { 351946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 1; 352046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 352146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 0; 352246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 352346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa break; 352446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 352546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 352681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 352781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 3528f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 352981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 353000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 353100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 353200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 35334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 35344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 35359705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private int updateStatusUpdate(Uri uri, ContentValues values, String selection, 35369705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori String[] selectionArgs) { 35379705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // update status_updates table, if status is provided 35389705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 35399705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori int updateCount = 0; 35409705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values); 35419705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 35429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori updateCount = mDb.update(Tables.STATUS_UPDATES, 35439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues, 35449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori getWhereClauseForStatusUpdatesTable(selection), 35459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 35469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 35489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // now update the Presence table 35499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues = getSettableColumnsForPresenceTable(values); 35509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 35519705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori updateCount = mDb.update(Tables.PRESENCE, settableValues, 35529705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selection, selectionArgs); 35539705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35549705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO updateCount is not entirely a valid count of updated rows because 2 tables could 35559705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // potentially get updated in this method. 35569705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return updateCount; 35579705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35589705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 35593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItems(Uri uri, ContentValues values, String selection, 35603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 35613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream items can't be moved to a new raw contact. 35623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItems.RAW_CONTACT_ID); 35633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream items being updated belong to the account. 35653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 35663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItems(account, selection, selectionArgs); 35673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream items table. 35696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 35706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 35716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 35723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If there's been no exception, the update should be fine. 35733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.update(Tables.STREAM_ITEMS, values, selection, selectionArgs); 35743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItemPhotos(Uri uri, ContentValues values, String selection, 35773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 35783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream item photos can't be moved to a new stream item. 35793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItemPhotos.STREAM_ITEM_ID); 35803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream item photos being updated belong to the account. 35823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 35833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 35843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream item 35866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 35876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 35886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 35896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 35906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo (since we're updating, it's valid for the photo to not be present). 35916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(values, true)) { 35926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // If there's been no exception, the update should be fine. 35936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return mDb.update(Tables.STREAM_ITEM_PHOTOS, values, selection, selectionArgs); 35946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 35956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 35963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35989705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori /** 35999705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori * Build a where clause to select the rows to be updated in status_updates table. 36009705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori */ 36019705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private String getWhereClauseForStatusUpdatesTable(String selection) { 36029705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.setLength(0); 36039705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE); 36049705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(selection); 36059705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(")"); 36069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mSb.toString(); 36079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) { 36109705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 36119705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values, 36129705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS); 36139705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values, 36149705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_TIMESTAMP); 36159705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values, 36169705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_RES_PACKAGE); 36179705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values, 36189705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_LABEL); 36199705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values, 36209705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_ICON); 36219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 36229705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36239705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36249705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForPresenceTable(ContentValues values) { 36259705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 36269705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values, 36279705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.PRESENCE); 3628aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.CHAT_CAPABILITY, values, 3629aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori StatusUpdates.CHAT_CAPABILITY); 36309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 36319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36335aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int updateGroups(Uri uri, ContentValues values, String selectionWithId, 3634f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 363573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3636ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3637ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov 363873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov ContentValues updatedValues; 3639f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter && !values.containsKey(Groups.DIRTY)) { 364073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = mValues; 364173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.clear(); 364273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.putAll(values); 364373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.put(Groups.DIRTY, 1); 364473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } else { 364573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = values; 364673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 364773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3648ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey int count = mDb.update(Tables.GROUPS, updatedValues, selectionWithId, selectionArgs); 36491a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) { 36501a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 365194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 36526ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi if (updatedValues.containsKey(Groups.SHOULD_SYNC) 36531129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) { 36546ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups.ACCOUNT_NAME, 3655e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey Groups.ACCOUNT_TYPE}, selectionWithId, selectionArgs, null, 36566ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi null, null); 36576ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountName; 36586ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountType; 36596ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi try { 36606ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi while (c.moveToNext()) { 36616ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountName = c.getString(0); 36626ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountType = c.getString(1); 366324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 36646ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Account account = new Account(accountName, accountType); 3665ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov ContentResolver.requestSync(account, ContactsContract.AUTHORITY, 36666ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi new Bundle()); 36676ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi break; 36686ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 36696ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 36706ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } finally { 36716ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi c.close(); 36726ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 36736ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 367494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana return count; 367594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 367694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 3677b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private int updateSettings(Uri uri, ContentValues values, String selection, 3678b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov String[] selectionArgs) { 3679e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final int count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs); 36801a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 36811a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3682e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3683e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3684e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3685e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3686dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs, 3687dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 36884529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (values.containsKey(RawContacts.CONTACT_ID)) { 36894529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " + 36904529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov "in content values. Contact IDs are assigned automatically"); 36914529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 369273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 369397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 369497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 369597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0"); 369697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 369797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 36984529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov int count = 0; 3699ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.RAW_CONTACTS, 370051bf5ea9531b9da72caff607dbdf35fd6f61cbe2Jeff Sharkey new String[] { RawContacts._ID }, selection, 37014529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov selectionArgs, null, null, null); 37024529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov try { 37034529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov while (cursor.moveToNext()) { 37044529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov long rawContactId = cursor.getLong(0); 3705dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateRawContact(rawContactId, values, callerIsSyncAdapter); 37064529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov count++; 37074529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37084529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } finally { 37094529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov cursor.close(); 37104529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37114529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 37124529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov return count; 37134529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37144529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 3715dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContact(long rawContactId, ContentValues values, 3716dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 371724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 371824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Enforce profile permissions if the raw contact is in the user's profile. 3719afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 372024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 372196b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker final String selection = RawContacts._ID + " = ?"; 372296b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(rawContactId); 372319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED) 372419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka && values.getAsInteger(RawContacts.DELETED) == 0); 372519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int previousDeleted = 0; 3726ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType = null; 3727ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName = null; 372819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete) { 372919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka Cursor cursor = mDb.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, selection, 373096b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1, null, null, null); 373119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka try { 373219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (cursor.moveToFirst()) { 373319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka previousDeleted = cursor.getInt(RawContactsQuery.DELETED); 3734ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE); 3735ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME); 373619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 373719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } finally { 373819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka cursor.close(); 373919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 374019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 374119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT); 374219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 3743f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 374496b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker int count = mDb.update(Tables.RAW_CONTACTS, values, selection, mSelectionArgs1); 37455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count != 0) { 3746f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (values.containsKey(RawContacts.AGGREGATION_MODE)) { 3747f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = values.getAsInteger(RawContacts.AGGREGATION_MODE); 3748f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov 3749f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // As per ContactsContract documentation, changing aggregation mode 3750f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // to DEFAULT should not trigger aggregation 3751f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) { 375269cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, aggregationMode, false); 3753f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 3754f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 3755433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey if (values.containsKey(RawContacts.STARRED)) { 3756dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 3757dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 3758dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana values.getAsLong(RawContacts.STARRED) != 0); 3759dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 37604529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov mContactAggregator.updateStarred(rawContactId); 3761dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 3762dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then update the 3763dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // favorites group membership based on whether or not this contact is starred. 3764dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // If it is starred, add a group membership, if one doesn't already exist 3765dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // otherwise delete any matching group memberships. 3766dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 3767dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean starred = 0 != DatabaseUtils.longForQuery(mDb, 3768dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana SELECTION_STARRED_FROM_RAW_CONTACTS, 3769dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}); 3770dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred); 3771dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3772dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3773dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3774dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then add a 3775dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // group membership to the group marked as AutoAdd, if any. 3776dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 3777dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 3778433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey } 3779dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3780285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov if (values.containsKey(RawContacts.SOURCE_ID)) { 37812b7a632bba423357ae5641f94da6a2f71afc523bDmitri Plotnikov mContactAggregator.updateLookupKeyForRawContact(mDb, rawContactId); 3782285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 3783f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.containsKey(RawContacts.NAME_VERIFIED)) { 3784f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 3785f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // If setting NAME_VERIFIED for this raw contact, reset it for all 3786f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // other raw contacts in the same aggregate 3787f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) { 378878fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.resetNameVerifiedForOtherRawContacts(rawContactId); 3789f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 3790f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov mContactAggregator.updateDisplayNameForRawContact(mDb, rawContactId); 3791f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 379219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete && previousDeleted == 1) { 3793d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.rawContactInserted(rawContactId, 3794d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov new Account(accountName, accountType)); 379519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 37965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 37975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return count; 379833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 379933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 3800321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana private int updateData(Uri uri, ContentValues values, String selection, 3801f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 380220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 380320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 380420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data._ID); 38055ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov mValues.remove(Data.RAW_CONTACT_ID); 380620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 380720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 380820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String packageName = values.getAsString(Data.RES_PACKAGE); 380920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (packageName != null) { 381020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 3811b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 381220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 381320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 381497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 381597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 381697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov Data.IS_READ_ONLY + "=0"); 381797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 381897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 3819653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov int count = 0; 382020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3821653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 3822653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // so we don't need to worry about updating data we don't have permission to read. 3823f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // This query will be allowed to return profiles, and we'll do the permission check 3824f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // within the loop. 38256ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Cursor c = queryLocal(uri.buildUpon() 3826f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "1").build(), 3827f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro DataRowHandler.DataUpdateQuery.COLUMNS, 38286ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro selection, selectionArgs, null, -1 /* directory ID */, 38296ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro true /* suppress profile check */); 3830653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov try { 3831653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov while(c.moveToNext()) { 383224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check profile permission for the raw contact that owns each data record. 383324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = c.getLong(DataRowHandler.DataUpdateQuery.RAW_CONTACT_ID); 3834afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 383524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 3836f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count += updateData(mValues, c, callerIsSyncAdapter); 383720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3838653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov } finally { 3839653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov c.close(); 384020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 384120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3842653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return count; 384320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 384420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3845f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) { 3846653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov if (values.size() == 0) { 3847653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return 0; 3848321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 3849653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov 3850f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String mimeType = c.getString(DataRowHandler.DataUpdateQuery.MIMETYPE); 3851a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 3852f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean updated = 3853f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro rowHandler.update(mDb, mTransactionContext, values, c, callerIsSyncAdapter); 3854f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) { 3855f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 3856a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov } 3857f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return updated ? 1 : 0; 3858321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 3859321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana 38608c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov private int updateContactOptions(ContentValues values, String selection, 3861dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 38628c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov int count = 0; 3863ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.CONTACTS, 386424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[] { Contacts._ID, Contacts.IS_USER_PROFILE }, selection, 38658c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov selectionArgs, null, null, null); 38668c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov try { 38678c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov while (cursor.moveToNext()) { 38688c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov long contactId = cursor.getLong(0); 386924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 387024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for profile write permission before updating a user's profile contact. 387124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean isProfile = cursor.getInt(1) == 1; 387224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (isProfile) { 387324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(true); 387424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 387524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 3876dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateContactOptions(contactId, values, callerIsSyncAdapter); 38778c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov count++; 38788c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 38798c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } finally { 38808c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov cursor.close(); 38818c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 38828c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 38838c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov return count; 38848c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 38858c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 3886dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateContactOptions(long contactId, ContentValues values, 3887dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 3888d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 388924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check write permission if the contact is the user's profile. 3890afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(mDb, contactId, true); 389124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 38928c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 3893b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 3894d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 3895b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 3896d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 3897b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 3898d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 3899b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 3900d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 3901b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 3902d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.STARRED); 3903d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 3904d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 39058c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.size() == 0) { 3906d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 3907d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 3908d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 39098c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.containsKey(RawContacts.STARRED)) { 3910c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey // Mark dirty when changing starred to trigger sync 39118c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3912c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey } 3913c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey 39144da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(contactId); 391597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov mDb.update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?" 391697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov + " AND " + RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0", mSelectionArgs1); 39178c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 3918dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (mValues.containsKey(RawContacts.STARRED) && !callerIsSyncAdapter) { 3919ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.RAW_CONTACTS, 3920dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=?", 3921dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mSelectionArgs1, null, null, null); 3922dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 3923dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (cursor.moveToNext()) { 3924dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana long rawContactId = cursor.getLong(0); 3925dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 3926dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mValues.getAsLong(RawContacts.STARRED) != 0); 3927dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3928dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 3929dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana cursor.close(); 3930dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3931dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3932dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 39338c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // Copy changeable values to prevent automatically managed fields from 39348c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // being explicitly updated by clients. 39358c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 3936b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 39378c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 3938b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 39398c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 3940b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 39418c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 3942b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 39438c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 3944b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 39458c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.STARRED); 39468c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 39479b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori int rslt = mDb.update(Tables.CONTACTS, mValues, Contacts._ID + "=?", mSelectionArgs1); 39486e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori 39499b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori if (values.containsKey(Contacts.LAST_TIME_CONTACTED) && 39509b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori !values.containsKey(Contacts.TIMES_CONTACTED)) { 39519b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 39529b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 39539b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori } 39549b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori return rslt; 3955f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 3956d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 3957127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 3958127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 39590c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1); 39600c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2); 396180c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 3962ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId1; 3963ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId2; 39640c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (rcId1 < rcId2) { 39650c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId1; 39660c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId2; 39670c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 39680c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId1; 39690c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId2; 3970b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3971127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 39720c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 39734da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[0] = String.valueOf(rawContactId1); 39744da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[1] = String.valueOf(rawContactId2); 39750c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, 39764da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov AggregationExceptions.RAW_CONTACT_ID1 + "=? AND " 39774da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2); 39780c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 39796bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 39806bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 39810c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 39820c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 39830c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 39840c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues); 3985127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 3986127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 39873389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov mContactAggregator.invalidateAggregationExceptionCache(); 398869cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId1, 398969cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 399069cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId2, 399169cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 3992dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov 3993bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateContact(mTransactionContext, db, rawContactId1); 3994bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateContact(mTransactionContext, db, rawContactId2); 3995127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 3996127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 3997127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 3998127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 3999b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4000b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 400170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong public void onAccountsUpdated(Account[] accounts) { 4002bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 40033826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 40043826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4005bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected boolean updateAccountsInBackground(Account[] accounts) { 4006f8536aaa7a52b9a7a353bc54e158becdbe79ec87Bai Tao // TODO : Check the unit test. 4007e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov boolean accountsChanged = false; 4008627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov HashSet<Account> existingAccounts = new HashSet<Account>(); 400949d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov mDb = mDbHelper.getWritableDatabase(); 401070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.beginTransaction(); 401170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong try { 4012dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana findValidAccounts(existingAccounts); 4013743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov 4014743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov // Add a row to the ACCOUNTS table for each new account 4015743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov for (Account account : accounts) { 4016743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov if (!existingAccounts.contains(account)) { 4017e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 4018743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov mDb.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 4019743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov + ", " + RawContacts.ACCOUNT_TYPE + ") VALUES (?, ?)", 4020743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov new String[] {account.name, account.type}); 4021743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 4022743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 402348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 4024627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov // Remove all valid accounts from the existing account set. What is left 4025743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov // in the accountsToDelete set will be extra accounts whose data must be deleted. 4026627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov HashSet<Account> accountsToDelete = new HashSet<Account>(existingAccounts); 4027627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (Account account : accounts) { 4028627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov accountsToDelete.remove(account); 402970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 403070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong 403133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov if (!accountsToDelete.isEmpty()) { 4032e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 4033e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov for (Account account : accountsToDelete) { 4034e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov Log.d(TAG, "removing data for removed account " + account); 4035e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov String[] params = new String[] {account.name, account.type}; 4036e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4037e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.GROUPS + 4038e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Groups.ACCOUNT_NAME + " = ?" + 4039e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + Groups.ACCOUNT_TYPE + " = ?", params); 4040e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4041e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.PRESENCE + 4042e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" + 4043e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "SELECT " + RawContacts._ID + 4044e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 4045e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 4046e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + RawContacts.ACCOUNT_TYPE + " = ?)", params); 4047e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4048e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.RAW_CONTACTS + 4049e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 4050e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + RawContacts.ACCOUNT_TYPE + " = ?", params); 4051e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4052e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.SETTINGS + 4053e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Settings.ACCOUNT_NAME + " = ?" + 4054e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + Settings.ACCOUNT_TYPE + " = ?", params); 4055e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4056e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.ACCOUNTS + 4057e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + "=?" + 4058e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + RawContacts.ACCOUNT_TYPE + "=?", params); 4059d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov mDb.execSQL( 4060d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov "DELETE FROM " + Tables.DIRECTORIES + 4061d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov " WHERE " + Directory.ACCOUNT_NAME + "=?" + 4062d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov " AND " + Directory.ACCOUNT_TYPE + "=?", params); 40634458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov resetDirectoryCache(); 4064e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 4065e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov 406633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // Find all aggregated contacts that used to contain the raw contacts 406733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // we have just deleted and see if they are still referencing the deleted 4068e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov // names or photos. If so, fix up those contacts. 406933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov HashSet<Long> orphanContactIds = Sets.newHashSet(); 407033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Cursor cursor = mDb.rawQuery("SELECT " + Contacts._ID + 407133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " FROM " + Tables.CONTACTS + 407233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " WHERE (" + Contacts.NAME_RAW_CONTACT_ID + " NOT NULL AND " + 407369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov Contacts.NAME_RAW_CONTACT_ID + " NOT IN " + 407469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + RawContacts._ID + 407569cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + "))" + 407633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " OR (" + Contacts.PHOTO_ID + " NOT NULL AND " + 407733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Contacts.PHOTO_ID + " NOT IN " + 407869cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + Data._ID + 407969cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.DATA + "))", null); 408033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov try { 408133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov while (cursor.moveToNext()) { 408233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov orphanContactIds.add(cursor.getLong(0)); 408333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 408433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } finally { 408533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov cursor.close(); 408633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 408733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 408833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov for (Long contactId : orphanContactIds) { 4089bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.updateAggregateData(mTransactionContext, contactId); 409033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 4091e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDbHelper.updateAllVisible(); 4092bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 409333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 409433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 4095e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov if (accountsChanged) { 4096e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDbHelper.getSyncState().onAccountsChanged(mDb, accounts); 4097e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 409870d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.setTransactionSuccessful(); 409970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } finally { 410070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.endTransaction(); 410170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 410273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.clear(); 41033826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 41043826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (accountsChanged) { 41053826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateContactsAccountCount(accounts); 41063826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 41073826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41083826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4109afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov return accountsChanged; 411070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 4111619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 41123826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateContactsAccountCount(Account[] accounts) { 41133826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov int count = 0; 41143826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov for (Account account : accounts) { 41153826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (isContactsAccount(account)) { 41163826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov count++; 41173826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41183826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41193826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mContactsAccountCount = count; 41203826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41213826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 41223826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov protected boolean isContactsAccount(Account account) { 41233826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov final IContentService cs = ContentResolver.getContentService(); 41243826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov try { 41253826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0; 41263826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } catch (RemoteException e) { 41273826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov Log.e(TAG, "Cannot obtain sync flag for account: " + account, e); 41283826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return false; 41293826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41303826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41313826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 413272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void onPackageChanged(String packageName) { 4133bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_DIRECTORIES, packageName); 4134d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4135d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4136619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 4137627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov * Finds all distinct accounts present in the specified table. 4138627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov */ 4139dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void findValidAccounts(Set<Account> validAccounts) { 4140743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov Cursor c = mDb.rawQuery( 4141743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov "SELECT " + RawContacts.ACCOUNT_NAME + "," + RawContacts.ACCOUNT_TYPE + 4142743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov " FROM " + Tables.ACCOUNTS, null); 4143627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 4144627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov while (c.moveToNext()) { 4145dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!c.isNull(0) || !c.isNull(1)) { 4146627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov validAccounts.add(new Account(c.getString(0), c.getString(1))); 4147627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4148627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4149627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } finally { 4150627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov c.close(); 4151627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4152627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4153627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov 41544f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 41554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 41564f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 415715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 415815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mReadAccessLatch); 415915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 4160d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY); 4161385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directory == null) { 41623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 41636ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1, false)); 4164385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directory.equals("0")) { 41653716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 41663716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 41676ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Directory.DEFAULT, false)); 4168d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } else if (directory.equals("1")) { 41693716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 41703716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 41716ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Directory.LOCAL_INVISIBLE, false)); 4172d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4173d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4174d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov DirectoryInfo directoryInfo = getDirectoryAuthority(directory); 4175d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo == null) { 4176a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov Log.e(TAG, "Invalid directory ID: " + uri); 4177a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov return null; 4178d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4179d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4180d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Builder builder = new Uri.Builder(); 4181d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.scheme(ContentResolver.SCHEME_CONTENT); 4182d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.authority(directoryInfo.authority); 4183d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.encodedPath(uri.getEncodedPath()); 4184d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountName != null) { 4185d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName); 4186d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4187d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountType != null) { 4188d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType); 4189d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 41902e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 41912e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limit = getLimit(uri); 41922e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov if (limit != null) { 41932e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit); 41942e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov } 41952e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 4196d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Uri directoryUri = builder.build(); 419709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 419809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov if (projection == null) { 419909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov projection = getDefaultProjection(uri); 420009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 420109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 4202332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov Cursor cursor = getContext().getContentResolver().query(directoryUri, projection, selection, 4203d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov selectionArgs, sortOrder); 42046ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 42056ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (cursor == null) { 42066ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 42076ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42086ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 4209547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro CrossProcessCursor crossProcessCursor = getCrossProcessCursor(cursor); 4210547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (crossProcessCursor != null) { 4211547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return wrapCursor(uri, cursor); 4212547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } else { 4213547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return matrixCursorFromCursor(wrapCursor(uri, cursor)); 4214547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 42153716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 42163716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4217547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro private Cursor wrapCursor(Uri uri, Cursor cursor) { 4218547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 4219547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro // If the cursor doesn't contain a snippet column, don't bother wrapping it. 4220547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (cursor.getColumnIndex(SearchSnippetColumns.SNIPPET) < 0) { 4221547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return cursor; 4222547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 4223547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 42243716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Parse out snippet arguments for use when snippets are retrieved from the cursor. 42253716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String[] args = null; 42263716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String snippetArgs = 42273716f1447ceb21180d1301790eabd8b9453f486dDave Santoro getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 42283716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (snippetArgs != null) { 42293716f1447ceb21180d1301790eabd8b9453f486dDave Santoro args = snippetArgs.split(","); 42303716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 42313716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 42323716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String query = uri.getLastPathSegment(); 42333716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String startMatch = args != null && args.length > 0 ? args[0] 42343716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_START_MATCH; 42353716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String endMatch = args != null && args.length > 1 ? args[1] 42363716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_END_MATCH; 42373716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String ellipsis = args != null && args.length > 2 ? args[2] 42383716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_ELLIPSIS; 42393716f1447ceb21180d1301790eabd8b9453f486dDave Santoro int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 42403716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 42413716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4242547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return new SnippetizingCursorWrapper(cursor, query, startMatch, endMatch, ellipsis, 4243547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro maxTokens); 42446ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42456ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 42466ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov private CrossProcessCursor getCrossProcessCursor(Cursor cursor) { 42476ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov Cursor c = cursor; 42486ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (c instanceof CrossProcessCursor) { 42496ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return (CrossProcessCursor) c; 42506ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else if (c instanceof CursorWindow) { 42516ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return getCrossProcessCursor(((CursorWrapper) c).getWrappedCursor()); 42526ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else { 42536ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 42546ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42556ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42566ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 42576ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov public MatrixCursor matrixCursorFromCursor(Cursor cursor) { 42586ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); 42596ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov int numColumns = cursor.getColumnCount(); 42606ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov String data[] = new String[numColumns]; 42616ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov cursor.moveToPosition(-1); 42626ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov while (cursor.moveToNext()) { 42636ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov for (int i = 0; i < numColumns; i++) { 42646ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov data[i] = cursor.getString(i); 42656ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42666ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov newCursor.addRow(data); 4267332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov } 42686ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return newCursor; 4269d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4270d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4271d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final class DirectoryQuery { 4272d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final String[] COLUMNS = new String[] { 4273d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory._ID, 4274d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.DIRECTORY_AUTHORITY, 4275d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_NAME, 4276d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_TYPE 4277d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov }; 4278d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4279d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int DIRECTORY_ID = 0; 4280d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int AUTHORITY = 1; 4281d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_NAME = 2; 4282d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_TYPE = 3; 4283d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4284d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4285d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 4286d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Reads and caches directory information for the database. 4287d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 4288d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private DirectoryInfo getDirectoryAuthority(String directoryId) { 42894458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized (mDirectoryCache) { 42904458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov if (!mDirectoryCacheValid) { 42914458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.clear(); 429249d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov SQLiteDatabase db = mDbHelper.getReadableDatabase(); 429349d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Cursor cursor = db.query(Tables.DIRECTORIES, 42944458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryQuery.COLUMNS, 42954458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov null, null, null, null, null); 42964458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov try { 42974458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov while (cursor.moveToNext()) { 42984458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryInfo info = new DirectoryInfo(); 42994458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov String id = cursor.getString(DirectoryQuery.DIRECTORY_ID); 43004458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.authority = cursor.getString(DirectoryQuery.AUTHORITY); 43014458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME); 43024458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE); 43034458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.put(id, info); 43044458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 43054458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } finally { 43064458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov cursor.close(); 4307d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 43084458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = true; 4309d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4310d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 43114458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov return mDirectoryCache.get(directoryId); 43124458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 4313d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4314d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 431572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void resetDirectoryCache() { 43164458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized(mDirectoryCache) { 43174458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = false; 43184458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 431972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 432072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 43216ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private Cursor queryLocal(Uri uri, String[] projection, String selection, 43226ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro String[] selectionArgs, String sortOrder, long directoryId, 43236ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean suppressProfileCheck) { 4324bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 4325bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov Log.v(TAG, "query: " + uri); 4326bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov } 43270b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov 4328b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 432935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4330d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 43311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 4332c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov String limit = getLimit(uri); 4333c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 4334a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 43354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 433635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 4337b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().query(db, projection, selection, selectionArgs, 433835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana sortOrder); 433935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4340d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 4341763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 434224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean existingWhere = appendLocalDirectorySelectionIfNeeded(qb, directoryId); 43436ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, Contacts.IS_USER_PROFILE, existingWhere, 43446ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 43456ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro sortOrder = prependProfileSortIfNeeded(uri, sortOrder, suppressProfileCheck); 4346619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 4347619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 4348619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 4349d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 43504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 4351afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 4352763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 43534da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 43544da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 43556bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 43566bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 43576bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 43585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP: 43595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP_ID: { 43605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 43615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = pathSegments.size(); 43625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount < 3) { 4363fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 4364fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 43655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 4366a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 43675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String lookupKey = pathSegments.get(2); 43685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount == 4) { 43695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4370afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 43715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4372763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 4373a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4374a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4375a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4376a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 4377a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 43785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return c; 43795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 43805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 43815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 4382763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 43834da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 43844da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 43854da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 43865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 43875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 43885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 43892149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_DATA: 43902149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_ID_DATA: { 43912149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 43922149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov int segmentCount = pathSegments.size(); 43932149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount < 4) { 43942149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 43952149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov "Missing a lookup key", uri)); 43962149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 43972149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov String lookupKey = pathSegments.get(2); 43982149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount == 5) { 43992149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4400afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44012149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 44022149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(lookupQb, uri, projection, false); 4403a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 4404a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4405a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4406a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Data.CONTACT_ID, contactId, Data.LOOKUP_KEY, lookupKey); 4407a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 44082149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov return c; 44092149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44102149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 44112149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov // TODO see if the contact exists but has no data rows (rare) 44122149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44132149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 44142149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 441524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 4416afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44172149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 441824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 44192149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov qb.appendWhere(" AND " + Data.CONTACT_ID + "=?"); 44202149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov break; 44212149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44222149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 44233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_ID_STREAM_ITEMS: { 44243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4425afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 44273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 44283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContactsColumns.CONCRETE_CONTACT_ID + "=?"); 44293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 44303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 44323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_STREAM_ITEMS: 44333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_ID_STREAM_ITEMS: { 44343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<String> pathSegments = uri.getPathSegments(); 44353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int segmentCount = pathSegments.size(); 44363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount < 4) { 44373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new IllegalArgumentException(mDbHelper.exceptionMessage( 44383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann "Missing a lookup key", uri)); 44393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String lookupKey = pathSegments.get(2); 44413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount == 5) { 44423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(pathSegments.get(3)); 4443afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 44453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(lookupQb); 44463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 44473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann projection, selection, selectionArgs, sortOrder, groupBy, limit, 44483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RawContacts.CONTACT_ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 44493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c != null) { 44503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return c; 44513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 44543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 44553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = lookupContactIdByLookupKey(db, lookupKey); 4456afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 44583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContacts.CONTACT_ID + "=?"); 44593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 44603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4462f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: { 446342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKey = Uri.encode(uri.getPathSegments().get(2)); 446424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 4465afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 4466ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 4467f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey qb.setProjectionMap(sContactsVCardProjectionMap); 44684da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 446924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 44704da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 4471f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey break; 4472f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey } 4473f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey 447442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 447542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); 447642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann String currentDateString = dateFormat.format(new Date()).toString(); 447742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann return db.rawQuery( 447842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann "SELECT" + 447942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " 'vcards_' || ? || '.vcf' AS " + OpenableColumns.DISPLAY_NAME + "," + 448042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " NULL AS " + OpenableColumns.SIZE, 448142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann new String[] { currentDateString }); 448242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 448342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 4484ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_FILTER: { 4485916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov String filterParam = ""; 4486ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 4487916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov filterParam = uri.getLastPathSegment(); 4488ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 44897ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov setTablesAndProjectionMapForContactsWithSnippet( 44907ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov qb, uri, projection, filterParam, directoryId); 44916ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, Contacts.IS_USER_PROFILE, false, 44926ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 44936ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro sortOrder = prependProfileSortIfNeeded(uri, sortOrder, suppressProfileCheck); 4494ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4495ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4496ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 4497ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT_FILTER: 4498ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT: { 44992f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Basically the resultant SQL should look like this: 45002f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing starred items) 45012f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 45022f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing frequently contacted items) 45032f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // ORDER BY ... 45042f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 45052f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final boolean phoneOnly = readBooleanQueryParameter( 45062f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa uri, ContactsContract.STREQUENT_PHONE_ONLY, false); 45072f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (match == CONTACTS_STREQUENT_FILTER && uri.getPathSegments().size() > 3) { 45084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 45094a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4510e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(Contacts._ID + " IN "); 45115e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov appendContactFilterAsNestedQuery(sb, filterParam); 45122f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection = DbQueryUtils.concatenateClauses(selection, sb.toString()); 45134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 45144a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 45152f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] subProjection = null; 45165e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection != null) { 45172f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa subProjection = appendProjectionArg(projection, TIMES_USED_SORT_COLUMN); 45185e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 45195e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 45204a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov // Build the first query for starred 45214928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 45224928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(phoneOnly ? 45234928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa sStrequentPhoneOnlyStarredProjectionMap 45244928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa : sStrequentStarredProjectionMap); 45252f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 45262f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection, Contacts.IS_USER_PROFILE + "=0")); 45272f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 45282f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String starredQuery = qb.buildQuery(subProjection, 452924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Contacts.STARRED + "=1", Contacts._ID, null, null, null); 4530d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 45312f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Reset the builder. 4532d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 45332f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 45344928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 45354928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // Build the second query for frequent part. 45364928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final String frequentQuery; 45374928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (phoneOnly) { 45384928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final StringBuilder tableBuilder = new StringBuilder(); 45394928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // In phone only mode, we need to look at view_data instead of 45404928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // contacts/raw_contacts to obtain actual phone numbers. One problem is that 45414928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data is much larger than view_contacts, so our query might become much 45424928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // slower. 45434928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // 45444928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // To avoid the possible slow down, we start from data usage table and join 45454928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data to the table, assuming data usage table is quite smaller than 45464928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // data rows (almost always it should be), and we don't want any phone 45474928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // numbers not used by the user. This way sqlite is able to drop a number of 45484928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // rows in view_data in the early stage of data lookup. 45494928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa tableBuilder.append(Tables.DATA_USAGE_STAT 45504928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " INNER JOIN " + Views.DATA + " " + Tables.DATA 45514928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" 45524928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataColumns.CONCRETE_ID + " AND " 45534928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" 45544928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT_CALL + ")"); 45554928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactPresenceJoin(tableBuilder, projection, RawContacts.CONTACT_ID); 45564928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactStatusUpdateJoin(tableBuilder, projection, 45574928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa ContactsColumns.LAST_STATUS_UPDATE_ID); 45584928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 45594928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setTables(tableBuilder.toString()); 45604928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentPhoneOnlyFrequentProjectionMap); 45614928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 45624928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 45634928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.STARRED + "=0 OR " + Contacts.STARRED + " IS NULL", 45644928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa MimetypesColumns.MIMETYPE + " IN (" 45654928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + Phone.CONTENT_ITEM_TYPE + "', " 45664928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + SipAddress.CONTENT_ITEM_TYPE + "')")); 45674928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, null, null, null, null, null); 45684928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } else { 45694928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 45704928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 45714928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 45724928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 45734928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa "(" + Contacts.STARRED + " =0 OR " + Contacts.STARRED + " IS NULL)", 45744928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.IS_USER_PROFILE + "=0")); 45754928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, 45764928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa null, Contacts._ID, null, null, null); 45774928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } 4578d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 4579d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 45802f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String unionQuery = 45812f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, 45822f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa STREQUENT_ORDER_BY, STREQUENT_LIMIT); 45832f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 45842f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Here, we need to use selection / selectionArgs (supplied from users) "twice", 45852f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // as we want them both for starred items and for frequently contacted items. 45862f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // 45872f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // e.g. if the user specify selection = "starred =?" and selectionArgs = "0", 45882f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // the resultant SQL should be like: 45892f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 45902f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 45912f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 45922f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] doubledSelectionArgs = null; 45932f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (selectionArgs != null) { 45942f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final int length = selectionArgs.length; 45952f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa doubledSelectionArgs = new String[length * 2]; 45967d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, 0, length); 45977d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, length, length); 45982f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 45992f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 46002f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa Cursor cursor = db.rawQuery(unionQuery, doubledSelectionArgs); 46012f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (cursor != null) { 46022f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa cursor.setNotificationUri(getContext().getContentResolver(), 4603d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 4604d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 46052f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa return cursor; 4606d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 4607d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 4608ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_GROUP: { 4609763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 4610b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 461171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 46124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 4613b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4614b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 4615b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4616b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 461724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 461824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 461924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 462024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(Contacts.IS_USER_PROFILE + "=1"); 462124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 462224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 462324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 462424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: { 462524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 462624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForEntities(qb, uri, projection); 462724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + Contacts.IS_USER_PROFILE + "=1"); 462824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 462924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 463024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 463124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: { 463224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 463324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 463424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 463524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 463624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 463724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 463824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA_ID: { 463924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 464024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 464124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 464224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + Data._ID + "=? AND " 464324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 464424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 464524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 464624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 464724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: { 464824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 4649ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 465024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.setProjectionMap(sContactsVCardProjectionMap); 465124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(Contacts.IS_USER_PROFILE + "=1"); 465224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 465324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 465424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 4655a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_DATA: { 46564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 465782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 46584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 46594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 46606bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 46616bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 466200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 4663a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 46643653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4665afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 466682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 46674da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 46684da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 46693653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 46703653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov break; 46713653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov } 46723653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 4673a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_ENTITIES: { 4674a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4675a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 4676a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 4677a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 4678a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 4679a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4680a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4681a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ENTITIES: 4682a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ID_ENTITIES: { 4683a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 4684a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov int segmentCount = pathSegments.size(); 4685a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount < 4) { 4686a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 4687a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov "Missing a lookup key", uri)); 4688a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4689a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lookupKey = pathSegments.get(2); 4690a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount == 5) { 4691a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4692a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4693a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(lookupQb, uri, projection); 4694a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 4695a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4696a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4697a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4698a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.CONTACT_ID, contactId, 4699a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.LOOKUP_KEY, lookupKey); 4700a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 4701a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 4702a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4703a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4704a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4705a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 4706a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 4707a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 4708a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + Contacts.Entity.CONTACT_ID + "=?"); 4709a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 4710a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4711a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 47123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 47133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 47143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 47183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 47193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 47203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemsColumns.CONCRETE_ID + "=?"); 47213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_LIMIT: { 47256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro MatrixCursor cursor = new MatrixCursor(new String[]{StreamItems.MAX_ITEMS}, 1); 47266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro cursor.addRow(new Object[]{MAX_STREAM_ITEMS_PER_RAW_CONTACT}); 47273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return cursor; 47283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 47313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 47323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 47363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 47373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 47383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 47393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?"); 47403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 47443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 47453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 47463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 47473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemPhotoId); 47483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 47493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=? AND " + 47503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=?"); 47513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4754f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case PHOTO_DIMENSIONS: { 4755f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro MatrixCursor cursor = new MatrixCursor( 4756f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM}, 4757f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1); 4758f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cursor.addRow(new Object[]{mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim}); 4759f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return cursor; 4760f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 4761f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 47624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case PHONES: { 476382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 476489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 47652815f58f72f109790585931f601a63ddc02536a5Evan Millar break; 47662815f58f72f109790585931f601a63ddc02536a5Evan Millar } 47672815f58f72f109790585931f601a63ddc02536a5Evan Millar 476848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: { 476982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 47704da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 477148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 47724da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 477348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 477448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 477548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 4776ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES_FILTER: { 477746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 477846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 477946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 478046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_CALL; 478146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 478246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 478389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 4784ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 47854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 47864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4787a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(" AND ("); 47885e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 478945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov boolean hasCondition = false; 47905e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov boolean orNeeded = false; 47915e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov String normalizedName = NameNormalizer.normalize(filterParam); 47925e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (normalizedName.length() > 0) { 4793155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(Data.RAW_CONTACT_ID + " IN " + 4794155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 4795155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 4796155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 4797155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 4798155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 4799155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 48002352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 4801155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 48025e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov orNeeded = true; 480345d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 48045e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 48055e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 4806892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String number = PhoneNumberUtils.normalizeNumber(filterParam); 4807892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (!TextUtils.isEmpty(number)) { 48085e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (orNeeded) { 48095e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(" OR "); 48105e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 48115e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(Data._ID + 4812892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID 4813892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " FROM " + Tables.PHONE_LOOKUP 4814892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 4815892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append(number); 4816892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append("%')"); 481745d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 481845d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov } 481945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov 482045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov if (!hasCondition) { 482145d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // If it is neither a phone number nor a name, the query should return 482245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // an empty cursor. Let's ensure that. 482345d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov sb.append("0"); 48245e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 48255e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 4826a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 4827ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 48285e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = PhoneColumns.NORMALIZED_NUMBER + "," + RawContacts.CONTACT_ID; 4829a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 483046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 483146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 483246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + PHONE_FILTER_SORT_ORDER; 483346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 483446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = PHONE_FILTER_SORT_ORDER; 483546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 4836a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 4837ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4838ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4839ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 48404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case EMAILS: { 484182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 484289c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 48434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov break; 48444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 48454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 484648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: { 484782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 48484da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 48494da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'" 48504da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + " AND " + Data._ID + "=?"); 485148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 485248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 485348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 48545e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_LOOKUP: { 485582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 485689c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 48574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov if (uri.getPathSegments().size() > 2) { 485808768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String email = uri.getLastPathSegment(); 485908768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String address = mDbHelper.extractAddressFromEmailAddress(email); 486008768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, address); 486108768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)"); 48624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 4863ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4864ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4865ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 48665e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_FILTER: { 486746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 486846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 486946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 487046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT; 487146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 487246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 487307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov String filterParam = null; 48747d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa 487507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 487607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = uri.getLastPathSegment(); 487707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (TextUtils.isEmpty(filterParam)) { 487807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = null; 487907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 488007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 48815e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 488207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (filterParam == null) { 488307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov // If the filter is unspecified, return nothing 488407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov qb.appendWhere(" AND 0"); 488507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } else { 488607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov StringBuilder sb = new StringBuilder(); 488707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append(" AND " + Data._ID + " IN ("); 488807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append( 488907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov "SELECT " + Data._ID + 489007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov " FROM " + Tables.DATA + 48912a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov " WHERE " + DataColumns.MIMETYPE_ID + "="); 48922a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(mDbHelper.getMimeTypeIdForEmail()); 48932a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(" AND " + Data.DATA1 + " LIKE "); 489407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 489520938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov if (!filterParam.contains("@")) { 4896155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append( 4897155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " UNION SELECT " + Data._ID + 4898155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.DATA + 4899155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE +" + DataColumns.MIMETYPE_ID + "="); 4900155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(mDbHelper.getMimeTypeIdForEmail()); 4901155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(" AND " + Data.RAW_CONTACT_ID + " IN " + 4902155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 4903155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 4904155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 4905155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 4906155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 4907155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 49082352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 4909155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 49105e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49115e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 4912a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 49135e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49145e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = Email.DATA + "," + RawContacts.CONTACT_ID; 4915a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 491646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 491746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 491846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + EMAIL_FILTER_SORT_ORDER; 49197d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } else { 49207d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa sortOrder = EMAIL_FILTER_SORT_ORDER; 49217d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } 4922a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 49235e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov break; 49245e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49255e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 4926ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 492782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 492889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 492989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 4930ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4931ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4932ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 493348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 493482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 49354da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 493648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 493748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 49384da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 493948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 494048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 494148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 49425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 4943763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 49446ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, RawContacts.RAW_CONTACT_IS_USER_PROFILE, true, 49456ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 49464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 49474f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 49484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 49495ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 49505ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 4951afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 4952763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 49534da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 49544da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 49554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 49564f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 49574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 49585ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 49595ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 496082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 49614da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 49624da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?"); 49636ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, RawContacts.RAW_CONTACT_IS_USER_PROFILE, true, 49646ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 496524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 496624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 496724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 49683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 49693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 4970afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 49713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 49723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 49733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=?"); 49743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 49753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 497624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 497724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 497824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 497924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 498024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 498124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 498224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 498324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 498424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: { 498524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 498624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = ContentUris.parseId(uri); 498724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 498824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 498924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 499024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts._ID + "=?"); 499124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 499224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 499324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 499424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 499524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 499624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 499724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 499824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 499924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 500024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + Data.RAW_CONTACT_ID + "=?"); 500124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 500224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 500324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 500424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_ENTITIES: { 500524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 500624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 500724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 500824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawEntities(qb, uri); 500924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 501024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts._ID + "=?"); 5011e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5012e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5013e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 5014e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey case DATA: { 501582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50166ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, RawContacts.RAW_CONTACT_IS_USER_PROFILE, true, 50176ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 5018e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5019e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5020e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 50214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case DATA_ID: { 502224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = ContentUris.parseId(uri); 5023afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForData(db, dataId, false); 502482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50254da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 50264da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 5027a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov break; 5028a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov } 5029a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov 5030a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 50314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 5032a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton if (TextUtils.isEmpty(sortOrder)) { 5033a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Default the sort order to something reasonable so we get consistent 5034a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // results when callers don't request an ordering 5035892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sortOrder = " length(lookup.normalized_number) DESC"; 5036a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5037a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5038e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : ""; 5039e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov String numberE164 = PhoneNumberUtils.formatNumberToE164(number, 5040e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov mDbHelper.getCurrentCountryIso()); 5041892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String normalizedNumber = 5042892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov PhoneNumberUtils.normalizeNumber(number); 5043892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov mDbHelper.buildPhoneLookupAndContactQuery(qb, normalizedNumber, numberE164); 5044e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov qb.setProjectionMap(sPhoneLookupProjectionMap); 5045e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov // Phone lookup cannot be combined with a selection 5046e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selection = null; 5047e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selectionArgs = null; 5048a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 5049a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5050a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5051ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 5052ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5053ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 505489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov appendAccountFromParameter(qb, uri); 5055ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5056ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5057ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5058ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 5059ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5060ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 50614da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 50624da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Groups._ID + "=?"); 5063ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5064ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5065ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5066ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 5067ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS + " AS groups"); 5068ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsSummaryProjectionMap); 506989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov appendAccountFromParameter(qb, uri); 507089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov groupBy = Groups._ID; 5071ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5072ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5073ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5074b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 50750c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS); 5076b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 5077b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 5078b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 5079b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 508031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 5081d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 50822d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov String filter = null; 50832d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 50842d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov filter = uri.getPathSegments().get(3); 50852d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov } 508631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 5087d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov if (limit != null) { 5088d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov maxSuggestions = Integer.parseInt(limit); 508931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 509031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 509131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 509231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 50935b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ArrayList<AggregationSuggestionParameter> parameters = null; 50945b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov List<String> query = uri.getQueryParameters("query"); 50955b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov if (query != null && !query.isEmpty()) { 50965b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters = new ArrayList<AggregationSuggestionParameter>(query.size()); 50975b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov for (String parameter : query) { 50985b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov int offset = parameter.indexOf(':'); 50995b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters.add(offset == -1 51005b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ? new AggregationSuggestionParameter( 510176dfa406e2cde19c824983c37fc92c1c5bf63eecDaniel Lehmann AggregationSuggestions.PARAMETER_MATCH_NAME, 51025b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter) 51035b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov : new AggregationSuggestionParameter( 51045b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(0, offset), 51055b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(offset + 1))); 51065b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 51075b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 51085b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 5109763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 51107581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov 51117581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov return mContactAggregator.queryAggregationSuggestions(qb, projection, contactId, 51125b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov maxSuggestions, filter, parameters); 511331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 511431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 5115eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 5116eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setTables(Tables.SETTINGS); 5117eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setProjectionMap(sSettingsProjectionMap); 511889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov appendAccountFromParameter(qb, uri); 5119e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5120e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // When requesting specific columns, this query requires 5121e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // late-binding of the GroupMembership MIME-type. 5122b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final String groupMembershipMimetypeId = Long.toString(mDbHelper 5123e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 512482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 5125b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.isInProjection(projection, Settings.UNGROUPED_COUNT)) { 5126e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5127e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 512882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 5129b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.isInProjection(projection, Settings.UNGROUPED_WITH_PHONES)) { 5130e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5131e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 5132e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5133eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 5134eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 5135eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 513682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 51370a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 51385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 51395ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 51405ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 514182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES_ID: { 51420a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 51434da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 51444da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(DataColumns.CONCRETE_ID + "=?"); 51455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 51465ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 51475ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 5148c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: { 5149174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchSuggestionsQuery( 5150174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, uri, projection, limit); 5151c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5152c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 5153c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: { 51542d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill String lookupKey = uri.getLastPathSegment(); 5155174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String filter = getQueryParameter( 5156174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov uri, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 5157174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchShortcutRefresh( 5158174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, projection, lookupKey, filter); 5159c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5160c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 51611b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS: 5162ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 51631b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 51641b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 51651b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 51661b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_WITH_PHONES: 5167ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 51681b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 51691b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1"); 51701b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 51711b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 51721b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_FAVORITES: 5173ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 51741b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 51751b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.STARRED + "=1"); 51761b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 51771b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 51781b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_GROUP_NAME: 5179ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 51801b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 518171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 51821b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 51831b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 51841b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 518546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITIES: { 5186a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 518746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 518846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 518946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 519046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITY_ID: { 519146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5192a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 51934da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 51944da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 519546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 519646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 519746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 519809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov case PROVIDER_STATUS: { 519909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return queryProviderStatus(uri, projection); 520009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 520109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5202d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES : { 5203d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5204d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5205d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5206d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5207d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 5208d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID : { 5209385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov long id = ContentUris.parseId(uri); 5210d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5211d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5212385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(id)); 5213d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.appendWhere(Directory._ID + "=?"); 5214d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5215d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5216d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 52177a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov case COMPLETE_NAME: { 52187a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return completeName(uri, projection); 52197a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 52207a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 52214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 5222f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 5223c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov sortOrder, limit); 52244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 52254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 522609e69522745551522c55dff27424496f255def46Daniel Lehmann qb.setStrict(true); 52277f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov 5228ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov Cursor cursor = 5229ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit); 5230ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) { 5231ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov cursor = bundleLetterCountExtras(cursor, db, qb, selection, selectionArgs, sortOrder); 5232ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5233ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov return cursor; 52345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 52355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 52365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection, 52375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String selection, String[] selectionArgs, String sortOrder, String groupBy, 52385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String limit) { 5239038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana if (projection != null && projection.length == 1 5240038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana && BaseColumns._COUNT.equals(projection[0])) { 5241038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana qb.setProjectionMap(sCountProjectionMap); 5242038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana } 52435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null, 52445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sortOrder, limit); 52454f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 52464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 52474f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 52484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 52494f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 52504f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 525109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov /** 525209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov * Creates a single-row cursor containing the current status of the provider. 525309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov */ 525409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private Cursor queryProviderStatus(Uri uri, String[] projection) { 525509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 525609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov RowBuilder row = cursor.newRow(); 525709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov for (int i = 0; i < projection.length; i++) { 525809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov if (ProviderStatus.STATUS.equals(projection[i])) { 525909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mProviderStatus); 526009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } else if (ProviderStatus.DATA1.equals(projection[i])) { 526109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mEstimatedStorageRequirement); 526209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 526309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 526409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return cursor; 526509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 526609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5267a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** 5268a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * Runs the query with the supplied contact ID and lookup ID. If the query succeeds, 5269a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * it returns the resulting cursor, otherwise it returns null and the calling 5270a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * method needs to resolve the lookup key and rerun the query. 5271a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov */ 5272a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private Cursor queryWithContactIdAndLookupKey(SQLiteQueryBuilder lookupQb, 5273a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteDatabase db, Uri uri, 5274a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection, String selection, String[] selectionArgs, 5275a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String sortOrder, String groupBy, String limit, 5276a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn, long contactId, String lookupKeyColumn, String lookupKey) { 5277a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] args; 5278a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (selectionArgs == null) { 5279a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[2]; 5280a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } else { 5281a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[selectionArgs.length + 2]; 5282a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 5283a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5284a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[0] = String.valueOf(contactId); 5285a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[1] = Uri.encode(lookupKey); 5286a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(contactIdColumn + "=? AND " + lookupKeyColumn + "=?"); 5287a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = query(db, lookupQb, projection, selection, args, sortOrder, 5288a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov groupBy, limit); 5289a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c.getCount() != 0) { 5290a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5291a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5292a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5293a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov c.close(); 5294a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return null; 5295a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 529609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5297bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov private static final class AddressBookIndexQuery { 5298bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String LETTER = "letter"; 5299bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String TITLE = "title"; 5300bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String COUNT = "count"; 5301ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5302bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String[] COLUMNS = new String[] { 5303bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov LETTER, TITLE, COUNT 5304ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov }; 5305ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5306bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_LETTER = 0; 5307bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_TITLE = 1; 5308bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_COUNT = 2; 5309bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 531024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The first letter of the sort key column is what is used for the index headings, except 531124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // in the case of the user's profile, in which case it is empty. 531224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro public static final String SECTION_HEADING_TEMPLATE = 531324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "(CASE WHEN %1$s=1 THEN '' ELSE SUBSTR(%2$s,1,1) END)"; 531424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5315de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa public static final String ORDER_BY = LETTER + " COLLATE " + PHONEBOOK_COLLATOR_NAME; 5316ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5317ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5318ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov /** 5319ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * Computes counts by the address book index titles and adds the resulting tally 5320ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * to the returned cursor as a bundle of extras. 5321ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov */ 5322ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov private Cursor bundleLetterCountExtras(Cursor cursor, final SQLiteDatabase db, 5323ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov SQLiteQueryBuilder qb, String selection, String[] selectionArgs, String sortOrder) { 5324ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortKey; 5325ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5326ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // The sort order suffix could be something like "DESC". 5327ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // We want to preserve it in the query even though we will change 5328ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // the sort column itself. 5329ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortOrderSuffix = ""; 5330ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (sortOrder != null) { 533124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 533224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // If the sort order contains one of the "is_profile" columns, we need to strip it out 533324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // first. 533424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (sortOrder.contains(Contacts.IS_USER_PROFILE) 533524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro || sortOrder.contains(RawContacts.RAW_CONTACT_IS_USER_PROFILE)) { 533624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String[] splitOrderClauses = sortOrder.split(","); 533724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro StringBuilder rejoinedClause = new StringBuilder(); 533824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro for (String orderClause : splitOrderClauses) { 533924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!orderClause.contains(Contacts.IS_USER_PROFILE) 534024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro && !orderClause.contains(RawContacts.RAW_CONTACT_IS_USER_PROFILE)) { 534124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (rejoinedClause.length() > 0) { 534224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro rejoinedClause.append(", "); 534324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 534424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro rejoinedClause.append(orderClause.trim()); 534524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 534624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 534724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sortOrder = rejoinedClause.toString(); 534824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 534924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5350ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int spaceIndex = sortOrder.indexOf(' '); 5351ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (spaceIndex != -1) { 5352ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder.substring(0, spaceIndex); 5353ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortOrderSuffix = sortOrder.substring(spaceIndex); 5354ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5355ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder; 5356ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5357ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5358ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = Contacts.SORT_KEY_PRIMARY; 5359ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5360ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5361bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String locale = getLocale().toString(); 5362ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov HashMap<String, String> projectionMap = Maps.newHashMap(); 536324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 536424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The user profile column varies depending on the view. 5365ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann String profileColumn = qb.getTables().contains(Views.CONTACTS) 536624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro ? Contacts.IS_USER_PROFILE 536724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro : RawContacts.RAW_CONTACT_IS_USER_PROFILE; 536824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String sectionHeading = String.format( 536924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro AddressBookIndexQuery.SECTION_HEADING_TEMPLATE, profileColumn, sortKey); 5370bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov projectionMap.put(AddressBookIndexQuery.LETTER, 537124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sectionHeading + " AS " + AddressBookIndexQuery.LETTER); 5372bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5373bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov /** 5374bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * Use the GET_PHONEBOOK_INDEX function, which is an android extension for SQLite3, 5375bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * to map the first letter of the sort key to a character that is traditionally 5376bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * used in phonebooks to represent that letter. For example, in Korean it will 5377bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * be the first consonant in the letter; for Japanese it will be Hiragana rather 5378bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * than Katakana. 5379bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov */ 5380ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.TITLE, 538124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "GET_PHONEBOOK_INDEX(" + sectionHeading + ",'" + locale + "')" 5382bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov + " AS " + AddressBookIndexQuery.TITLE); 5383ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.COUNT, 5384ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov "COUNT(" + Contacts._ID + ") AS " + AddressBookIndexQuery.COUNT); 5385ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov qb.setProjectionMap(projectionMap); 5386ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5387f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs, 5388ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY, null /* having */, 5389ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY + sortOrderSuffix); 5390ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5391ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov try { 5392f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov int groupCount = indexCursor.getCount(); 5393ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String titles[] = new String[groupCount]; 5394ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int counts[] = new int[groupCount]; 5395bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int indexCount = 0; 5396bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String currentTitle = null; 5397bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5398bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // Since GET_PHONEBOOK_INDEX is a many-to-1 function, we may end up 5399bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // with multiple entries for the same title. The following code 5400bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // collapses those duplicates. 5401ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov for (int i = 0; i < groupCount; i++) { 5402f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.moveToNext(); 5403bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String title = indexCursor.getString(AddressBookIndexQuery.COLUMN_TITLE); 5404bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int count = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT); 5405bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount == 0 || !TextUtils.equals(title, currentTitle)) { 5406bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles[indexCount] = currentTitle = title; 5407bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount] = count; 5408bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov indexCount++; 5409bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } else { 5410bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount - 1] += count; 5411bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5412bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5413bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5414bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount < groupCount) { 5415bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String[] newTitles = new String[indexCount]; 5416bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(titles, 0, newTitles, 0, indexCount); 5417bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles = newTitles; 5418bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5419bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int[] newCounts = new int[indexCount]; 5420bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(counts, 0, newCounts, 0, indexCount); 5421bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts = newCounts; 5422ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5423ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5424e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return new AddressBookCursor((CrossProcessCursor) cursor, titles, counts); 5425ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } finally { 5426f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.close(); 5427ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5428ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5429ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 54302d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill /** 543192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Returns the contact Id for the contact identified by the lookupKey. 543292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Robust against changes in the lookup key: if the key has changed, will 543392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * look up the contact by the raw contact IDs or name encoded in the lookup 543492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * key. 54352d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill */ 54362d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) { 54375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey key = new ContactLookupKey(); 54385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments = key.parse(lookupKey); 54395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 544092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov long contactId = -1; 544192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_SOURCE_ID)) { 544292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdBySourceIds(db, segments); 544392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 544492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 544592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 544692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 544792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 544892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov boolean hasRawContactIds = 544992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID); 545092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds) { 545192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdByRawContactIds(db, segments); 545292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 545392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 545492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 545592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 545692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 545792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds 545892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME)) { 54595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = lookupContactIdByDisplayNames(db, segments); 54605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 54615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 54635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 54645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private interface LookupBySourceIdQuery { 54665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String TABLE = Tables.RAW_CONTACTS; 54675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 54695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 54705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 54715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 54725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.SOURCE_ID 54735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 54745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 54765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_TYPE = 1; 54775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 54785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int SOURCE_ID = 3; 54795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 54805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long lookupContactIdBySourceIds(SQLiteDatabase db, 54825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments) { 54835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 54845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(RawContacts.SOURCE_ID + " IN ("); 54855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 54865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 548792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID) { 54885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 54895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 54905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 54915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 54925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 54935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 54945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS, 54965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 54975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 54985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 54995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountType = c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE); 55005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME); 55015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 55025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey.getAccountHashCode(accountType, accountName); 55035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID); 55045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 55055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 550692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID 550792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 55085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(sourceId)) { 55095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID); 55105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 55115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 55155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 55165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 55195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 552192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByRawContactIdQuery { 552292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.RAW_CONTACTS; 55235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 55255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 55265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 55275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 552892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts._ID, 55295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 55305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 55325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_TYPE = 1; 55335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 553492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ID = 3; 55355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 553792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByRawContactIds(SQLiteDatabase db, 553892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 553992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 554092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(RawContacts._ID + " IN ("); 55415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 55425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 554392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 554492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(segment.rawContactId); 554592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(","); 55465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 554892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 554992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 55505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 555192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov Cursor c = db.query(LookupByRawContactIdQuery.TABLE, LookupByRawContactIdQuery.COLUMNS, 555292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.toString(), null, null, null, null); 555392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov try { 555492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov while (c.moveToNext()) { 555592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountType = c.getString(LookupByRawContactIdQuery.ACCOUNT_TYPE); 555692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountName = c.getString(LookupByRawContactIdQuery.ACCOUNT_NAME); 555792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int accountHashCode = 555892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ContactLookupKey.getAccountHashCode(accountType, accountName); 555992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String rawContactId = c.getString(LookupByRawContactIdQuery.ID); 556092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 556192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 556292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID 556392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 556492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && segment.rawContactId.equals(rawContactId)) { 556592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov segment.contactId = c.getLong(LookupByRawContactIdQuery.CONTACT_ID); 556692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov break; 556792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 556892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 556992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 557092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } finally { 557192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov c.close(); 55725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 557492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return getMostReferencedContactId(segments); 557592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 557692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 557792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByDisplayNameQuery { 557892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS; 557992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 558092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String COLUMNS[] = { 558192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.CONTACT_ID, 558292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 558392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 558492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov NameLookupColumns.NORMALIZED_NAME 558592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov }; 558692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 558792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int CONTACT_ID = 0; 558892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_TYPE = 1; 558992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_NAME = 2; 559092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int NORMALIZED_NAME = 3; 559192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 559292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 559392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByDisplayNames(SQLiteDatabase db, 559492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 55955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 55965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(NameLookupColumns.NORMALIZED_NAME + " IN ("); 55975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 55985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 559992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 560092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 56015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 56025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 56035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 56065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY 56075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov + " AND " + RawContacts.CONTACT_ID + " NOT NULL"); 56085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS, 56105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 56115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 56125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 56135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountType = c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE); 56145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME); 56155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 56165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey.getAccountHashCode(accountType, accountName); 56175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME); 56185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 56195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 562092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if ((segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 562192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) 562292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 56235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(name)) { 56245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID); 56255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 56265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 56305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 56315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 56345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 563692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private boolean lookupKeyContainsType(ArrayList<LookupKeySegment> segments, int lookupType) { 563792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 563892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 563992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == lookupType) { 564092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return true; 564192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 564292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 564392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 564492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return false; 564592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 564692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 5647ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateLookupKeyForRawContact(SQLiteDatabase db, long rawContactId) { 5648ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov mContactAggregator.updateLookupKeyForRawContact(db, rawContactId); 5649ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov } 5650ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov 56515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov /** 56525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov * Returns the contact ID that is mentioned the highest number of times. 56535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov */ 56545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) { 56555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Collections.sort(segments); 56565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long bestContactId = -1; 56585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int bestRefCount = 0; 56595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = -1; 56615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int count = 0; 56625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = segments.size(); 56645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segmentCount; i++) { 56655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 56665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId != -1) { 56675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId == contactId) { 56685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count++; 56695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 56705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 56715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestContactId = contactId; 56725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestRefCount = count; 56735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = segment.contactId; 56755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count = 1; 56765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 56805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 56815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 56825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return bestContactId; 56835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 5686763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 5687763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar String[] projection) { 56884928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 56892f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 56902f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 56912f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 56924928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * @param includeDataUsageStat true when the table should include DataUsageStat table. 56934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Note that this uses INNER JOIN instead of LEFT OUTER JOIN, so some of data in Contacts 56944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * may be dropped. 56952f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 56962f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 56974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa String[] projection, boolean includeDataUsageStat) { 569882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 5699ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 57002f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 57012f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Just for frequently contacted contacts in Strequent Uri handling. 57024928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (includeDataUsageStat) { 57032f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa sb.append(" INNER JOIN " + 5704ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA_USAGE_STAT + " AS " + Tables.DATA_USAGE_STAT + 57052f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa " ON (" + 57062f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DbQueryUtils.concatenateClauses( 57072f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DataUsageStatColumns.CONCRETE_TIMES_USED + " > 0", 57084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) + 57092f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa ")"); 57102f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 57112f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 57127ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 57137ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 5714916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setTables(sb.toString()); 5715916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionMap); 5716916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov } 5717916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 5718916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** 5719916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * Finds name lookup records matching the supplied filter, picks one arbitrary match per 5720916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * contact and joins that with other contacts tables. 5721916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov */ 5722916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private void setTablesAndProjectionMapForContactsWithSnippet(SQLiteQueryBuilder qb, Uri uri, 57237ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov String[] projection, String filter, long directoryId) { 57247ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov 57257ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5726ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 5727916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 572803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (filter != null) { 572903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov filter = filter.trim(); 573003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 573103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 573230cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov if (TextUtils.isEmpty(filter) || (directoryId != -1 && directoryId != Directory.DEFAULT)) { 573330cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov sb.append(" JOIN (SELECT NULL AS " + SearchSnippetColumns.SNIPPET + " WHERE 0)"); 57345e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } else { 57355e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov appendSearchIndexJoin(sb, uri, projection, filter); 57365e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 57377ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 57387ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 573903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setTables(sb.toString()); 574003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionWithSnippetMap); 574103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 5742916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 574303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private void appendSearchIndexJoin( 574403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov StringBuilder sb, Uri uri, String[] projection, String filter) { 5745916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 5746174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET)) { 574703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String[] args = null; 574803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String snippetArgs = 574903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 575003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (snippetArgs != null) { 575103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov args = snippetArgs.split(","); 575203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 575303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 57545e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String startMatch = args != null && args.length > 0 ? args[0] 57555e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_START_MATCH; 57565e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String endMatch = args != null && args.length > 1 ? args[1] 57575e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_END_MATCH; 57585e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String ellipsis = args != null && args.length > 2 ? args[2] 57595e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_ELLIPSIS; 57605e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 57615e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 57625e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 5763174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin( 5764174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb, filter, true, startMatch, endMatch, ellipsis, maxTokens); 5765174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 5766174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin(sb, filter, false, null, null, null, 0); 5767174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5768174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5769174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 5770174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public void appendSearchIndexJoin(StringBuilder sb, String filter, 5771174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean snippetNeeded, String startMatch, String endMatch, String ellipsis, 5772174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int maxTokens) { 5773174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isEmailAddress = false; 5774174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String emailAddress = null; 5775174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isPhoneNumber = false; 5776174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String phoneNumber = null; 5777174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String numberE164 = null; 5778174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 57793716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // If the query consists of a single word, we can do snippetizing after-the-fact for a 57803716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // performance boost. 57813716f1447ceb21180d1301790eabd8b9453f486dDave Santoro boolean singleTokenSearch = filter.split(QUERY_TOKENIZER_REGEX).length == 1; 57823716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 5783174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (filter.indexOf('@') != -1) { 5784174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov emailAddress = mDbHelper.extractAddressFromEmailAddress(filter); 5785174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isEmailAddress = !TextUtils.isEmpty(emailAddress); 5786174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 5787174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isPhoneNumber = isPhoneNumber(filter); 578804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (isPhoneNumber) { 578904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann phoneNumber = PhoneNumberUtils.normalizeNumber(filter); 579004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann numberE164 = PhoneNumberUtils.formatNumberToE164(phoneNumber, 579104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann mDbHelper.getCountryIso()); 579204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 5793174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5794174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 5795174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(" JOIN (SELECT " + SearchIndexColumns.CONTACT_ID + " AS snippet_contact_id"); 5796174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (snippetNeeded) { 57975e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(", "); 57985e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 57993d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 58005e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 580104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Email.ADDRESS + ")"); 580204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + Tables.DATA_JOIN_RAW_CONTACTS); 580304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 580404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID + " AND " + Email.ADDRESS + " LIKE "); 580504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann DatabaseUtils.appendEscapedSQLString(sb, filter + "%"); 580604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 58073d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 58083d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(","); 58093716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 58103716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 58113716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 58123716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 58133716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 58143716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 58153716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 58163d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(")"); 58173d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 58183d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 58193d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 582004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Phone.NUMBER + ")"); 582104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + 582204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann Tables.DATA_JOIN_RAW_CONTACTS + " JOIN " + Tables.PHONE_LOOKUP); 582304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" ON " + DataColumns.CONCRETE_ID); 582404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID); 582504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 582604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID); 582704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" AND " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 582804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(phoneNumber); 582904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 583004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(numberE164)) { 583104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" OR " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 583204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(numberE164); 583304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 583404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 583504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 58365e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 58375e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 58383716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 58393716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 58403716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 58413716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 58423716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 58433716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 58443716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 58455e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 584603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 584704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann final String normalizedFilter = NameNormalizer.normalize(filter); 584804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(normalizedFilter)) { 58493716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 58503716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 58513716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 58523716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 58533716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("(CASE WHEN EXISTS (SELECT 1 FROM "); 58543716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.RAW_CONTACTS + " AS rc INNER JOIN "); 58553716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.NAME_LOOKUP + " AS nl ON (rc." + RawContacts._ID); 58563716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=nl." + NameLookupColumns.RAW_CONTACT_ID); 58573716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") WHERE nl." + NameLookupColumns.NORMALIZED_NAME); 58583716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" GLOB '" + normalizedFilter + "*' AND "); 58593716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("nl." + NameLookupColumns.NAME_TYPE + "="); 58603716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(NameLookupType.NAME_COLLATION_KEY + " AND "); 58613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 58623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=rc." + RawContacts.CONTACT_ID); 58633716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") THEN NULL ELSE "); 58643716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 58653716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" END)"); 58663716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 586704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } else { 586804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("NULL"); 586904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 587003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 58715e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" AS " + SearchSnippetColumns.SNIPPET); 58725e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 587303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 58745e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" FROM " + Tables.SEARCH_INDEX); 58755e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" WHERE "); 58765e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(Tables.SEARCH_INDEX + " MATCH "); 58775e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 58782352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, "\"" + sanitizeMatch(filter) + "*\""); 58793d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 58802352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, 588104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann "\"" + sanitizeMatch(filter) + "*\" OR \"" + phoneNumber + "*\"" 58822352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov + (numberE164 != null ? " OR \"" + numberE164 + "\"" : "")); 588303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 58842352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filter) + "*"); 58859c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov } 588603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov sb.append(") ON (" + Contacts._ID + "=snippet_contact_id)"); 5887a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov } 5888a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov 58892352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov private String sanitizeMatch(String filter) { 58902352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov // TODO more robust preprocessing of match expressions 58912352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov return filter.replace('-', ' ').replace('\"', ' '); 58922352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov } 58932352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov 58945e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov private void appendSnippetFunction( 58955e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov StringBuilder sb, String startMatch, String endMatch, String ellipsis, int maxTokens) { 58965e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append("snippet(" + Tables.SEARCH_INDEX + ","); 58975e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 58985e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 58995e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 59005e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 59015e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, ellipsis); 59025e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 59035e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov // The index of the column used for the snippet, "content" 59045e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(",1,"); 59055e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(maxTokens); 59065e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 59075e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 59085e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 5909763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) { 5910763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar StringBuilder sb = new StringBuilder(); 5911ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.RAW_CONTACTS); 5912763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setTables(sb.toString()); 5913763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setProjectionMap(sRawContactsProjectionMap); 5914763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar appendAccountFromParameter(qb, uri); 5915763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar } 5916763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar 5917a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForRawEntities(SQLiteQueryBuilder qb, Uri uri) { 5918ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.RAW_ENTITIES); 5919a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sRawEntityProjectionMap); 592046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana appendAccountFromParameter(qb, uri); 592146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 592246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 592382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 592482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String[] projection, boolean distinct) { 592546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, distinct, null); 592646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 592746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 592846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 592946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @param usageType when non-null {@link Tables#DATA_USAGE_STAT} is joined with the specified 593046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type. 593146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 593246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 593346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String[] projection, boolean distinct, Integer usageType) { 593482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 5935ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 593682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov sb.append(" data"); 593782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov 5938a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID); 5939a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 5940a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 5941a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 59423296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey 594346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (usageType != null) { 594446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa appendDataUsageStatJoin(sb, usageType, DataColumns.CONCRETE_ID); 594546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 594646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 594782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov qb.setTables(sb.toString()); 5948f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov 5949f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov boolean useDistinct = distinct 5950f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov || !mDbHelper.isInProjection(projection, DISTINCT_DATA_PROHIBITING_COLUMNS); 5951f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setDistinct(useDistinct); 5952f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setProjectionMap(useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap); 595382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov appendAccountFromParameter(qb, uri); 5954ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov } 5955ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov 59560a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb, 59570a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String[] projection) { 59580a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StringBuilder sb = new StringBuilder(); 5959ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 59600a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" data"); 5961a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 5962a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 59630a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 5964a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 5965a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sStatusUpdatesProjectionMap); 5966a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5967a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 59683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItems(SQLiteQueryBuilder qb) { 59691dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.STREAM_ITEMS 59701dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.RAW_CONTACTS + " ON (" 59711dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemsColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 59721dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.CONTACTS + " ON (" 59731dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + RawContactsColumns.CONCRETE_CONTACT_ID + "=" + ContactsColumns.CONCRETE_ID + ")"); 59743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemsProjectionMap); 59753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 59763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 59773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItemPhotos(SQLiteQueryBuilder qb) { 59781dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.PHOTO_FILES 59791dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.STREAM_ITEM_PHOTOS + " ON (" 59801dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_PHOTO_FILE_ID + "=" 59811dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + PhotoFilesColumns.CONCRETE_ID 59821dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.STREAM_ITEMS + " ON (" 59831dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=" 59841dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemsColumns.CONCRETE_ID + ")"); 59853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemPhotosProjectionMap); 59863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 59873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 5988a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForEntities(SQLiteQueryBuilder qb, Uri uri, 5989a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection) { 5990a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5991ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.ENTITIES); 5992a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" data"); 5993a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5994a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts.Entity.CONTACT_ID); 5995a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 5996a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, Contacts.Entity.DATA_ID); 5997a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, Contacts.Entity.DATA_ID); 5998a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5999a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6000a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sEntityProjectionMap); 6001a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendAccountFromParameter(qb, uri); 6002a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6003a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6004a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactStatusUpdateJoin(StringBuilder sb, String[] projection, 6005a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lastStatusUpdateIdColumn) { 6006a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, 6007a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS, 6008a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_RES_PACKAGE, 6009a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_ICON, 6010a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_LABEL, 6011a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_TIMESTAMP)) { 6012a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " " 6013a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.ALIAS + 6014a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + lastStatusUpdateIdColumn + "=" 6015a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")"); 60160a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6017a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 60180a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6019a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataStatusUpdateJoin(StringBuilder sb, String[] projection, 6020a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 6021b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov if (mDbHelper.isInProjection(projection, 60220a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS, 60230a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_RES_PACKAGE, 60240a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_ICON, 60250a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_LABEL, 60260a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_TIMESTAMP)) { 60270a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + 6028a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "=" 6029a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + dataIdColumn + ")"); 60300a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6031a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6032a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 603346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void appendDataUsageStatJoin(StringBuilder sb, int usageType, String dataIdColumn) { 603446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" LEFT OUTER JOIN " + Tables.DATA_USAGE_STAT + 603546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" + dataIdColumn + 603646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " AND " + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" + usageType + ")"); 603746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 603846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 6039a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactPresenceJoin(StringBuilder sb, String[] projection, 6040a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn) { 6041a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, 6042a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_PRESENCE, Contacts.CONTACT_CHAT_CAPABILITY)) { 6043a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + 6044a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + contactIdColumn + " = " 6045a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + ")"); 6046a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6047a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6048a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6049a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataPresenceJoin(StringBuilder sb, String[] projection, 6050a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 6051a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, Data.PRESENCE, Data.CHAT_CAPABILITY)) { 6052a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE + 6053a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdates.DATA_ID + "=" + dataIdColumn + ")"); 6054a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6055a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6056a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 605724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private boolean appendLocalDirectorySelectionIfNeeded(SQLiteQueryBuilder qb, long directoryId) { 6058385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directoryId == Directory.DEFAULT) { 6059385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY); 606024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 6061385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directoryId == Directory.LOCAL_INVISIBLE){ 6062385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " NOT IN " + Tables.DEFAULT_DIRECTORY); 606324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 606424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 606524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return false; 606624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 606724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 606824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void appendProfileRestriction(SQLiteQueryBuilder qb, Uri uri, String profileColumn, 60696ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean andRequired, boolean suppressProfileCheck) { 60706ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (!shouldIncludeProfile(uri, suppressProfileCheck)) { 607124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere((andRequired ? " AND (" : "") 607224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + profileColumn + " IS NULL OR " 607324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + profileColumn + "=0" 607424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + (andRequired ? ")" : "")); 6075385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } 6076385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } 6077385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov 60786ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private String prependProfileSortIfNeeded(Uri uri, String sortOrder, 60796ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean suppressProfileCheck) { 60806ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (shouldIncludeProfile(uri, suppressProfileCheck)) { 608124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (TextUtils.isEmpty(sortOrder)) { 608224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return Contacts.IS_USER_PROFILE + " DESC"; 608324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else { 608424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return Contacts.IS_USER_PROFILE + " DESC, " + sortOrder; 608524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 608624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 608724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return sortOrder; 608824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 608924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 60906ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private boolean shouldIncludeProfile(Uri uri, boolean suppressProfileCheck) { 609124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The user's profile may be returned alongside other contacts if it was requested and 609224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // the calling application has permission to read profile data. 6093377850d2dfd28eaf1b22273a50cfe066f6667ab9Dave Santoro boolean profileRequested = readBooleanQueryParameter(uri, ContactsContract.ALLOW_PROFILE, 609424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro false); 60956ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (profileRequested && !suppressProfileCheck) { 609624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 609724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 609824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return profileRequested; 609924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 610024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 61014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) { 6102f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6103f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 6104e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6105e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6106e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6107e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 6108fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6109fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6110e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6111e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6112e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6113e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6114e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6115e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 61164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere(RawContacts.ACCOUNT_NAME + "=" 61174a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + DatabaseUtils.sqlEscapeString(accountName) + " AND " 61184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + RawContacts.ACCOUNT_TYPE + "=" 61194a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + DatabaseUtils.sqlEscapeString(accountType)); 61204a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } else { 61214a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere("1"); 61224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 61234a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 61244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 6125e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong private String appendAccountToSelection(Uri uri, String selection) { 6126f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6127f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 6128e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6129e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6130e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6131e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 6132fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6133fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6134e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6135e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6136e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6137e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6138e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6139e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 6140e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "=" 6141e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountName) + " AND " 6142e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + RawContacts.ACCOUNT_TYPE + "=" 6143e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountType)); 6144e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong if (!TextUtils.isEmpty(selection)) { 6145e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(" AND ("); 6146e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(selection); 6147e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(')'); 6148e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6149e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selectionSb.toString(); 6150e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } else { 6151e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selection; 6152e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6153e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6154e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong 61557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 6156c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * Gets the value of the "limit" URI query parameter. 6157c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * 6158c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * @return A string containing a non-negative integer, or <code>null</code> if 6159c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * the parameter is not set, or is set to an invalid value. 6160c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov */ 6161f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private String getLimit(Uri uri) { 61622e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limitParam = getQueryParameter(uri, ContactsContract.LIMIT_PARAM_KEY); 6163c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (limitParam == null) { 6164c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6165c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6166c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov // make sure that the limit is a non-negative integer 6167c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov try { 6168c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov int l = Integer.parseInt(limitParam); 6169c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (l < 0) { 6170c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6171c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6172c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6173c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return String.valueOf(l); 6174c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } catch (NumberFormatException ex) { 6175c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6176c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6177c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6178c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6179c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 6180b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov @Override 6181f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 6182415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6183f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mode.equals("r")) { 6184f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mReadAccessLatch); 6185f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6186f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mWriteAccessLatch); 6187f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6188415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6189b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov int match = sUriMatcher.match(uri); 6190b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov switch (match) { 6191a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 6192afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 619324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6194afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 6195afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro return openPhotoAssetFile(db, uri, mode, 619624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Data._ID + "=" + Contacts.PHOTO_ID + " AND " + 619724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContacts.CONTACT_ID + "=?", 619824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(rawContactId)}); 6199e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6200b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6201f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: { 6202f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6203f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6204f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact ID can only be read."); 6205f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6206afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6207f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 6208afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6209afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = db.query(Tables.CONTACTS, 6210f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{Contacts.PHOTO_FILE_ID}, 6211f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID + "=?", new String[]{String.valueOf(contactId)}, 6212f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, null); 6213f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6214f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6215f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(0); 6216f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6217f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6218f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6219f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6220f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6221f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6222f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6223f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: { 6224f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6225f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6226f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact lookup key can only be read."); 6227f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6228f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro List<String> pathSegments = uri.getPathSegments(); 6229f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int segmentCount = pathSegments.size(); 6230f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount < 4) { 6231f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6232f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Missing a lookup key", uri)); 6233f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6234afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6235f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String lookupKey = pathSegments.get(2); 6236f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Contacts.PHOTO_FILE_ID}; 6237f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount == 5) { 6238f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(pathSegments.get(3)); 6239afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6240f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 6241f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 6242afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 6243f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro projection, null, null, null, null, null, 6244f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 6245f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c != null) { 6246f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6247f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6248f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6249f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6250f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6251f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6252f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6253f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6254f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6255f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6256f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6257f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 6258afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 6259afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6260afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = qb.query(db, projection, Contacts._ID + "=?", 6261f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(contactId)}, null, null, null); 6262f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6263f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6264f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6265f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6266f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6267f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6268f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6269f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6270f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: { 6272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6273f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean writeable = !mode.equals("r"); 6274afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6275afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, writeable); 6276f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6277f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Find the primary photo data record for this raw contact. 6278f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6279f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Data._ID, Photo.PHOTO_FILE_ID}; 6280f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 6281afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = qb.query(db, projection, 6282f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?", 6283f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(rawContactId), Photo.CONTENT_ITEM_TYPE}, 6284f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, Data.IS_PRIMARY + " DESC"); 6285f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long dataId = 0; 6286f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = 0; 6287f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6288f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c.getCount() >= 1) { 6289f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6290f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro dataId = c.getLong(0); 6291f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro photoFileId = c.getLong(1); 6292f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6293f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6294f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6295f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6296f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6297f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If writeable, open a writeable file descriptor that we can monitor. 6298f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // When the caller finishes writing content, we'll process the photo and 6299f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // update the data record. 6300f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (writeable) { 6301f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForWrite(rawContactId, dataId, uri, mode); 6302f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6303f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6304f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6305f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6306f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6307f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: { 6308f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = ContentUris.parseId(uri); 6309f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6310f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6311f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by key can only be read."); 6312f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6313f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6314f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6315f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6316e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov case DATA_ID: { 6317afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 631824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = Long.parseLong(uri.getPathSegments().get(1)); 6319afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForData(db, dataId, false); 6320afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro return openPhotoAssetFile(db, uri, mode, 6321e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov Data._ID + "=? AND " + Data.MIMETYPE + "='" + Photo.CONTENT_ITEM_TYPE + "'", 632224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(dataId)}); 6323d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6324d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6325fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case PROFILE_AS_VCARD: { 6326fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // When opening a contact as file, we pass back contents as a 6327fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // vCard-encoded stream. We build into a local buffer first, 6328fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // then pipe into MemoryFile once the exact size is known. 6329fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6330fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6331fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen return buildAssetFileDescriptor(localStream); 6332fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 633342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 6334fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case CONTACTS_AS_VCARD: { 633542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // When opening a contact as file, we pass back contents as a 633642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // vCard-encoded stream. We build into a local buffer first, 633742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // then pipe into MemoryFile once the exact size is known. 633842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6339fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6340f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 634142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 634242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 634342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 634449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov SQLiteDatabase db = mDbHelper.getReadableDatabase(); 634542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKeys = uri.getPathSegments().get(2); 634642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String[] loopupKeyList = lookupKeys.split(":"); 634742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final StringBuilder inBuilder = new StringBuilder(); 6348fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Uri queryUri = Contacts.CONTENT_URI; 634942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann int index = 0; 6350fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen 6351d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // SQLite has limits on how many parameters can be used 6352d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // so the IDs are concatenated to a query string here instead 635342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann for (String lookupKey : loopupKeyList) { 635442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann if (index == 0) { 6355d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append("("); 635642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } else { 6357d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append(","); 635842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 635924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 6360afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 636124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro inBuilder.append(contactId); 6362fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (mProfileIdCache.profileContactId == contactId) { 6363fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen queryUri = queryUri.buildUpon().appendQueryParameter( 6364377850d2dfd28eaf1b22273a50cfe066f6667ab9Dave Santoro ContactsContract.ALLOW_PROFILE, "true").build(); 6365fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 636642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann index++; 636742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 636842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann inBuilder.append(')'); 636942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String selection = Contacts._ID + " IN " + inBuilder.toString(); 6370d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6371d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // When opening a contact as file, we pass back contents as a 6372d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // vCard-encoded stream. We build into a local buffer first, 6373d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // then pipe into MemoryFile once the exact size is known. 6374d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6375fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(queryUri, localStream, selection, null); 6376f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 6377d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6378b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6379b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov default: 6380fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new FileNotFoundException(mDbHelper.exceptionMessage("File does not exist", 6381fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov uri)); 6382b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6383b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6384b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6385afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private AssetFileDescriptor openPhotoAssetFile(SQLiteDatabase db, Uri uri, String mode, 6386afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro String selection, String[] selectionArgs) 6387e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throws FileNotFoundException { 6388e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov if (!"r".equals(mode)) { 6389e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throw new FileNotFoundException(mDbHelper.exceptionMessage("Mode " + mode 6390e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov + " not supported.", uri)); 6391e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6392e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6393e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov String sql = 6394ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann "SELECT " + Photo.PHOTO + " FROM " + Views.DATA + 6395e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov " WHERE " + selection; 639608ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood try { 6397f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6398f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert DatabaseUtils.blobFileDescriptorForQuery(db, sql, selectionArgs)); 639908ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } catch (SQLiteDoneException e) { 640008ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood // this will happen if the DB query returns no rows (i.e. contact does not exist) 640108ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood throw new FileNotFoundException(uri.toString()); 640208ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } 6403e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6404e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6405f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6406f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a display photo from the photo store for reading. 6407f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoFileId The display photo file ID 6408f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor that allows the file to be read. 6409f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @throws FileNotFoundException If no photo file for the given ID exists. 6410f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6411f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForRead(long photoFileId) 6412f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throws FileNotFoundException { 6413f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoStore.Entry entry = mPhotoStore.get(photoFileId); 6414f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 6415f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return makeAssetFileDescriptor( 6416f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(new File(entry.path), 6417f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.MODE_READ_ONLY), 6418f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro entry.size); 6419f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6420f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 6421f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new FileNotFoundException("No photo file found for ID " + photoFileId); 6422f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6423f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6424f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6425f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6426f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a file descriptor for a photo to be written. When the caller completes writing 6427f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to the file (closing the output stream), the image will be parsed out and processed. 6428f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If processing succeeds, the given raw contact ID's primary photo record will be 6429f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * populated with the inserted image (if no primary photo record exists, the data ID can 6430f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * be left as 0, and a new data record will be inserted). 6431f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rawContactId Raw contact ID this photo entry should be associated with. 6432f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param dataId Data ID for a photo mimetype that will be updated with the inserted 6433f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * image. May be set to 0, in which case the inserted image will trigger creation 6434f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * of a new primary photo image data row for the raw contact. 6435f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param uri The URI being used to access this file. 6436f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param mode Read/write mode string. 6437f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor the caller can use to write an image file for the 6438f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact. 6439f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6440f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForWrite(long rawContactId, long dataId, Uri uri, 6441f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String mode) { 6442f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6443f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return new AssetFileDescriptor(new MonitoredParcelFileDescriptor(rawContactId, dataId, 6444f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(File.createTempFile("img", null), 6445f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentResolver.modeToMode(uri, mode))), 6446f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 0, AssetFileDescriptor.UNKNOWN_LENGTH); 6447f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException ioe) { 6448f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Could not create temp image file in mode " + mode); 6449f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return null; 6450f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6451f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6452f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6453f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6454f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Parcel file descriptor wrapper that monitors when the file is closed. 6455f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If the file contains a valid image, the image is either inserted into the given 6456f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact or updated in the given data row. 6457f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6458f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private class MonitoredParcelFileDescriptor extends ParcelFileDescriptor { 6459f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mRawContactId; 6460f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mDataId; 6461f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private MonitoredParcelFileDescriptor(long rawContactId, long dataId, 6462f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor descriptor) { 6463f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro super(descriptor); 6464f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mRawContactId = rawContactId; 6465f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDataId = dataId; 6466f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6467f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6468f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro @Override 6469f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public void close() throws IOException { 6470f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6471f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check to see whether a valid image was written out. 6472f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Bitmap b = BitmapFactory.decodeFileDescriptor(getFileDescriptor()); 6473f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (b != null) { 6474f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoProcessor processor = new PhotoProcessor(b, mMaxDisplayPhotoDim, 6475f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim); 6476f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6477f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Store the compressed photo in the photo store. 6478f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = mPhotoStore.insert(processor); 6479f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6480f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Depending on whether we already had a data row to attach the photo to, 6481f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // do an update or insert. 6482f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mDataId != 0) { 6483f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Update the data record with the new photo. 6484f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 6485f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6486f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6487f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6488f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6489f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6490f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6491f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6492f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6493f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro update(ContentUris.withAppendedId(Data.CONTENT_URI, mDataId), updateValues, 6494f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null); 6495f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6496f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Insert a new primary data record with the photo. 6497f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues insertValues = new ContentValues(); 6498f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6499f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6500f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6501f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6502f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 6503f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.IS_PRIMARY, 1); 6504f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6505f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6506f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6507f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6508f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insert(RawContacts.CONTENT_URI.buildUpon() 6509f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(String.valueOf(mRawContactId)) 6510f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(RawContacts.Data.CONTENT_DIRECTORY).build(), 6511f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues); 6512f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6513f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6514f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6515f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro super.close(); 6516f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6517f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6518f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6519f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6520d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile"; 6521d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6522d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6523f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert * Returns an {@link AssetFileDescriptor} backed by the 6524d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * contents of the given {@link ByteArrayOutputStream}. 6525d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6526f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) { 6527d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey try { 6528d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey stream.flush(); 6529d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6530d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final byte[] byteData = stream.toByteArray(); 6531d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6532f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6533f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert ParcelFileDescriptor.fromData(byteData, CONTACT_MEMORY_FILE_NAME), 6534f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert byteData.length); 6535d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } catch (IOException e) { 6536ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert Log.w(TAG, "Problem writing stream into an ParcelFileDescriptor: " + e.toString()); 6537ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert return null; 6538d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6539d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6540d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6541f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd) { 6542f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor(fd, AssetFileDescriptor.UNKNOWN_LENGTH); 6543f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6544f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6545f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd, long length) { 6546f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return fd != null ? new AssetFileDescriptor(fd, 0, length) : null; 6547f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6548f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6549d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6550d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * Output {@link RawContacts} matching the requested selection in the vCard 6551d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * format to the given {@link OutputStream}. This method returns silently if 6552d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * any errors encountered. 6553d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6554fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen private void outputRawContactsAsVCard(Uri uri, OutputStream stream, 6555fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen String selection, String[] selectionArgs) { 6556d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final Context context = this.getContext(); 6557dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen int vcardconfig = VCardConfig.VCARD_TYPE_DEFAULT; 6558fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if(uri.getBooleanQueryParameter( 6559fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, false)) { 6560dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen vcardconfig |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT; 6561dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen } 65627a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa final VCardComposer composer = 6563dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen new VCardComposer(context, vcardconfig, false); 6564108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Writer writer = null; 6565108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6566108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer = new BufferedWriter(new OutputStreamWriter(stream)); 6567fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (!composer.init(uri, selection, selectionArgs, null)) { 6568108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "Failed to init VCardComposer"); 6569108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa return; 6570108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6571d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6572108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa while (!composer.isAfterLast()) { 6573108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.write(composer.createOneEntry()); 6574108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6575108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6576108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.e(TAG, "IOException: " + e); 6577108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } finally { 6578108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa composer.terminate(); 6579108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa if (writer != null) { 6580108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6581108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.close(); 6582108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6583108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "IOException during closing output stream: " + e); 6584108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6585d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6586d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6587d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6588b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 65894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 65904f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 6591415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6592415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov waitForAccess(mReadAccessLatch); 6593415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6594a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 65954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 6596b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS: 6597be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return Contacts.CONTENT_TYPE; 65982d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill case CONTACTS_LOOKUP: 6599b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_ID: 6600b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_LOOKUP_ID: 660124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 6602b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_ITEM_TYPE; 6603f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: 660442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: 660524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 6606f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey return Contacts.CONTENT_VCARD_TYPE; 6607f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov case CONTACTS_ID_PHOTO: 6608f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: 6609f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6610f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: 6611f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: 6612f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: 6613f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return "image/jpeg"; 6614b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS: 661524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 6616be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return RawContacts.CONTENT_TYPE; 6617b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS_ID: 661824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 6619b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return RawContacts.CONTENT_ITEM_TYPE; 6620f481f22a9323fe338672f99b88b26c5f0725cd42David Brown case DATA: 662124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 6622f481f22a9323fe338672f99b88b26c5f0725cd42David Brown return Data.CONTENT_TYPE; 6623508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 6624b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getDataMimeType(ContentUris.parseId(uri)); 662548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES: 662648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_TYPE; 662748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 662848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_ITEM_TYPE; 66299005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov case PHONE_LOOKUP: 66309005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov return PhoneLookup.CONTENT_TYPE; 663148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS: 663248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_TYPE; 663348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 663448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_ITEM_TYPE; 663548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS: 663648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_TYPE; 663748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: 663848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_ITEM_TYPE; 6639b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 6640b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_TYPE; 6641b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 6642b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_ITEM_TYPE; 6643b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case SETTINGS: 6644b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Settings.CONTENT_TYPE; 6645b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 6646b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_TYPE; 6647c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: 6648c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SUGGEST_MIME_TYPE; 6649c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: 6650c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SHORTCUT_MIME_TYPE; 6651d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES: 6652d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_TYPE; 6653d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID: 6654d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_ITEM_TYPE; 665561efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov default: 665661efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov return mLegacyApiSupport.getType(uri); 66574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 66584f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 66597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 666009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov public String[] getDefaultProjection(Uri uri) { 666109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov final int match = sUriMatcher.match(uri); 666209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov switch (match) { 666309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS: 666409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP: 666509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_ID: 666609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP_ID: 666709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 666824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 666909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsProjectionMap.getColumnNames(); 667009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 66718727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov case CONTACTS_ID_ENTITIES: 667224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: 66738727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov return sEntityProjectionMap.getColumnNames(); 66748727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov 667509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_VCARD: 667609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_MULTI_VCARD: 667724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 667809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsVCardProjectionMap.getColumnNames(); 667909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 668009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS: 668109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS_ID: 668224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 668324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 668409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sRawContactsProjectionMap.getColumnNames(); 668509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 668609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DATA_ID: 668709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES: 668809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES_ID: 668909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS: 669009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS_ID: 669109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS: 669209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS_ID: 669324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 669409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDataProjectionMap.getColumnNames(); 669509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 669609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONE_LOOKUP: 669709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sPhoneLookupProjectionMap.getColumnNames(); 669809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 669909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 670009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 670109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sAggregationExceptionsProjectionMap.getColumnNames(); 670209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 670309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case SETTINGS: 670409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sSettingsProjectionMap.getColumnNames(); 670509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 670609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES: 670709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES_ID: 670809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDirectoryProjectionMap.getColumnNames(); 670909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 671009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov default: 671109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return null; 671209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 671309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 671409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 6715f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private class StructuredNameLookupBuilder extends NameLookupBuilder { 6716f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6717f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov public StructuredNameLookupBuilder(NameSplitter splitter) { 6718f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov super(splitter); 6719f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6720f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6721f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 6722f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected void insertNameLookup(long rawContactId, long dataId, int lookupType, 6723f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov String name) { 672478fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.insertNameLookup(rawContactId, dataId, lookupType, name); 6725f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6726f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6727f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 6728f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected String[] getCommonNicknameClusters(String normalizedName) { 6729d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); 6730f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6731f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6732f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 67332d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) { 6734d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov sb.append("(" + 6735d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov "SELECT DISTINCT " + RawContacts.CONTACT_ID + 6736d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 6737d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " JOIN " + Tables.NAME_LOOKUP + 6738d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " ON(" + RawContactsColumns.CONCRETE_ID + "=" 6739d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov + NameLookupColumns.RAW_CONTACT_ID + ")" + 6740d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " WHERE normalized_name GLOB '"); 6741e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(NameNormalizer.normalize(filterParam)); 6742916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov sb.append("*' AND " + NameLookupColumns.NAME_TYPE + 6743916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov " IN(" + CONTACT_LOOKUP_NAME_TYPES + "))"); 6744e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 6745e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 67469a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov public boolean isPhoneNumber(String filter) { 67479a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean atLeastOneDigit = false; 67489a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov int len = filter.length(); 67499a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov for (int i = 0; i < len; i++) { 67509a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov char c = filter.charAt(i); 67519a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (c >= '0' && c <= '9') { 67529a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov atLeastOneDigit = true; 67539a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } else if (c != '*' && c != '#' && c != '+' && c != 'N' && c != '.' && c != ';' 67549a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov && c != '-' && c != '(' && c != ')' && c != ' ') { 67559a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return false; 67569a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 67579a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 67589a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return atLeastOneDigit; 67599a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 67609a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 67614a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** 67627a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * Takes components of a name from the query parameters and returns a cursor with those 67637a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * components as well as all missing components. There is no database activity involved 67647a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * in this so the call can be made on the UI thread. 67657a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov */ 67667a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private Cursor completeName(Uri uri, String[] projection) { 67677a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (projection == null) { 67687a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov projection = sDataProjectionMap.getColumnNames(); 67697a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 67707a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 67717a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ContentValues values = new ContentValues(); 6772f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataRowHandlerForStructuredName handler = (DataRowHandlerForStructuredName) 6773f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov getDataRowHandler(StructuredName.CONTENT_ITEM_TYPE); 67747a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 67757a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov copyQueryParamsToContentValues(values, uri, 67767a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.DISPLAY_NAME, 67777a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PREFIX, 67787a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.GIVEN_NAME, 67797a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.MIDDLE_NAME, 67807a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.FAMILY_NAME, 67817a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.SUFFIX, 67827a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_NAME, 67837a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_FAMILY_NAME, 67847a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_MIDDLE_NAME, 67857a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_GIVEN_NAME 67867a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ); 67877a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 67887a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov handler.fixStructuredNameComponents(values, values); 67897a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 67907a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 67917a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov Object[] row = new Object[projection.length]; 67927a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 67937a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov row[i] = values.get(projection[i]); 67947a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 67957a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov cursor.addRow(row); 67967a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return cursor; 67977a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 67987a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 67997a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private void copyQueryParamsToContentValues(ContentValues values, Uri uri, String... columns) { 68007a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (String column : columns) { 68017a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov String param = uri.getQueryParameter(column); 68027a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (param != null) { 68037a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov values.put(column, param); 68047a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68057a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68067a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68077a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68087a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68097a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov /** 68104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov * Inserts an argument at the beginning of the selection arg list. 68114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov */ 68124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private String[] insertSelectionArg(String[] selectionArgs, String arg) { 6813b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 6814b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 6815b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 6816b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 6817b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 68184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov newSelectionArgs[0] = arg; 68194a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length); 6820b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 6821b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 6822b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 6823caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 68245e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar private String[] appendProjectionArg(String[] projection, String arg) { 68255e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection == null) { 68265e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return null; 68275e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 68285e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar final int length = projection.length; 68295e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar String[] newProjection = new String[length + 1]; 68305e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar System.arraycopy(projection, 0, newProjection, 0, length); 68315e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar newProjection[length] = arg; 68325e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return newProjection; 68335e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 68345e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 6835caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov protected Account getDefaultAccount() { 6836caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov AccountManager accountManager = AccountManager.get(getContext()); 6837caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov try { 68385f1f4a062ac34d75d2dbf586702cbeb121cf09caDmitri Plotnikov Account[] accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE); 6839caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov if (accounts != null && accounts.length > 0) { 6840caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov return accounts[0]; 6841caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 6842caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } catch (Throwable e) { 68436f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov Log.e(TAG, "Cannot determine the default account for contacts compatibility", e); 6844caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 68456f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov return null; 6846caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 6847f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 684873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov /** 684973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov * Returns true if the specified account type is writable. 685073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov */ 685173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov protected boolean isWritableAccount(String accountType) { 6852bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov if (accountType == null) { 6853bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov return true; 6854bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov } 6855bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov 685673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov Boolean writable = mAccountWritability.get(accountType); 685773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable != null) { 685873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 685973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 686073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 6861627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov IContentService contentService = ContentResolver.getContentService(); 6862627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 6863627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) { 6864627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov if (ContactsContract.AUTHORITY.equals(sync.authority) && 686573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov accountType.equals(sync.accountType)) { 686673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = sync.supportsUploading(); 686773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov break; 6868627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 6869627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 6870627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } catch (RemoteException e) { 6871627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov Log.e(TAG, "Could not acquire sync adapter types"); 6872627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 687373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 687473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable == null) { 687573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = false; 687673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 687773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 687873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.put(accountType, writable); 687973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 6880627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 6881b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov 6882d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 6883f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter, 6884f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean defaultValue) { 6885f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6886f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov // Manually parse the query, which is much faster than calling uri.getQueryParameter 6887f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 6888f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 6889f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 6890f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6891f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6892f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = query.indexOf(parameter); 6893f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 6894f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 6895f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6896f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6897f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameter.length(); 6898f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6899f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return !matchQueryParameter(query, index, "=0", false) 6900f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && !matchQueryParameter(query, index, "=false", true); 6901f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6902f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6903f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private static boolean matchQueryParameter(String query, int index, String value, 6904f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean ignoreCase) { 6905f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int length = value.length(); 6906f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return query.regionMatches(ignoreCase, index, value, 0, length) 6907f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && (query.length() == index + length || query.charAt(index + length) == '&'); 6908f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6909f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6910f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /** 6911f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * A fast re-implementation of {@link Uri#getQueryParameter} 6912f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov */ 6913f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static String getQueryParameter(Uri uri, String parameter) { 6914f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 6915f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 6916f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 6917f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6918f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6919f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int queryLength = query.length(); 6920f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int parameterLength = parameter.length(); 6921f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6922f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String value; 6923f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = 0; 6924f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov while (true) { 6925f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index = query.indexOf(parameter, index); 6926f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 6927f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 69285fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 69295fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa 69305fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // Should match against the whole parameter instead of its suffix. 69315fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // e.g. The parameter "param" must not be found in "some_param=val". 69325fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (index > 0) { 69335fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa char prevChar = query.charAt(index - 1); 69345fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (prevChar != '?' && prevChar != '&') { 69355fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // With "some_param=val1¶m=val2", we should find second "param" occurrence. 69365fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa index += parameterLength; 69375fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa continue; 69385fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 6939f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6940f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6941f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameterLength; 6942f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6943f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (queryLength == index) { 6944f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 6945f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6946f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6947f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query.charAt(index) == '=') { 6948f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index++; 6949f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov break; 6950f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6951f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6952f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6953f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int ampIndex = query.indexOf('&', index); 6954f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (ampIndex == -1) { 6955f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index); 6956f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } else { 6957f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index, ampIndex); 6958f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6959f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6960f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return Uri.decode(value); 6961f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 69625dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 69630dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov protected boolean isAggregationUpgradeNeeded() { 69640dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov if (!mContactAggregator.isEnabled()) { 69650dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return false; 69660dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 69670dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 69680dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_AGGREGATION_ALGORITHM, "1")); 69690dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return version < PROPERTY_AGGREGATION_ALGORITHM_VERSION; 69700dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 69710dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 6972bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void upgradeAggregationAlgorithmInBackground() { 69730dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // This upgrade will affect very few contacts, so it can be performed on the 69740dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // main thread during the initial boot after an OTA 69750dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 69760dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Upgrading aggregation algorithm"); 69770dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int count = 0; 69780dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long start = SystemClock.currentThreadTimeMillis(); 69790dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 698049d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov mDb = mDbHelper.getWritableDatabase(); 69810dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.beginTransaction(); 69820dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Cursor cursor = mDb.query(true, 69830dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Tables.RAW_CONTACTS + " r1 JOIN " + Tables.RAW_CONTACTS + " r2", 69840dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov new String[]{"r1." + RawContacts._ID}, 69850dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov "r1." + RawContacts._ID + "!=r2." + RawContacts._ID + 69860dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.CONTACT_ID + "=r2." + RawContacts.CONTACT_ID + 69870dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.ACCOUNT_NAME + "=r2." + RawContacts.ACCOUNT_NAME + 69880dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.ACCOUNT_TYPE + "=r2." + RawContacts.ACCOUNT_TYPE, 69890dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov null, null, null, null, null); 69900dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 69910dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov while (cursor.moveToNext()) { 69920dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long rawContactId = cursor.getLong(0); 69930dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, 69940dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 69950dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov count++; 69960dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 69970dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 69980dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov cursor.close(); 69990dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 7000bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateInTransaction(mTransactionContext, mDb); 7001bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 70020dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.setTransactionSuccessful(); 70030dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDbHelper.setProperty(PROPERTY_AGGREGATION_ALGORITHM, 70040dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov String.valueOf(PROPERTY_AGGREGATION_ALGORITHM_VERSION)); 70050dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 70060dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.endTransaction(); 70070dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long end = SystemClock.currentThreadTimeMillis(); 70080dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Aggregation algorithm upgraded for " + count 70090dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov + " contacts, in " + (end - start) + "ms"); 70100dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 70110dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 70129a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 70139a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov /* Visible for testing */ 70149a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean isPhone() { 70159a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (!sIsPhoneInitialized) { 70169a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhone = new TelephonyManager(getContext()).isVoiceCapable(); 70179a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhoneInitialized = true; 70189a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 70199a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return sIsPhone; 70209a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 702146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 702246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private boolean handleDataUsageFeedback(Uri uri) { 702346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final long currentTimeMillis = System.currentTimeMillis(); 702446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 702546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] ids = uri.getLastPathSegment().trim().split(","); 702646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ArrayList<Long> dataIds = new ArrayList<Long>(); 702746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 702846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (String id : ids) { 702946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa dataIds.add(Long.valueOf(id)); 703046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 703146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final boolean successful; 703246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (TextUtils.isEmpty(usageType)) { 703346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.w(TAG, "Method for data usage feedback isn't specified. Ignoring."); 703446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = false; 703546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 703646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = updateDataUsageStat(dataIds, usageType, currentTimeMillis) > 0; 703746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 703846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 703946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Handle old API. This doesn't affect the result of this entire method. 704046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] questionMarks = new String[ids.length]; 704146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Arrays.fill(questionMarks, "?"); 704246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = Data._ID + " IN (" + TextUtils.join(",", questionMarks) + ")"; 704346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final Cursor cursor = mDb.query( 7044ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA, 704546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { Data.CONTACT_ID }, 704646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa where, ids, null, null, null); 704746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 704846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa while (cursor.moveToNext()) { 704946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mSelectionArgs1[0] = cursor.getString(0); 705046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa ContentValues values2 = new ContentValues(); 705146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values2.put(Contacts.LAST_TIME_CONTACTED, currentTimeMillis); 705246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.update(Tables.CONTACTS, values2, Contacts._ID + "=?", mSelectionArgs1); 705346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 705446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 705546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 705646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 705746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 705846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 705946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 706046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return successful; 706146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 706246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 706346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 706446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Update {@link Tables#DATA_USAGE_STAT}. 706546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * 706646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @return the number of rows affected. 706746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 7068f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa @VisibleForTesting 7069f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa /* package */ int updateDataUsageStat( 7070f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa List<Long> dataIds, String type, long currentTimeMillis) { 707146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final int typeInt = sDataUsageTypeMap.get(type); 707246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = DataUsageStatColumns.DATA_ID + " =? AND " 707346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT + " =?"; 707446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] columns = 707546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { DataUsageStatColumns._ID, DataUsageStatColumns.TIMES_USED }; 707646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ContentValues values = new ContentValues(); 707746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (Long dataId : dataIds) { 707846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] args = new String[] { dataId.toString(), String.valueOf(typeInt) }; 707946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.beginTransaction(); 708046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 708146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final Cursor cursor = mDb.query(Tables.DATA_USAGE_STAT, columns, where, args, 708246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa null, null, null); 708346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 708446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (cursor.getCount() > 0) { 708546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!cursor.moveToFirst()) { 708646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.e(TAG, 708746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa "moveToFirst() failed while getAccount() returned non-zero."); 708846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 708946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 709046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, cursor.getInt(1) + 1); 709146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 709246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.update(Tables.DATA_USAGE_STAT, values, 709346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns._ID + " =?", 709446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { cursor.getString(0) }); 709546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 709646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 709746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 709846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.DATA_ID, dataId); 709946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.USAGE_TYPE_INT, typeInt); 710046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, 1); 710146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 710246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.insert(Tables.DATA_USAGE_STAT, null, values); 710346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 710446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.setTransactionSuccessful(); 710546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 710646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 710746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 710846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 710946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.endTransaction(); 711046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 711146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 711246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 711346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return dataIds.size(); 711446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 711546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 711646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 711746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Returns a sort order String for promoting data rows (email addresses, phone numbers, etc.) 711846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * associated with a primary account. The primary account should be supplied from applications 711946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * with {@link ContactsContract#PRIMARY_ACCOUNT_NAME} and 712046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * {@link ContactsContract#PRIMARY_ACCOUNT_TYPE}. Null will be returned when the primary 712146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * account isn't available. 712246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 712346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private String getAccountPromotionSortOrder(Uri uri) { 712446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountName = 712546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME); 712646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountType = 712746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE); 712846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 712946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Data rows associated with primary account should be promoted. 713046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountName)) { 713146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa StringBuilder sb = new StringBuilder(); 713246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append("(CASE WHEN " + RawContacts.ACCOUNT_NAME + "="); 713346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountName); 713446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountType)) { 713546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 713646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountType); 713746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 713846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" THEN 0 ELSE 1 END)"); 713946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return sb.toString(); 714046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 714146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return null; 714246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 714346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 71444f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 7145