ContactsProvider2.java revision 45ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ec
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 22645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final String FREQUENT_ORDER_BY = DataUsageStatColumns.TIMES_USED + " DESC," 22745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 22845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 2296e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE = 2309b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.CONTACTS + " SET " + Contacts.TIMES_CONTACTED + "=" + 2319b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " CASE WHEN " + Contacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " + 2329b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " (" + Contacts.TIMES_CONTACTED + " + 1) END WHERE " + Contacts._ID + "=?"; 2339b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 2346e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE = 2359b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.RAW_CONTACTS + " SET " + RawContacts.TIMES_CONTACTED + "=" + 2369b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " CASE WHEN " + RawContacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " + 2379b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " (" + RawContacts.TIMES_CONTACTED + " + 1) END WHERE " + RawContacts.CONTACT_ID + "=?"; 2389b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 239de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK"; 240de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa 2413716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Regex for splitting query strings - we split on any group of non-alphanumeric characters, 2423716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // excluding the @ symbol. 2433716f1447ceb21180d1301790eabd8b9453f486dDave Santoro /* package */ static final String QUERY_TOKENIZER_REGEX = "[^\\w@]+"; 2443716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 245d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS = 1000; 246d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS_ID = 1001; 2475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP = 1002; 2485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP_ID = 1003; 249a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_DATA = 1004; 2505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_FILTER = 1005; 2515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT = 1006; 2525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT_FILTER = 1007; 2535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_GROUP = 1008; 254a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_PHOTO = 1009; 255f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_DISPLAY_PHOTO = 1010; 256f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_DISPLAY_PHOTO = 1011; 257f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_DISPLAY_PHOTO = 1012; 258f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_AS_VCARD = 1013; 259f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_AS_MULTI_VCARD = 1014; 260f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_DATA = 1015; 261f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_DATA = 1016; 262f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_ENTITIES = 1017; 263f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ENTITIES = 1018; 264f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_ENTITIES = 1019; 265f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_STREAM_ITEMS = 1020; 266f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_STREAM_ITEMS = 1021; 267f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_STREAM_ITEMS = 1022; 26845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final int CONTACTS_FREQUENT = 1023; 2694f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2705ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS = 2002; 2715ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_ID = 2003; 2725ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_DATA = 2004; 27346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITY_ID = 2005; 274f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_DISPLAY_PHOTO = 2006; 275f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS = 2007; 2764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2776bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 2786bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 279ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 28048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_ID = 3003; 28148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_FILTER = 3004; 28248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS = 3005; 28348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_ID = 3006; 28448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_LOOKUP = 3007; 28548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_FILTER = 3008; 28648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS = 3009; 28748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS_ID = 3010; 288a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 2906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 291b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 292b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 293b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 29482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES = 7000; 29582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES_ID = 7001; 2961f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 29731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 29831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 299eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey private static final int SETTINGS = 9000; 300eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 301ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 302ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 303ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 304ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 30535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 306b5a4add17815167d20a90645779df34cdf45280dFred Quintana private static final int SYNCSTATE_ID = 11001; 30735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 308c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SUGGESTIONS = 12001; 309c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SHORTCUT = 12002; 310c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 3111b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS = 14000; 3121b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001; 3131b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002; 3141b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003; 3151b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 31646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITIES = 15001; 31746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 31809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private static final int PROVIDER_STATUS = 16001; 31909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 320d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES = 17001; 321d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES_ID = 17002; 322d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 3237a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private static final int COMPLETE_NAME = 18000; 3247a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 32524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE = 19000; 32624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_ENTITIES = 19001; 32724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA = 19002; 32824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA_ID = 19003; 32924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_AS_VCARD = 19004; 33024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS = 19005; 33124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID = 19006; 33224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_DATA = 19007; 33324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_ENTITIES = 19008; 33424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 33546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final int DATA_USAGE_FEEDBACK_ID = 20001; 33646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 3373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS = 21000; 3383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_PHOTOS = 21001; 3393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID = 21002; 3403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS = 21003; 3413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS_ID = 21004; 3423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_LIMIT = 21005; 3433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 344f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int DISPLAY_PHOTO = 22000; 345f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_DIMENSIONS = 22001; 346f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 347dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID = 348dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 349dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME 350dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "=" + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 351dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE 352dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "=" + RawContactsColumns.CONCRETE_ACCOUNT_TYPE 353dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND " + Groups.FAVORITES + " != 0"; 354dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 355dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID = 356dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 357dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 358dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 359dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 360dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND " 361dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + Groups.AUTO_ADD + " != 0"; 362dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 363dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String[] PROJECTION_GROUP_ID 364dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana = new String[]{Tables.GROUPS + "." + Groups._ID}; 365dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 366dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_GROUPMEMBERSHIP_DATA = DataColumns.MIMETYPE_ID + "=? " 367dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.GROUP_ROW_ID + "=? " 368dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.RAW_CONTACT_ID + "=?"; 369dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 370dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_STARRED_FROM_RAW_CONTACTS = 371dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana "SELECT " + RawContacts.STARRED 372dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " FROM " + Tables.RAW_CONTACTS + " WHERE " + RawContacts._ID + "=?"; 373dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 374e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public class AddressBookCursor extends CursorWrapper implements CrossProcessCursor { 375e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov private final CrossProcessCursor mCursor; 376e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov private final Bundle mBundle; 377e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 378e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public AddressBookCursor(CrossProcessCursor cursor, String[] titles, int[] counts) { 379e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov super(cursor); 380e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mCursor = cursor; 381e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle = new Bundle(); 382e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle.putStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES, titles); 383e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle.putIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, counts); 384e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 385e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 386e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 387e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public Bundle getExtras() { 388e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mBundle; 389e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 390e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 391e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 392e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public void fillWindow(int pos, CursorWindow window) { 393e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mCursor.fillWindow(pos, window); 394e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 395e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 396e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 397e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public CursorWindow getWindow() { 398e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mCursor.getWindow(); 399e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 400e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 401e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 402e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public boolean onMove(int oldPosition, int newPosition) { 403e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mCursor.onMove(oldPosition, newPosition); 404e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 405e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 406e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 407d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private interface DataContactsQuery { 408f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov public static final String TABLE = "data " 409f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) " 410f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)"; 41167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 41267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 4136cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov RawContactsColumns.CONCRETE_ID, 4146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_TYPE, 4156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_NAME, 4163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 417f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov ContactsColumns.CONCRETE_ID 418ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 419ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 420d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov public static final int RAW_CONTACT_ID = 0; 4216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_TYPE = 1; 4226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_NAME = 2; 4236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int DATA_ID = 3; 4246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int CONTACT_ID = 4; 425ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 4261f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 427f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov interface RawContactsQuery { 42819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String TABLE = Tables.RAW_CONTACTS; 42919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 43019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String[] COLUMNS = new String[] { 431ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.DELETED, 432ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 433ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_NAME, 43419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka }; 43519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 43619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int DELETED = 0; 437ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_TYPE = 1; 438ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_NAME = 2; 43919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 44019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 441c76cdd0723b99f478c9ba5329d14a971cd8dfb3dCostin Manolache public static final String DEFAULT_ACCOUNT_TYPE = "com.google"; 442caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 44371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov /** Sql where statement for filtering on groups. */ 44471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov private static final String CONTACTS_IN_GROUP_SELECT = 44571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov Contacts._ID + " IN " 44671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + RawContacts.CONTACT_ID 44771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.RAW_CONTACTS 44871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN " 44971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 45071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.DATA_JOIN_MIMETYPES 45171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 45271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 45371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + Tables.GROUPS + "." + Groups._ID 45471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.GROUPS 45571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Groups.TITLE + "=?)))"; 45671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov 457a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating DIRTY flag on multiple raw contacts */ 458a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_DIRTY_SQL = 459a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 460a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.DIRTY + "=1" + 461a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 462a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 463a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating VERSION on multiple raw contacts */ 464a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL = 465a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 466a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.VERSION + " = " + RawContacts.VERSION + " + 1" + 467a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 468a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 469c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Current contacts - those contacted within the last 3 days (in seconds) 470c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_CURRENT = 3 * 24 * 60 * 60; 471c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 472c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Recent contacts - those contacted within the last 30 days (in seconds) 473c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_RECENT = 30 * 24 * 60 * 60; 474c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 475f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa private static final String TIME_SINCE_LAST_USED = 476f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa "(strftime('%s', 'now') - " + DataUsageStatColumns.LAST_TIME_USED + "/1000)"; 477f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa 478c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov /* 479c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * Sorting order for email address suggestions: first starred, then the rest. 4802262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * second in_visible_group, then the rest. 4812262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * Within the four (starred/unstarred, in_visible_group/not-in_visible_group) groups 4822262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * - three buckets: very recently contacted, then fairly 483c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * recently contacted, then the rest. Within each of the bucket - descending count 48446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * of times contacted (both for data row and for contact row). If all else fails, alphabetical. 48546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * (Super)primary email address is returned before other addresses for the same contact. 486c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov */ 487c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final String EMAIL_FILTER_SORT_ORDER = 4882262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa Contacts.STARRED + " DESC, " 4892262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa + Contacts.IN_VISIBLE_GROUP + " DESC, " 490f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + "(CASE WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_CURRENT 49146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 0 " 492f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + " WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_RECENT 49346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 1 " 49446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " ELSE 2 END), " 49546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.TIMES_USED + " DESC, " 49646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Contacts.DISPLAY_NAME + ", " 49746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Data.CONTACT_ID + ", " 498c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_SUPER_PRIMARY + " DESC, " 499c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_PRIMARY + " DESC"; 50046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 50146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** Currently same as {@link #EMAIL_FILTER_SORT_ORDER} */ 50246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final String PHONE_FILTER_SORT_ORDER = EMAIL_FILTER_SORT_ORDER; 503c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 504916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Name lookup types used for contact filtering */ 505916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private static final String CONTACT_LOOKUP_NAME_TYPES = 506916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.NAME_COLLATION_KEY + "," + 507916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.EMAIL_BASED_NICKNAME + "," + 50892ddc5cdc4d89ee2c6e861ae7b3a3a913ffa0100Dmitri Plotnikov NameLookupType.NICKNAME; 509916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 510f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov /** 511f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * If any of these columns are used in a Data projection, there is no point in 512f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * using the DISTINCT keyword, which can negatively affect performance. 513f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov */ 514f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov private static final String[] DISTINCT_DATA_PROHIBITING_COLUMNS = { 515f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data._ID, 516f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.RAW_CONTACT_ID, 517f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.NAME_RAW_CONTACT_ID, 518f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 519f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 520f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.DIRTY, 521f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.NAME_VERIFIED, 522f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.SOURCE_ID, 523f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.VERSION, 524f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov }; 525916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 526f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsColumns = ProjectionMap.builder() 527f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CUSTOM_RINGTONE) 528f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME) 529f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_ALTERNATIVE) 530f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_SOURCE) 531f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.IN_VISIBLE_GROUP) 532f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LAST_TIME_CONTACTED) 533f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LOOKUP_KEY) 534f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME) 535f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME_STYLE) 536f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHOTO_ID) 537f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .add(Contacts.PHOTO_FILE_ID) 5383d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_URI) 5393d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_THUMBNAIL_URI) 540f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SEND_TO_VOICEMAIL) 541f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_ALTERNATIVE) 542f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_PRIMARY) 543f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.STARRED) 544f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.TIMES_CONTACTED) 545cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 546f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 547f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 548f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsPresenceColumns = ProjectionMap.builder() 549f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 550f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE) 551f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 552f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 553f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 554f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 555f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 556f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 557f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 558f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 559f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 560f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 561f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 562f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 563f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 564f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 565f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSnippetColumns = ProjectionMap.builder() 56603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov .add(SearchSnippetColumns.SNIPPET) 567f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 568f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 569f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactColumns = ProjectionMap.builder() 570f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_NAME) 571f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_TYPE) 572f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DIRTY) 573f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.NAME_VERIFIED) 574f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SOURCE_ID) 575f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.VERSION) 576f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 577f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 578f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactSyncColumns = ProjectionMap.builder() 579f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC1) 580f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC2) 581f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC3) 582f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC4) 583f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 584f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 585f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataColumns = ProjectionMap.builder() 586f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA1) 587f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA2) 588f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA3) 589f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA4) 590f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA5) 591f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA6) 592f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA7) 593f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA8) 594f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA9) 595f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA10) 596f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA11) 597f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA12) 598f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA13) 599f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA14) 600f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA15) 601f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA_VERSION) 602f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_PRIMARY) 603f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_SUPER_PRIMARY) 604f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.MIMETYPE) 605f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RES_PACKAGE) 606f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC1) 607f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC2) 608f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC3) 609f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC4) 610f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(GroupMembership.GROUP_SOURCE_ID) 611f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 612f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 613f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactPresenceColumns = ProjectionMap.builder() 614f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 615f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.PRESENCE) 616f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 617f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.CHAT_CAPABILITY) 618f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 619f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 620f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 621f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 622f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 623f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 624f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 625f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 626f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 627f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 628f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 629f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 630f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataPresenceColumns = ProjectionMap.builder() 631f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.PRESENCE, Tables.PRESENCE + "." + StatusUpdates.PRESENCE) 632f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CHAT_CAPABILITY, Tables.PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 633f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS, StatusUpdatesColumns.CONCRETE_STATUS) 634f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_TIMESTAMP, StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 635f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_RES_PACKAGE, StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 636f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_LABEL, StatusUpdatesColumns.CONCRETE_STATUS_LABEL) 637f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_ICON, StatusUpdatesColumns.CONCRETE_STATUS_ICON) 638f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 639f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 640038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana /** Contains just BaseColumns._COUNT */ 641f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sCountProjectionMap = ProjectionMap.builder() 642f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(BaseColumns._COUNT, "COUNT(*)") 643f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 644f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 645e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov /** Contains just the contacts columns */ 646f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionMap = ProjectionMap.builder() 647f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts._ID) 648f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 649f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.NAME_RAW_CONTACT_ID) 65024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 651f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 652f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsPresenceColumns) 653f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 654f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 655916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Contains just the contacts columns */ 656f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionWithSnippetMap = ProjectionMap.builder() 657f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 658f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sSnippetColumns) 659f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 660916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6615e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar /** Used for pushing starred contacts to the top of a times contacted list **/ 662f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentStarredProjectionMap = ProjectionMap.builder() 663f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 6642f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 665f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 666f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 667f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder() 668f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 6692f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, "SUM(" + DataUsageStatColumns.CONCRETE_TIMES_USED + ")") 670f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 671f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 6724928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 6734928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 6744928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. Right now Starred part just returns NULL for 6754928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * those data columns (frequent part should return real ones in data table). 6764928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 6774928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyStarredProjectionMap 6784928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 6794928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 6804928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 6814928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER, "NULL") 6824928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE, "NULL") 6834928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL, "NULL") 6844928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 6854928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 6864928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 6874928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 6884928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. We hard-code {@link Contacts#IS_USER_PROFILE} to NULL, 6894928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * because sContactsProjectionMap specifies a field that doesn't exist in the view behind the 6904928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * query that uses this projection map. 6914928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 6924928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyFrequentProjectionMap 6934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 6944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 6954928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, DataUsageStatColumns.CONCRETE_TIMES_USED) 6964928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER) 6974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE) 6984928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL) 6994928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Contacts.IS_USER_PROFILE, "NULL") 7004928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7014928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 702f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey /** Contains just the contacts vCard columns */ 703f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsVCardProjectionMap = ProjectionMap.builder() 704fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen .add(Contacts._ID) 705f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME + " || '.vcf'") 706f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.SIZE, "NULL") 707f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 708f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 709ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov /** Contains just the raw contacts columns */ 710f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactsProjectionMap = ProjectionMap.builder() 711f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 712f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 713f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 714f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_PRIMARY) 715f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_ALTERNATIVE) 716f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_SOURCE) 717f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME) 718f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME_STYLE) 719f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_PRIMARY) 720f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_ALTERNATIVE) 721f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.TIMES_CONTACTED) 722f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.LAST_TIME_CONTACTED) 723f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CUSTOM_RINGTONE) 724f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SEND_TO_VOICEMAIL) 725f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 726f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.AGGREGATION_MODE) 72724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 728f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 729f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 730f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 731f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 732a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the raw entity view*/ 733f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawEntityProjectionMap = ProjectionMap.builder() 734f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 735f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 736f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.Entity.DATA_ID) 737f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 738f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 73924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 740f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 741f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 742f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 743f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 744f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 745a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the contact entity view*/ 746f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sEntityProjectionMap = ProjectionMap.builder() 747f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity._ID) 748f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.CONTACT_ID) 749f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.RAW_CONTACT_ID) 750f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DATA_ID) 751f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.NAME_RAW_CONTACT_ID) 752f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DELETED) 75324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 754f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 755f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 756f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 757f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 758f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 759f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 760f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 761f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** Contains columns from the data view */ 763f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataProjectionMap = ProjectionMap.builder() 764f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID) 765f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RAW_CONTACT_ID) 766f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CONTACT_ID) 767f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.NAME_RAW_CONTACT_ID) 76824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 769f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 770f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 771f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 772f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 773f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 774f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 775f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7765e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov /** Contains columns from the data view */ 777f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDistinctDataProjectionMap = ProjectionMap.builder() 778f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID, "MIN(" + Data._ID + ")") 779f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 78024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 781f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 782f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 783f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 784f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 785f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 786f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7879261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data and contacts columns, for joined tables */ 788f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sPhoneLookupProjectionMap = ProjectionMap.builder() 789f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup._ID, "contacts_view." + Contacts._ID) 790f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LOOKUP_KEY, "contacts_view." + Contacts.LOOKUP_KEY) 791f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.DISPLAY_NAME, "contacts_view." + Contacts.DISPLAY_NAME) 792f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LAST_TIME_CONTACTED, "contacts_view." + Contacts.LAST_TIME_CONTACTED) 793f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TIMES_CONTACTED, "contacts_view." + Contacts.TIMES_CONTACTED) 794f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.STARRED, "contacts_view." + Contacts.STARRED) 795f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.IN_VISIBLE_GROUP, "contacts_view." + Contacts.IN_VISIBLE_GROUP) 796f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.PHOTO_ID, "contacts_view." + Contacts.PHOTO_ID) 7973d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_URI, "contacts_view." + Contacts.PHOTO_URI) 7983d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_THUMBNAIL_URI, "contacts_view." + Contacts.PHOTO_THUMBNAIL_URI) 799f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.CUSTOM_RINGTONE, "contacts_view." + Contacts.CUSTOM_RINGTONE) 800f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.HAS_PHONE_NUMBER, "contacts_view." + Contacts.HAS_PHONE_NUMBER) 801f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.SEND_TO_VOICEMAIL, "contacts_view." + Contacts.SEND_TO_VOICEMAIL) 802f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.NUMBER, Phone.NUMBER) 803f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TYPE, Phone.TYPE) 804f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LABEL, Phone.LABEL) 8052530512f639c4979fd7371c7dd25dd67e8118124Bai Tao .add(PhoneLookup.NORMALIZED_NUMBER, Phone.NORMALIZED_NUMBER) 806f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 807f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 808ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 809f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsProjectionMap = ProjectionMap.builder() 810f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups._ID) 811f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_NAME) 812f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_TYPE) 813f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SOURCE_ID) 814f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DIRTY) 815f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.VERSION) 816f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.RES_PACKAGE) 817f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE) 818f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE_RES) 819f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.GROUP_VISIBLE) 820f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYSTEM_ID) 821f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DELETED) 822f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.NOTES) 8231cdfc9dacc136e99d3c0bc5b4212bc3c973be337Daniel Lehmann .add(Groups.ACTION) 8241cdfc9dacc136e99d3c0bc5b4212bc3c973be337Daniel Lehmann .add(Groups.ACTION_URI) 825f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SHOULD_SYNC) 826f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.FAVORITES) 827f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.AUTO_ADD) 828c039cfb78c40730483fd71178df63ada5826a315Dmitri Plotnikov .add(Groups.GROUP_IS_READ_ONLY) 829f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC1) 830f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC2) 831f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC3) 832f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC4) 833f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 834f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 835ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains {@link Groups} columns along with summary details */ 836f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsSummaryProjectionMap = ProjectionMap.builder() 837f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sGroupsProjectionMap) 838f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_COUNT, 839f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID 840f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS 841f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP 842f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + Clauses.BELONGS_TO_GROUP 843f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ")") 844f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_WITH_PHONES, 845f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID 846f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS 847f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP 848f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + Clauses.BELONGS_TO_GROUP 849f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + Contacts.HAS_PHONE_NUMBER + ")") 850f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 851f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 852373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov /** Contains the agg_exceptions columns */ 853f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sAggregationExceptionsProjectionMap = ProjectionMap.builder() 854f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id") 855f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.TYPE) 856f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID1) 857f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID2) 858f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 859f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 860eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey /** Contains the agg_exceptions columns */ 861f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSettingsProjectionMap = ProjectionMap.builder() 862f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_NAME) 863f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_TYPE) 864f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_VISIBLE) 865f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.SHOULD_SYNC) 866f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ANY_UNSYNCED, 867f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN MIN(" + Settings.SHOULD_SYNC 868f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ",(SELECT " 869f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "(CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL" 870f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 871f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE MIN(" + Groups.SHOULD_SYNC + ")" 872f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)" 873f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.GROUPS 874f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 875f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_NAME 876f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 877f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_TYPE + "))=0" 878f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 879f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE 0" 880f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)") 881f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_COUNT, 882f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 883f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 884f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 885f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 886f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 887f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 888f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_WITH_PHONES, 889f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 890f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 891f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 892f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Contacts.HAS_PHONE_NUMBER 893f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 894f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 895f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 896f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 897f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 89882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov /** Contains StatusUpdates columns */ 899f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStatusUpdatesProjectionMap = ProjectionMap.builder() 900f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PresenceColumns.RAW_CONTACT_ID) 901f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.DATA_ID, DataColumns.CONCRETE_ID) 902f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_ACCOUNT) 903f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_HANDLE) 904f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PROTOCOL) 905f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 906f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // properly enforce uniqueness of null values 907f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CUSTOM_PROTOCOL, 908f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL + "=''" 909f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN NULL" 910f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END)") 911f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PRESENCE) 912f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CHAT_CAPABILITY) 913f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS) 914f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_TIMESTAMP) 915f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_RES_PACKAGE) 916f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_ICON) 917f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_LABEL) 918f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 919f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 9203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Contains StreamItems columns */ 9213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemsProjectionMap = ProjectionMap.builder() 9223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems._ID, StreamItemsColumns.CONCRETE_ID) 9233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(RawContacts.CONTACT_ID) 9243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_PACKAGE) 9263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_ICON) 9273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_LABEL) 9283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TEXT) 9293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TIMESTAMP) 9303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.COMMENTS) 9313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.ACTION) 9323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.ACTION_URI) 9333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemPhotosProjectionMap = ProjectionMap.builder() 9363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos._ID, StreamItemPhotosColumns.CONCRETE_ID) 9373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.STREAM_ITEM_ID) 9393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.SORT_INDEX) 9406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_FILE_ID) 9416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_URI, 9426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro "'" + DisplayPhoto.CONTENT_URI + "'||'/'||" + StreamItemPhotos.PHOTO_FILE_ID) 9433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.ACTION, StreamItemPhotosColumns.CONCRETE_ACTION) 9443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.ACTION_URI, StreamItemPhotosColumns.CONCRETE_ACTION_URI) 9451dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.HEIGHT) 9461dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.WIDTH) 9471dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.FILESIZE) 9483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9501b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov /** Contains Live Folders columns */ 951f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sLiveFoldersProjectionMap = ProjectionMap.builder() 952f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders._ID, Contacts._ID) 953f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders.NAME, Contacts.DISPLAY_NAME) 954f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // TODO: Put contact photo back when we have a way to display a default icon 955f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // for contacts without a photo 956f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // .add(LiveFolders.ICON_BITMAP, Photos.DATA) 957f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 958f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 959d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** Contains {@link Directory} columns */ 960f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDirectoryProjectionMap = ProjectionMap.builder() 961f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory._ID) 962f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.PACKAGE_NAME) 963f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.TYPE_RESOURCE_ID) 964f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DISPLAY_NAME) 965f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DIRECTORY_AUTHORITY) 966f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_TYPE) 967f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_NAME) 968f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.EXPORT_SUPPORT) 969778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.SHORTCUT_SUPPORT) 970778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.PHOTO_SUPPORT) 971f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 9727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 9739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // where clause to update the status_updates table 9749705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE = 9759705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID + 9769705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE + 9779705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE "; 9789705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 9792526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private static final String[] EMPTY_STRING_ARRAY = new String[0]; 9802526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 981bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 982bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Notification ID for failure to import contacts. 983bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 984bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private static final int LEGACY_IMPORT_FAILED_NOTIFICATION = 1; 98551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 98603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_START_MATCH = "["; 98703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_END_MATCH = "]"; 98803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_ELLIPSIS = "..."; 98903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final int DEFAULT_SNIPPET_ARG_MAX_TOKENS = -10; 99003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 9919a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhoneInitialized; 9929a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhone; 9939a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 994f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov private StringBuilder mSb = new StringBuilder(); 9951129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs1 = new String[1]; 9961129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs2 = new String[2]; 9972526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private ArrayList<String> mSelectionArgs = Lists.newArrayList(); 9982526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 999f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private Account mAccount; 1000f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 100146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 100246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Stores mapping from type Strings exposed via {@link DataUsageFeedback} to 100346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type integers in {@link DataUsageStatColumns}. 100446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 100546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final Map<String, Integer> sDataUsageTypeMap; 100646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 10074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 10084f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 1009a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 1010d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 1011d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 1012a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA); 1013a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES); 10143653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", 10153653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 10162d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", 10172d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov AGGREGATION_SUGGESTIONS); 1018a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO); 1019f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", 1020f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_ID_DISPLAY_PHOTO); 10213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", 10223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_ID_STREAM_ITEMS); 1023c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER); 10245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER); 10255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP); 10262149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA); 10275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID); 10282149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", 10292149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov CONTACTS_LOOKUP_ID_DATA); 1030f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", 1031f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_DISPLAY_PHOTO); 1032f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo", 1033f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_ID_DISPLAY_PHOTO); 1034a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities", 1035a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ENTITIES); 1036a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities", 1037a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ID_ENTITIES); 10383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items", 10393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_STREAM_ITEMS); 10403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items", 10413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_ID_STREAM_ITEMS); 1042f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD); 104342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*", 104442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann CONTACTS_AS_MULTI_VCARD); 10455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT); 1046ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*", 1047ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov CONTACTS_STREQUENT_FILTER); 10485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP); 104945ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "contacts/frequent", CONTACTS_FREQUENT); 10503653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 10515ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); 10525ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); 10535ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA); 1054f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/display_photo", 1055f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro RAW_CONTACTS_ID_DISPLAY_PHOTO); 105646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ENTITY_ID); 10573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items", 10583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RAW_CONTACTS_ID_STREAM_ITEMS); 105946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 106046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES); 1061b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 10624f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 10634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 1064ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 106548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID); 10665e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER); 1067ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 10684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS); 106948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID); 10701dac83b8fa58944acfd00f44e717a7dddc659d2dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP); 10715e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP); 10725e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER); 10734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER); 1074ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 107548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID); 107646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** "*" is in CSV form with data ids ("123,456,789") */ 107746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/usagefeedback/*", DATA_USAGE_FEEDBACK_ID); 10781f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1079ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 1080ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 1081ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 1082ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 108335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 1084b5a4add17815167d20a90645779df34cdf45280dFred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#", 1085b5a4add17815167d20a90645779df34cdf45280dFred Quintana SYNCSTATE_ID); 108635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1087a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 1088b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 1089b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 1090b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 1091b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 10924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1093eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS); 1094eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 109582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES); 109682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID); 10971f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1098c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, 1099c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 1100c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 1101c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 11022d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 1103c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SHORTCUT); 1104c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 11051b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts", 11061b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS); 11071b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*", 11081b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_GROUP_NAME); 11091b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones", 11101b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_WITH_PHONES); 11111b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites", 11121b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_FAVORITES); 111309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 111409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS); 1115d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1116d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES); 1117d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID); 11187a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 11197a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME); 112024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 112124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile", PROFILE); 112224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/entities", PROFILE_ENTITIES); 112324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data", PROFILE_DATA); 112424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data/#", PROFILE_DATA_ID); 112524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/as_vcard", PROFILE_AS_VCARD); 112624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts", PROFILE_RAW_CONTACTS); 112724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#", 112824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID); 112924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/data", 113024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_DATA); 113124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/entity", 113224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_ENTITIES); 113346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 11343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items", STREAM_ITEMS); 11353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/photo", STREAM_ITEMS_PHOTOS); 11363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#", STREAM_ITEMS_ID); 11373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo", STREAM_ITEMS_ID_PHOTOS); 11383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo/#", 11393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann STREAM_ITEMS_ID_PHOTOS_ID); 11403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items_limit", STREAM_ITEMS_LIMIT); 11413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 1142f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "display_photo/*", DISPLAY_PHOTO); 1143f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS); 1144f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 114546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa HashMap<String, Integer> tmpTypeMap = new HashMap<String, Integer>(); 114646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_CALL, DataUsageStatColumns.USAGE_TYPE_INT_CALL); 114746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, 114846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT); 114946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, 115046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT); 115146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sDataUsageTypeMap = Collections.unmodifiableMap(tmpTypeMap); 115219a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov } 115319a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov 1154d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static class DirectoryInfo { 1155d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String authority; 1156d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountName; 1157d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountType; 1158d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 1159d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1160d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 1161d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Cached information about contact directories. 1162d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 11634458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private HashMap<String, DirectoryInfo> mDirectoryCache = new HashMap<String, DirectoryInfo>(); 11644458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private boolean mDirectoryCacheValid = false; 1165d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 11663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 1167ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov * An entry in group id cache. It maps the combination of (account type, account name 1168ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov * and source id) to group row id. 1169ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov */ 1170e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov public static class GroupIdCacheEntry { 1171ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType; 1172ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName; 1173ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String sourceId; 1174ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov long groupId; 1175ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov } 1176a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov 1177e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // We don't need a soft cache for groups - the assumption is that there will only 1178e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // be a small number of contact groups. The cache is keyed off source id. The value 1179e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // is a list of groups with this group id. 1180e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap(); 1181e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov 118224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 118324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Cached information about the contact ID and raw contact IDs that make up the user's 118424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile entry. 118524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 118624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static class ProfileIdCache { 118724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean inited; 118824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long profileContactId; 118924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Set<Long> profileRawContactIds = Sets.newHashSet(); 119024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Set<Long> profileDataIds = Sets.newHashSet(); 119124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 119224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 119324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Initializes the cache of profile contact and raw contact IDs. Does nothing if 119424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * the cache is already initialized (unless forceRefresh is set to true). 119524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param db The contacts database. 119624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forceRefresh Whether to force re-initialization of the cache. 119724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 119824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void init(SQLiteDatabase db, boolean forceRefresh) { 119924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!inited || forceRefresh) { 120024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileContactId = 0; 120124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactIds.clear(); 120224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileDataIds.clear(); 120324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Cursor c = db.rawQuery("SELECT " + 120424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_CONTACT_ID + "," + 120524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "," + 120624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro DataColumns.CONCRETE_ID + 120724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro " FROM " + Tables.RAW_CONTACTS + " JOIN " + Tables.ACCOUNTS + " ON " + 120824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "=" + 120924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro AccountsColumns.PROFILE_RAW_CONTACT_ID + 121024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro " JOIN " + Tables.DATA + " ON " + 121124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "=" + DataColumns.CONCRETE_RAW_CONTACT_ID, 121224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro null); 121324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro try { 121424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro while (c.moveToNext()) { 121524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (profileContactId == 0) { 121624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileContactId = c.getLong(0); 121724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 121824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactIds.add(c.getLong(1)); 121924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileDataIds.add(c.getLong(2)); 122024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 122124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } finally { 122224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro c.close(); 122324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 122424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 122524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 122624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 122724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 122824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private ProfileIdCache mProfileIdCache; 122924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1230f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1231f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of display photos. Larger images will be scaled 1232f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to fit. 1233f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1234f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxDisplayPhotoDim; 1235f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1236f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1237f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of photo thumbnails. 1238f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1239f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxThumbnailPhotoDim; 1240f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private HashMap<String, DataRowHandler> mDataRowHandlers; 1242b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private ContactsDatabaseHelper mDbHelper; 124331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1244f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private PhotoStore mPhotoStore; 1245f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12464097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 1247f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private NameLookupBuilder mNameLookupBuilder; 1248315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov 1249622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private PostalSplitter mPostalSplitter; 1250622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey 125172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov private ContactDirectoryManager mContactDirectoryManager; 1252622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private ContactAggregator mContactAggregator; 1253f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 1254a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private GlobalSearchSupport mGlobalSearchSupport; 1255d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov private CommonNicknameCache mCommonNicknameCache; 1256f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov private SearchIndexManager mSearchIndexManager; 1257a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 125820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private ContentValues mValues = new ContentValues(); 125973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov private HashMap<String, Boolean> mAccountWritability = Maps.newHashMap(); 126020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 126109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private int mProviderStatus = ProviderStatus.STATUS_NORMAL; 12623826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private boolean mProviderStatusUpdateNeeded; 126309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private long mEstimatedStorageRequirement = 0; 126415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mReadAccessLatch; 126515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mWriteAccessLatch; 126615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private boolean mAccountUpdateListenerRegistered; 1267bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private boolean mOkToOpenAccess = true; 126873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 1269d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private TransactionContext mTransactionContext = new TransactionContext(); 1270de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov 12711a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey private boolean mVisibleTouched = false; 12721a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 127381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov private boolean mSyncToNetwork; 127481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 12754cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao private Locale mCurrentLocale; 12763826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private int mContactsAccountCount; 1277d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov 1278bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private HandlerThread mBackgroundThread; 1279bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private Handler mBackgroundHandler; 1280bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1281f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mLastPhotoCleanup = 0; 1282f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 12844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 1285de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov super.onCreate(); 1286ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov try { 1287ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return initialize(); 1288ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } catch (RuntimeException e) { 1289ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov Log.e(TAG, "Cannot start provider", e); 1290ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return false; 1291ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 1292ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 129335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1294ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov private boolean initialize() { 129515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov StrictMode.setThreadPolicy( 129615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 129715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 12983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Resources resources = getContext().getResources(); 1299f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxDisplayPhotoDim = resources.getInteger( 1300f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_display_photo_dim); 1301f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim = resources.getInteger( 1302f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_thumbnail_photo_dim); 13033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 130424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mProfileIdCache = new ProfileIdCache(); 1305b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper = (ContactsDatabaseHelper)getDatabaseHelper(); 130672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov mContactDirectoryManager = new ContactDirectoryManager(this); 1307a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov mGlobalSearchSupport = new GlobalSearchSupport(this); 1308f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mPhotoStore = new PhotoStore(getContext().getFilesDir(), mDbHelper); 130965ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov 1310bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // The provider is closed for business until fully initialized 131115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = new CountDownLatch(1); 131215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = new CountDownLatch(1); 131372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1314bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread = new HandlerThread("ContactsProviderWorker", 1315bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov Process.THREAD_PRIORITY_BACKGROUND); 1316bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread.start(); 1317bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler = new Handler(mBackgroundThread.getLooper()) { 1318bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov @Override 1319bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov public void handleMessage(Message msg) { 1320bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov performBackgroundTask(msg.what, msg.obj); 1321bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1322bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov }; 13232a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov 132415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_INITIALIZE); 1325bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1326bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 1327bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_LOCALE); 1328bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM); 132905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_SEARCH_INDEX); 1330bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_PROVIDER_STATUS); 133115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_OPEN_WRITE_ACCESS); 1332f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 13333826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 133449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov return true; 13354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 13364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1337767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov /** 133851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * (Re)allocates all locale-sensitive structures. 133951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 134004b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov private void initForDefaultLocale() { 134115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 134215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mLegacyApiSupport = new LegacyApiSupport(context, mDbHelper, this, mGlobalSearchSupport); 13434cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mCurrentLocale = getLocale(); 134404b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov mNameSplitter = mDbHelper.createNameSplitter(); 13454cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter); 13464cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mPostalSplitter = new PostalSplitter(mCurrentLocale); 134751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov mCommonNicknameCache = new CommonNicknameCache(mDbHelper.getReadableDatabase()); 1348cdd03b2ba03718a7fa85663a2438136284a1557cBai Tao ContactLocaleUtils.getIntance().setLocale(mCurrentLocale); 13495b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator = new ContactAggregator(this, mDbHelper, 135015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 13515b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 1352f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov mSearchIndexManager = new SearchIndexManager(this); 13535b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 1354bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers = new HashMap<String, DataRowHandler>(); 1355bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1356bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, 13576d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForEmail(context, mDbHelper, mContactAggregator)); 1358bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE, 13596d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForIm(context, mDbHelper, mContactAggregator)); 1360bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, 13616d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForOrganization(context, mDbHelper, mContactAggregator)); 1362bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, 13636d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForPhoneNumber(context, mDbHelper, mContactAggregator)); 1364bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, 13656d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForNickname(context, mDbHelper, mContactAggregator)); 1366bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE, 13676d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForStructuredName(context, mDbHelper, mContactAggregator, 1368bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mNameSplitter, mNameLookupBuilder)); 1369bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(StructuredPostal.CONTENT_ITEM_TYPE, 13706d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForStructuredPostal(context, mDbHelper, mContactAggregator, 1371bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mPostalSplitter)); 1372bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE, 13736d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForGroupMembership(context, mDbHelper, mContactAggregator, 1374bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mGroupIdCache)); 1375bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Photo.CONTENT_ITEM_TYPE, 1376f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new DataRowHandlerForPhoto(context, mDbHelper, mContactAggregator, mPhotoStore)); 13776d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov mDataRowHandlers.put(Note.CONTENT_ITEM_TYPE, 13786d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForNote(context, mDbHelper, mContactAggregator)); 1379bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1380bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1381bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /** 1382bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Visible for testing. 1383bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov */ 1384bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /* package */ PhotoPriorityResolver createPhotoPriorityResolver(Context context) { 1385bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov return new PhotoPriorityResolver(context); 1386bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1387bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1388bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task) { 1389bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendEmptyMessage(task); 1390bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1391bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1392bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task, Object arg) { 1393bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(task, arg)); 1394bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1395bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1396bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void performBackgroundTask(int task, Object arg) { 1397bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov switch (task) { 139815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_INITIALIZE: { 139915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov initForDefaultLocale(); 140015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch.countDown(); 140115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = null; 140215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov break; 140315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 140415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 140515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_OPEN_WRITE_ACCESS: { 1406bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (mOkToOpenAccess) { 140715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch.countDown(); 140815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = null; 1409bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1410bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1411bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1412bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1413bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS: { 1414bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isLegacyContactImportNeeded()) { 1415bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov importLegacyContactsInBackground(); 1416bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1417bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1418bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1419bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1420bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_ACCOUNTS: { 142115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 142215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (!mAccountUpdateListenerRegistered) { 142315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov AccountManager.get(context).addOnAccountsUpdatedListener(this, null, false); 142415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mAccountUpdateListenerRegistered = true; 142515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 142615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 142715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Account[] accounts = AccountManager.get(context).getAccounts(); 1428bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov boolean accountsChanged = updateAccountsInBackground(accounts); 1429bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateContactsAccountCount(accounts); 1430bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateDirectoriesInBackground(accountsChanged); 1431bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1432bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1433bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1434bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_LOCALE: { 1435bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateLocaleInBackground(); 1436bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1437bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1438bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1439fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov case BACKGROUND_TASK_CHANGE_LOCALE: { 1440fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov changeLocaleInBackground(); 1441fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov break; 1442fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1443fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1444bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM: { 1445bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isAggregationUpgradeNeeded()) { 1446bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov upgradeAggregationAlgorithmInBackground(); 1447bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1448bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1449bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1450bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 145105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_SEARCH_INDEX: { 145205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov updateSearchIndexInBackground(); 145305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov break; 145405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 145505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1456bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_PROVIDER_STATUS: { 1457bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateProviderStatus(); 1458bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1459bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1460bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1461bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_DIRECTORIES: { 1462bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (arg != null) { 1463bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.onPackageChanged((String) arg); 1464bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1465bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1466bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1467f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1468f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case BACKGROUND_TASK_CLEANUP_PHOTOS: { 1469f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check rate limit. 1470f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long now = System.currentTimeMillis(); 1471f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (now - mLastPhotoCleanup > PHOTO_CLEANUP_RATE_LIMIT) { 1472f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mLastPhotoCleanup = now; 1473f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupPhotoStore(); 1474f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro break; 1475f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1476f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1477bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 14784cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 14794cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao 148053fac8f99f3884c372c907a76766d27fa9e1d95fDmitri Plotnikov public void onLocaleChanged() { 14813826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 14823826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 14834f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov return; 14844f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov } 14854f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov 1486fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_CHANGE_LOCALE); 14874cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 148851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 148951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov /** 149051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * Verifies that the contacts database is properly configured for the current locale. 149151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * If not, changes the database locale to the current locale using an asynchronous task. 149251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * This needs to be done asynchronously because the process involves rebuilding 149351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * large data structures (name lookup, sort keys), which can take minutes on 149451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * a large set of contacts. 149551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 1496bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateLocaleInBackground() { 1497f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 1498f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov // The process is already running - postpone the change 1499f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov if (mProviderStatus == ProviderStatus.STATUS_CHANGING_LOCALE) { 1500f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov return; 1501f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov } 1502f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 150351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 150451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final String providerLocale = prefs.getString(PREF_LOCALE, null); 150551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final Locale currentLocale = mCurrentLocale; 150651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov if (currentLocale.toString().equals(providerLocale)) { 150751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov return; 150851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 150951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 151051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov int providerStatus = mProviderStatus; 151151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_CHANGING_LOCALE); 1512bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDbHelper.setLocale(this, currentLocale); 1513bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).apply(); 1514bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov setProviderStatus(providerStatus); 1515bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 151651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 1517fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov /** 1518fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov * Reinitializes the provider for a new locale. 1519fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov */ 1520fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov private void changeLocaleInBackground() { 1521fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Re-initializing the provider without stopping it. 1522fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Locking the database will prevent inserts/updates/deletes from 1523fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // running at the same time, but queries may still be running 1524fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // on other threads. Those queries may return inconsistent results. 1525fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov SQLiteDatabase db = mDbHelper.getWritableDatabase(); 1526fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.beginTransaction(); 1527fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov try { 1528fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov initForDefaultLocale(); 1529fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.setTransactionSuccessful(); 1530fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } finally { 1531fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.endTransaction(); 1532fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1533fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1534fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov updateLocaleInBackground(); 1535fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1536fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 153705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov protected void updateSearchIndexInBackground() { 153805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov mSearchIndexManager.updateIndex(); 153905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 154005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1541bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateDirectoriesInBackground(boolean rescan) { 1542bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanAllPackages(rescan); 154351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 154451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 15453826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateProviderStatus() { 15463826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 15473826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 15483826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return; 15493826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15503826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 15513826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mContactsAccountCount == 0 155249d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov && DatabaseUtils.queryNumEntries(mDbHelper.getReadableDatabase(), 155349d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Tables.CONTACTS, null) == 0) { 15543826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 15553826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } else { 15563826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 15573826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15583826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15593826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 156031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* Visible for testing */ 1561f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro protected void cleanupPhotoStore() { 15626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro SQLiteDatabase db = mDbHelper.getWritableDatabase(); 15636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 15646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Assemble the set of photo store file IDs that are in use, and send those to the photo 1565f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // store. Any photos that aren't in that set will be deleted, and any photos that no 1566f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // longer exist in the photo store will be returned for us to clear out in the DB. 15676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = db.query(Views.DATA, new String[]{Data._ID, Photo.PHOTO_FILE_ID}, 1568f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.MIMETYPE + "=" + Photo.MIMETYPE + " AND " 1569f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro + Photo.PHOTO_FILE_ID + " IS NOT NULL", null, null, null, null); 15706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> usedPhotoFileIds = Sets.newHashSet(); 15716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToDataId = Maps.newHashMap(); 1572f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1573f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro while (c.moveToNext()) { 15746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = c.getLong(0); 15756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(1); 15766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 15776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToDataId.put(photoFileId, dataId); 15786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 15796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 15806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 15816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 15826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 15836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Also query for all social stream item photos. 15846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c = db.query(Tables.STREAM_ITEM_PHOTOS, 15856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{ 15866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos._ID, 15876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.STREAM_ITEM_ID, 15886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.PHOTO_FILE_ID 15896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro }, 15906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro null, null, null, null, null); 15916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToStreamItemPhotoId = Maps.newHashMap(); 15926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> streamItemPhotoIdToStreamItemId = Maps.newHashMap(); 15936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 15946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro while (c.moveToNext()) { 15956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = c.getLong(0); 15966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = c.getLong(1); 15976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(2); 15986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 15996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToStreamItemPhotoId.put(photoFileId, streamItemPhotoId); 16006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemPhotoIdToStreamItemId.put(streamItemPhotoId, streamItemId); 1601f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1602f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 1603f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 1604f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1605f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1606f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Run the photo store cleanup. 16076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> missingPhotoIds = mPhotoStore.cleanup(usedPhotoFileIds); 1608f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1609f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If any of the keys we're using no longer exist, clean them up. 16106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!missingPhotoIds.isEmpty()) { 1611f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 16126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro for (long missingPhotoId : missingPhotoIds) { 16136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToDataId.containsKey(missingPhotoId)) { 16146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = photoFileIdToDataId.get(missingPhotoId); 1615f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 1616f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.putNull(Photo.PHOTO_FILE_ID); 1617f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ops.add(ContentProviderOperation.newUpdate( 16186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentUris.withAppendedId(Data.CONTENT_URI, dataId)) 1619f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .withValues(updateValues).build()); 1620f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 16216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToStreamItemPhotoId.containsKey(missingPhotoId)) { 16226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For missing photos that were in stream item photos, just delete the stream 16236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // item photo. 16246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = photoFileIdToStreamItemPhotoId.get(missingPhotoId); 16256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = streamItemPhotoIdToStreamItemId.get(streamItemPhotoId); 16266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ops.add(ContentProviderOperation.newDelete( 16276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.CONTENT_URI.buildUpon() 16286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemId)) 16296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY) 16306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemPhotoId)) 16316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .build()).build()); 16326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 1633f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1634f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1635f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro applyBatch(ops); 1636f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (OperationApplicationException oae) { 1637f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Not a fatal problem (and we'll try again on the next cleanup). 1638f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Failed to clean up outdated photo references", oae); 1639f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1640f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1641f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1642f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1643f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* Visible for testing */ 1644de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov @Override 1645b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 1646b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return ContactsDatabaseHelper.getInstance(context); 164731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 164831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1649f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* package */ PhotoStore getPhotoStore() { 1650f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return mPhotoStore; 1651f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1652f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 165387614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxDisplayPhotoDim() { 165487614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxDisplayPhotoDim; 165587614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 165687614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 165787614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxThumbnailPhotoDim() { 165887614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxThumbnailPhotoDim; 165987614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 166087614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1661013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov /* package */ NameSplitter getNameSplitter() { 1662013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov return mNameSplitter; 1663013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov } 1664013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov 16655df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov /* package */ NameLookupBuilder getNameLookupBuilder() { 16665df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov return mNameLookupBuilder; 16675df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov } 16685df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov 16695dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov /* Visible for testing */ 1670ed78fd6df5e9f3a2d572162e5d374d1f4a625bddDmitri Plotnikov public ContactDirectoryManager getContactDirectoryManagerForTest() { 167172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov return mContactDirectoryManager; 167272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 167372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 167472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov /* Visible for testing */ 16755dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov protected Locale getLocale() { 16765dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov return Locale.getDefault(); 16775dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov } 16785dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 16793d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov protected boolean isLegacyContactImportNeeded() { 1680b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_CONTACTS_IMPORTED, "0")); 1681b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov return version < PROPERTY_CONTACTS_IMPORT_VERSION; 16823d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 16833d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1684568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov protected LegacyContactImporter getLegacyContactImporter() { 1685568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return new LegacyContactImporter(getContext(), this); 1686568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1687568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1688568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 1689bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Imports legacy contacts as a background task. 1690568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 1691bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private void importLegacyContactsInBackground() { 1692bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Importing legacy contacts"); 1693bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADING); 1694568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1695bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 1696bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDbHelper.setLocale(this, mCurrentLocale); 1697bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, mCurrentLocale.toString()).commit(); 1698568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1699bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov LegacyContactImporter importer = getLegacyContactImporter(); 1700bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (importLegacyContacts(importer)) { 1701bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportSuccess(); 1702bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } else { 1703bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportFailure(); 1704bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1705568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1706568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1707bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1708bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Unlocks the provider and declares that the import process is complete. 1709bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1710bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportSuccess() { 1711bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1712bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)getContext().getSystemService(Context.NOTIFICATION_SERVICE); 1713bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.cancel(LEGACY_IMPORT_FAILED_NOTIFICATION); 1714bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1715b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov // Store a property in the database indicating that the conversion process succeeded 1716b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov mDbHelper.setProperty(PROPERTY_CONTACTS_IMPORTED, 1717b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov String.valueOf(PROPERTY_CONTACTS_IMPORT_VERSION)); 1718bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 1719bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Completed import of legacy contacts"); 1720bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1721bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1722bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1723bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Announces the provider status and keeps the provider locked. 1724bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1725bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportFailure() { 1726bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Context context = getContext(); 1727bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1728bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); 1729bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1730bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // Show a notification 1731bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Notification n = new Notification(android.R.drawable.stat_notify_error, 1732bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_ticker), 1733bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov System.currentTimeMillis()); 1734bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.setLatestEventInfo(context, 1735bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_title), 1736bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_text), 1737bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov PendingIntent.getActivity(context, 0, new Intent(Intents.UI.LIST_DEFAULT), 0)); 1738bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; 1739bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1740bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.notify(LEGACY_IMPORT_FAILED_NOTIFICATION, n); 1741bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1742bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADE_OUT_OF_MEMORY); 1743bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Failed to import legacy contacts"); 1744bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1745bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // Do not let any database changes until this issue is resolved. 1746bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mOkToOpenAccess = false; 17473d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17483d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 17493d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /* Visible for testing */ 1750568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /* package */ boolean importLegacyContacts(LegacyContactImporter importer) { 17510e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff boolean aggregatorEnabled = mContactAggregator.isEnabled(); 17523d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov mContactAggregator.setEnabled(false); 17533d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov try { 1754bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (importer.importContacts()) { 1755bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1756bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // TODO aggregate all newly added raw contacts 1757bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mContactAggregator.setEnabled(aggregatorEnabled); 1758bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return true; 1759bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 17603d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } catch (Throwable e) { 17613d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov Log.e(TAG, "Legacy contact import failed", e); 17623d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 1763bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mEstimatedStorageRequirement = importer.getEstimatedStorageRequirement(); 1764bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return false; 17653d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17663d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1767a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 1768a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 1769a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 1770a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /* package */ void wipeData() { 1771b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.wipeData(); 1772f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mPhotoStore.clear(); 17733826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS; 1774a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 1775a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1776568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 177715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov * During intialization, this content provider will 1778568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * block all attempts to change contacts data. In particular, it will hold 1779568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * up all contact syncs. As soon as the import process is complete, all 1780568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * processes waiting to write to the provider are unblocked and can proceed 1781568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * to compete for the database transaction monitor. 1782568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 178315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private void waitForAccess(CountDownLatch latch) { 178415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (latch == null) { 178515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 178615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 178715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 178815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov while (true) { 178915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov try { 179015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov latch.await(); 179115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 179215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } catch (InterruptedException e) { 179315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Thread.currentThread().interrupt(); 1794ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov } 1795568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1796568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1797568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1798568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1799568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public Uri insert(Uri uri, ContentValues values) { 180015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1801568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.insert(uri, values); 1802568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1803568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1804568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1805568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 180615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (mWriteAccessLatch != null) { 1807bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // We are stuck trying to upgrade contacts db. The only update request 1808bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // allowed in this case is an update of provider status, which will trigger 1809bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // an attempt to upgrade contacts again. 1810bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov int match = sUriMatcher.match(uri); 1811bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (match == PROVIDER_STATUS) { 1812bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Integer newStatus = values.getAsInteger(ProviderStatus.STATUS); 1813bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (newStatus != null && newStatus == ProviderStatus.STATUS_UPGRADING) { 1814bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1815bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 1; 1816bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } else { 1817bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 0; 1818bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1819bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1820bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 182115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1822568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.update(uri, values, selection, selectionArgs); 1823568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1824568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1825568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1826568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int delete(Uri uri, String selection, String[] selectionArgs) { 182715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1828568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.delete(uri, selection, selectionArgs); 1829568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1830568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1831568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1832568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 1833568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov throws OperationApplicationException { 183415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1835568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.applyBatch(operations); 1836568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1837568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 18384f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 18397b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov public int bulkInsert(Uri uri, ContentValues[] values) { 18407b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov waitForAccess(mWriteAccessLatch); 18417b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov return super.bulkInsert(uri, values); 18427b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov } 18437b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov 18447b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov @Override 1845285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void onBeginTransaction() { 1846bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1847b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "onBeginTransaction"); 1848b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1849285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.onBeginTransaction(); 18501ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana mContactAggregator.clearPendingAggregations(); 1851d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.clear(); 1852b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1853b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1854285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 1855285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 1856285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void beforeTransactionCommit() { 18571129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 1858bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1859b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "beforeTransactionCommit"); 1860b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1861285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.beforeTransactionCommit(); 1862b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 1863bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateInTransaction(mTransactionContext, mDb); 18641a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (mVisibleTouched) { 18651a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = false; 1866b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.updateAllVisible(); 18671a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey } 18683826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 1869bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 1870bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 18713826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatusUpdateNeeded) { 18723826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 18733826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = false; 18743826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 1875b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1876b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1877bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov private void updateSearchIndexInTransaction() { 1878bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov Set<Long> staleContacts = mTransactionContext.getStaleSearchIndexContactIds(); 1879bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov Set<Long> staleRawContacts = mTransactionContext.getStaleSearchIndexRawContactIds(); 1880bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov if (!staleContacts.isEmpty() || !staleRawContacts.isEmpty()) { 1881bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mSearchIndexManager.updateIndexForRawContacts(staleContacts, staleRawContacts); 1882bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mTransactionContext.clearSearchIndexUpdates(); 1883bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 1884bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 1885bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 1886b5a4add17815167d20a90645779df34cdf45280dFred Quintana private void flushTransactionalChanges() { 1887bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1888b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "flushTransactionChanges"); 1889b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 18901129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 189124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Determine whether we need to refresh the profile ID cache. 189224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean profileCacheRefreshNeeded = false; 189324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1894d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov for (long rawContactId : mTransactionContext.getInsertedRawContactIds()) { 18958ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(mDb, rawContactId); 1896bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.onRawContactInsert(mTransactionContext, mDb, rawContactId); 1897285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 1898b5a4add17815167d20a90645779df34cdf45280dFred Quintana 189924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Map<Long, Account> insertedProfileRawContactAccountMap = 190024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.getInsertedProfileRawContactIds(); 190124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!insertedProfileRawContactAccountMap.isEmpty()) { 190224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro for (long profileRawContactId : insertedProfileRawContactAccountMap.keySet()) { 190324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mDbHelper.updateRawContactDisplayName(mDb, profileRawContactId); 190424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mContactAggregator.onProfileRawContactInsert(mTransactionContext, mDb, 190524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactId, 190624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro insertedProfileRawContactAccountMap.get(profileRawContactId)); 190724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 190824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = true; 190924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 191024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1911d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov Set<Long> dirtyRawContacts = mTransactionContext.getDirtyRawContactIds(); 1912d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!dirtyRawContacts.isEmpty()) { 1913a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 1914a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL); 1915d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, dirtyRawContacts); 1916a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 1917a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mDb.execSQL(mSb.toString()); 191824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 191924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = profileCacheRefreshNeeded || 192024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro !Collections.disjoint(mProfileIdCache.profileRawContactIds, dirtyRawContacts); 1921a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov } 1922a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 1923d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov Set<Long> updatedRawContacts = mTransactionContext.getUpdatedRawContactIds(); 1924d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!updatedRawContacts.isEmpty()) { 1925a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 1926a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL); 1927d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, updatedRawContacts); 1928a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 1929a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mDb.execSQL(mSb.toString()); 193024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 193124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = profileCacheRefreshNeeded || 193224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro !Collections.disjoint(mProfileIdCache.profileRawContactIds, updatedRawContacts); 1933b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1934b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1935d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov for (Map.Entry<Long, Object> entry : mTransactionContext.getUpdatedSyncStates()) { 1936b5a4add17815167d20a90645779df34cdf45280dFred Quintana long id = entry.getKey(); 19379d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana if (mDbHelper.getSyncState().update(mDb, id, entry.getValue()) <= 0) { 19389d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana throw new IllegalStateException( 19399d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana "unable to update sync state, does it still exist?"); 19409d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana } 1941b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1942b5a4add17815167d20a90645779df34cdf45280dFred Quintana 194324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (profileCacheRefreshNeeded) { 194424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Force the profile ID cache to refresh. 194524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mProfileIdCache.init(mDb, true); 194624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 194724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1948d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.clear(); 1949b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1950b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1951a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** 1952a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * Appends comma separated ids. 1953a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * @param ids Should not be empty 1954a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov */ 1955d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private void appendIds(StringBuilder sb, Set<Long> ids) { 1956b5a4add17815167d20a90645779df34cdf45280dFred Quintana for (long id : ids) { 1957a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(id).append(','); 1958b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1959a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 1960a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.setLength(sb.length() - 1); // Yank the last comma 1961285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 1962285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 196324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 196424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given contact ID represents the user's personal profile - if it is, calls 196524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * a permission check (for writing the profile if forWrite is true, for reading the profile 196624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * otherwise). If the contact ID is not the user's profile, no check is executed. 1967afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 196824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param contactId The contact ID to be checked. 196924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 197024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 1971afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForContact(SQLiteDatabase db, long contactId, 1972afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro boolean forWrite) { 1973afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 197424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileContactId == contactId) { 197524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 197624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 197724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 197824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 197924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 198024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given raw contact ID is a member of the user's personal profile - if it 198124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * is, calls a permission check (for writing the profile if forWrite is true, for reading the 198224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile otherwise). If the raw contact ID is not in the user's profile, no check is 198324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * executed. 1984afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 198524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param rawContactId The raw contact ID to be checked. 198624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 198724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 1988afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForRawContact(SQLiteDatabase db, long rawContactId, 1989afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro boolean forWrite) { 1990afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 199124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileRawContactIds.contains(rawContactId)) { 199224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 199324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 199424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 199524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 199624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 199724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given data ID is a member of the user's personal profile - if it is, 199824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * calls a permission check (for writing the profile if forWrite is true, for reading the 199924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile otherwise). If the data ID is not in the user's profile, no check is executed. 2000afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 200124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param dataId The data ID to be checked. 200224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 200324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 2004afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForData(SQLiteDatabase db, long dataId, boolean forWrite) { 2005afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 200624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileDataIds.contains(dataId)) { 200724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 200824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 200924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 201024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 201124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 201224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Performs a permission check for WRITE_PROFILE or READ_PROFILE (depending on the parameter). 201324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * If the permission check fails, this will throw a SecurityException. 201424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 201524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 201624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void enforceProfilePermission(boolean forWrite) { 201724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String profilePermission = forWrite 201824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro ? "android.permission.WRITE_PROFILE" 201924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro : "android.permission.READ_PROFILE"; 202024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro getContext().enforceCallingOrSelfPermission(profilePermission, null); 202124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 202224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2023285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2024cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov protected void notifyChange() { 202581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov notifyChange(mSyncToNetwork); 202681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = false; 202781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 202881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 202981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov protected void notifyChange(boolean syncToNetwork) { 203081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null, 203181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov syncToNetwork); 2032cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov } 2033568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 203451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov protected void setProviderStatus(int status) { 20353826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != status) { 20363826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = status; 20373826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov getContext().getContentResolver().notifyChange(ProviderStatus.CONTENT_URI, null, false); 20383826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 203951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 204051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 2041f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public DataRowHandler getDataRowHandler(final String mimeType) { 20423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataRowHandler handler = mDataRowHandlers.get(mimeType); 20433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (handler == null) { 20446d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov handler = new DataRowHandlerForCustomMimetype( 20456d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov getContext(), mDbHelper, mContactAggregator, mimeType); 20463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(mimeType, handler); 20473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 20483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return handler; 20493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 20503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 20514f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 2052de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected Uri insertInTransaction(Uri uri, ContentValues values) { 2053bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 20541129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Log.v(TAG, "insertInTransaction: " + uri + " " + values); 2055b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2056f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2057f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 2058f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 2059f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2060a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 2061a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 206235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2063a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 206435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 2065b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov id = mDbHelper.getSyncState().insert(mDb, values); 206635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 206735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2068d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 2069d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov insertContact(values); 20706bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 20716bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 20726bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 207324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 207424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro throw new UnsupportedOperationException( 207524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "The profile contact is created automatically"); 207624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 207724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 20785ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 207924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter, false); 2080f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2081a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2082a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2083a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 20845ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 20855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 2086f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2087f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2088a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2089a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2090a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 20913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 20923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItems.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 20933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 20943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 20953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 20963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 20973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 209824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 209924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(true); 210024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter, true); 210124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mSyncToNetwork |= !callerIsSyncAdapter; 210224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 210324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 210424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2105a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case DATA: { 2106f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2107f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2108a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2109a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2110a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2111ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 2112f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov id = insertGroup(uri, values, callerIsSyncAdapter); 2113f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2114ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2115ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2116ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2117eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 21185aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey id = insertSettings(uri, values); 211943880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 2120eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 2121eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 2122eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 212382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 212482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov id = insertStatusUpdate(values); 21251f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 21261f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 21271f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 21283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 21293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 21303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 21343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 21353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 21363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 21403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 21413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItemPhotos.STREAM_ITEM_ID, uri.getPathSegments().get(1)); 21423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 21433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2147a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 214881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 2149f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 2150a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2151a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 21537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 21547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 21557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2156de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return ContentUris.withAppendedId(uri, id); 2157a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2158a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2159a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2160e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * If account is non-null then store it in the values. If the account is 2161e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * already specified in the values then it must be consistent with the 2162e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * account, if it is non-null. 2163e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * 2164e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param uri Current {@link Uri} being operated on. 2165e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param values {@link ContentValues} to read and possibly update. 2166e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when only one of 2167e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_NAME} or 2168e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the 2169e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * other undefined. 2170e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME} 2171e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between 2172e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * the given {@link Uri} and {@link ContentValues}. 21737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 2174e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException { 2175f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 2176f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 2177e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 2178f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2179f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME); 2180f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 2181e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialValues = TextUtils.isEmpty(valueAccountName) 2182e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey ^ TextUtils.isEmpty(valueAccountType); 2183e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2184e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri || partialValues) { 2185e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 2186fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 2187fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 2188e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2189e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2190e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 2191e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 2192e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validUri = !TextUtils.isEmpty(accountName); 2193e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validValues = !TextUtils.isEmpty(valueAccountName); 2194e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2195e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validValues && validUri) { 2196e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Check that accounts match when both present 2197e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean accountMatch = TextUtils.equals(accountName, valueAccountName) 2198e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey && TextUtils.equals(accountType, valueAccountType); 2199e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (!accountMatch) { 2200fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 2201fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "When both specified, ACCOUNT_NAME and ACCOUNT_TYPE must match", uri)); 2202e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2203e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validUri) { 2204e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Fill values from Uri when not present 2205f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_NAME, accountName); 2206f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_TYPE, accountType); 2207e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validValues) { 2208f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountName = valueAccountName; 2209f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountType = valueAccountType; 2210e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else { 2211e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return null; 2212f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 2213f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2214e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Use cached Account object when matches, otherwise create 2215f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mAccount == null 2216f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.name.equals(accountName) 2217f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.type.equals(accountType)) { 2218f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mAccount = new Account(accountName, accountType); 2219035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 2220f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2221e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return mAccount; 22227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 22237e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 22247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 2225d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov * Inserts an item in the contacts table 22266bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 22276bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 22286bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 22296bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 2230d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private long insertContact(ContentValues values) { 2231de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new UnsupportedOperationException("Aggregate contacts are created automatically"); 22326bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 22336bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 22346bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 223524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Inserts an item in the raw contacts table 2236a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2237f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param uri the values for the new row 2238f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param values the account this contact should be associated with. may be null. 2239dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana * @param callerIsSyncAdapter 224024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forProfile Whether this raw contact is being inserted into the user's profile. 2241a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2242a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 224324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private long insertRawContact(Uri uri, ContentValues values, boolean callerIsSyncAdapter, 224424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean forProfile) { 2245f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2246f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2247f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 2248f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2249e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final Account account = resolveAccount(uri, mValues); 22507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 22513d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov if (values.containsKey(RawContacts.DELETED) 22523d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov && values.getAsInteger(RawContacts.DELETED) != 0) { 2253f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 22543d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 22553d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2256f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov long rawContactId = mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, mValues); 2257f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = RawContacts.AGGREGATION_MODE_DEFAULT; 225824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (forProfile) { 225924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Profile raw contacts should never be aggregated by the aggregator; they are always 226024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // aggregated under a single profile contact. 226124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro aggregationMode = RawContacts.AGGREGATION_MODE_DISABLED; 226224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else if (mValues.containsKey(RawContacts.AGGREGATION_MODE)) { 2263f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov aggregationMode = mValues.getAsInteger(RawContacts.AGGREGATION_MODE); 2264f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 2265f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov mContactAggregator.markNewForAggregation(rawContactId, aggregationMode); 2266285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 226724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (forProfile) { 226824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Trigger creation of the user profile Contact (or association with the existing one) 226924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // at the end of the transaction. 227024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.profileRawContactInserted(rawContactId, account); 227124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else { 227224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Trigger creation of a Contact based on this RawContact at the end of transaction 227324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.rawContactInserted(rawContactId, account); 227424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 2275f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2276dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 2277dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 2278dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long starred = values.getAsLong(RawContacts.STARRED); 2279dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (starred != null && starred != 0) { 2280dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred != 0); 2281dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2282dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2283dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 22843826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 2285023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov return rawContactId; 2286a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2287a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2288dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void addAutoAddMembership(long rawContactId) { 2289dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID, 2290dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2291dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2292dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2293dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2294dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2295dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2296dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private Long findGroupByRawContactId(String selection, long rawContactId) { 2297dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Cursor c = mDb.query(Tables.GROUPS + "," + Tables.RAW_CONTACTS, PROJECTION_GROUP_ID, 2298dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, 2299dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}, 2300dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana null /* groupBy */, null /* having */, null /* orderBy */); 2301dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 2302dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (c.moveToNext()) { 2303dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return c.getLong(0); 2304dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2305dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return null; 2306dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 2307dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana c.close(); 2308dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2309dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2310dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2311dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void updateFavoritesMembership(long rawContactId, boolean isStarred) { 2312dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID, 2313dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2314dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2315dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (isStarred) { 2316dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2317dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2318dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana deleteDataGroupMembership(rawContactId, groupId); 2319dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2320dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2321dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2322dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2323dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void insertDataGroupMembership(long rawContactId, long groupId) { 2324dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ContentValues groupMembershipValues = new ContentValues(); 2325dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.GROUP_ROW_ID, groupId); 2326dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 2327dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(DataColumns.MIMETYPE_ID, 2328dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 2329dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDb.insert(Tables.DATA, null, groupMembershipValues); 2330dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2331dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2332dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void deleteDataGroupMembership(long rawContactId, long groupId) { 2333dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final String[] selectionArgs = { 2334dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)), 2335dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(groupId), 2336dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(rawContactId)}; 2337dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDb.delete(Tables.DATA, SELECTION_GROUPMEMBERSHIP_DATA, selectionArgs); 2338dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2339dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2340a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2341a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 2342a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2343a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 2344a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2345a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 2346f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private long insertData(ContentValues values, boolean callerIsSyncAdapter) { 2347a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 2348de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.clear(); 2349de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.putAll(values); 235067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 2351de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID); 235220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 235324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // If the data being inserted belongs to the user's profile entry, check for the 235424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // WRITE_PROFILE permission before proceeding. 2355afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 235624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2357de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace package with internal mapping 2358de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String packageName = mValues.getAsString(Data.RES_PACKAGE); 2359de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (packageName != null) { 2360b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 2361de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 2362de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 2363508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 2364de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace mimetype with internal mapping 2365de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String mimeType = mValues.getAsString(Data.MIMETYPE); 2366de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (TextUtils.isEmpty(mimeType)) { 2367de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new IllegalArgumentException(Data.MIMETYPE + " is required"); 2368de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 23694097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 2370b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.getMimeTypeId(mimeType)); 2371de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 2372a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2373a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2374d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov id = rowHandler.insert(mDb, mTransactionContext, rawContactId, mValues); 2375f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2376d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 2377a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2378d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.rawContactUpdated(rawContactId); 2379a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 23804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 23814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 23823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 23833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_items table. The account is checked against the 23843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account in the raw contact for which the stream item is being inserted. If the 23853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * new stream item results in more stream items under this raw contact than the limit, 23863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest one will be deleted (note that if the stream item inserted was the 23873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * oldest, it will be immediately deleted, and this will return 0). 23883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 23893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 23903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 23913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return the stream item _ID of the newly created row, or 0 if it was not created 23923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 23933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItem(Uri uri, ContentValues values) { 23943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 23953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 23963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 23973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 23983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = mValues.getAsLong(StreamItems.RAW_CONTACT_ID); 23993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If the data being inserted belongs to the user's profile entry, check for the 24013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // WRITE_PROFILE permission before proceeding. 2402afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 24033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 24053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 24063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 24073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream items table. 24096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 24106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 24116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 24123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Insert the new stream item. 24136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro id = mDb.insert(Tables.STREAM_ITEMS, null, mValues); 24146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (id == -1) { 24156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insertion failed. 24166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 24176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check to see if we're over the limit for stream items under this raw contact. 24203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // It's possible that the inserted stream item is older than the the existing 24213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // ones, in which case it may be deleted immediately (resetting the ID to 0). 24223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = cleanUpOldStreamItems(rawContactId, id); 24233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 24253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_item_photos table. The account is checked against 24293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the account in the raw contact that owns the stream item being modified. 24303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 24313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 24323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 24336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return the stream item photo _ID of the newly created row, or 0 if there was an issue 24346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * with processing the photo or creating the row 24353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 24363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItemPhoto(Uri uri, ContentValues values) { 24373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 24383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 24393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 24403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = mValues.getAsLong(StreamItemPhotos.STREAM_ITEM_ID); 24423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemId != 0) { 24433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = lookupRawContactIdForStreamId(streamItemId); 24443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If the data being inserted belongs to the user's profile entry, check for the 24463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // WRITE_PROFILE permission before proceeding. 2447afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 24483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 24503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 24513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 24523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream item 24546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 24556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 24566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 24573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 24596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(mValues, false)) { 24606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insert the stream item photo. 24616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro id = mDb.insert(Tables.STREAM_ITEM_PHOTOS, null, mValues); 24626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 24653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Processes the photo contained in the {@link ContactsContract.StreamItemPhotos#PHOTO} 24696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * field of the given values, attempting to store it in the photo store. If successful, 24706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * the resulting photo file ID will be added to the values for insert/update in the table. 24716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * <p> 24726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * If updating, it is valid for the picture to be empty or unspecified (the function will 24736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * still return true). If inserting, a valid picture must be specified. 24746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param values The content values provided by the caller. 24756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param forUpdate Whether this photo is being processed for update (vs. insert). 24766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return Whether the insert or update should proceed. 24776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 24786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro private boolean processStreamItemPhoto(ContentValues values, boolean forUpdate) { 24796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!values.containsKey(StreamItemPhotos.PHOTO)) { 24806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 24816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro byte[] photoBytes = values.getAsByteArray(StreamItemPhotos.PHOTO); 24836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoBytes == null) { 24846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 24856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 24876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 24886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 24896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = mPhotoStore.insert(new PhotoProcessor(photoBytes, 24901dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim, true), true); 24916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileId != 0) { 24926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.put(StreamItemPhotos.PHOTO_FILE_ID, photoFileId); 24936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(StreamItemPhotos.PHOTO); 24946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return true; 24956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 24966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Couldn't store the photo, return 0. 24976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert"); 24986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 24996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } catch (IOException ioe) { 25016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert", ioe); 25026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 25036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 25066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 25073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Looks up the raw contact ID that owns the specified stream item. 25083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param streamItemId The ID of the stream item. 25093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The associated raw contact ID, or -1 if no such stream item exists. 25103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long lookupRawContactIdForStreamId(long streamItemId) { 25123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = -1; 25133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = mDb.query(Tables.STREAM_ITEMS, new String[]{StreamItems.RAW_CONTACT_ID}, 25143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems._ID + "=?", new String[]{String.valueOf(streamItemId)}, 25153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c.moveToFirst()) { 25183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann rawContactId = c.getLong(0); 25193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 25213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 25223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return rawContactId; 25243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given raw contact ID is owned by the given account. 25283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account is null, this will return true iff the raw contact 25293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * is also associated with the "null" account. 25303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 25313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account does not match, this will throw a security exception. 25323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 25333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to check for. 25343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void enforceModifyingAccount(Account account, long rawContactId) { 25363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String accountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 25373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + "=? AND " 25383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + "=?"; 25393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String noAccountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 25403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " IS NULL AND " 25413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " IS NULL"; 25423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c; 25433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (account != null) { 25443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContactsColumns.CONCRETE_ID}, 25453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann accountSelection, 25463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(rawContactId), mAccount.name, mAccount.type}, 25473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 25493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContactsColumns.CONCRETE_ID}, 25503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann noAccountSelection, new String[]{String.valueOf(rawContactId)}, 25513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if(c.getCount() == 0) { 25553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new SecurityException("Caller account does not match raw contact ID " 25563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + rawContactId); 25573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 25593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 25603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream items matches up with the given 25653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 25663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 25673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 25683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 25693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 25703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item IDs that would be included in this selection. 25713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItems(Account account, String selection, 25733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 25743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = Lists.newArrayList(); 25753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 25763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 25773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = qb.query(mDb, 25783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{StreamItems._ID, StreamItems.RAW_CONTACT_ID}, 25793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 25803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 25823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemIds.add(c.getLong(0)); 25833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 25853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 25863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 25883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 25893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds; 25913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream item photos matches up with the given 25953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 25963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 25973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 25983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 25993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 26003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item photo IDs that would be included in this selection. 26013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItemPhotos(Account account, String selection, 26033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 26043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemPhotoIds = Lists.newArrayList(); 26053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 26063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 26073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = qb.query(mDb, new String[]{StreamItemPhotos._ID, StreamItems.RAW_CONTACT_ID}, 26083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 26093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 26113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemPhotoIds.add(c.getLong(0)); 26123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 26143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 26153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemPhotoIds; 26203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Queries the database for stream items under the given raw contact. If there are 26243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * more entries than {@link ContactsProvider2#MAX_STREAM_ITEMS_PER_RAW_CONTACT}, 26253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest entries (as determined by timestamp) will be deleted. 26263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to examine for stream items. 26273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param insertedStreamItemId The ID of the stream item that was just inserted, 26283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * prompting this cleanup. Callers may pass 0 if no insertion prompted the 26293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * cleanup. 26303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The ID of the inserted stream item if it still exists after cleanup; 26313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 0 otherwise. 26323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long cleanUpOldStreamItems(long rawContactId, long insertedStreamItemId) { 26343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long postCleanupInsertedStreamId = insertedStreamItemId; 26353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = mDb.query(Tables.STREAM_ITEMS, new String[]{StreamItems._ID}, 26363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 26373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, StreamItems.TIMESTAMP + " DESC, " + StreamItems._ID + " DESC"); 26383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int streamItemCount = c.getCount(); 26403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemCount <= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 26413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Still under the limit - nothing to clean up! 26423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return insertedStreamItemId; 26433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 26443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToLast(); 26453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.getPosition() >= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 26463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = c.getLong(0); 26473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (insertedStreamItemId == streamItemId) { 26483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // The stream item just inserted is being deleted. 26493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann postCleanupInsertedStreamId = 0; 26503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(c.getLong(0)); 26523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToPrevious(); 26533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return postCleanupInsertedStreamId; 26593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2661ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateRawContactDisplayName(SQLiteDatabase db, long rawContactId) { 26628ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(db, rawContactId); 2663d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov } 2664d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov 26659261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 266620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov * Delete data row by row so that fixing of primaries etc work correctly. 266720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov */ 2668f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) { 266920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 267020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2671de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 2672de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 2673f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, 2674f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov selection, selectionArgs, null); 2675de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov try { 2676de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov while(c.moveToNext()) { 2677f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 267824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 267924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for write profile permission if the data belongs to the profile. 2680afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 268124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2682f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 2683a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2684d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov count += rowHandler.delete(mDb, mTransactionContext, c); 2685f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2686d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 268788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov } 268820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 268920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 2690de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov c.close(); 269120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 269220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 269320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 269420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 269520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 269688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov /** 269788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov * Delete a data row provided that it is one of the allowed mime types. 269888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov */ 269920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov public int deleteData(long dataId, String[] allowedMimeTypes) { 2700f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 270188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 270288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 27034da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 2704f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, Data._ID + "=?", 27054da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1, null); 2706f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 270720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 270820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!c.moveToFirst()) { 270920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 271020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 271120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2712f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 271320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean valid = false; 271420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov for (int i = 0; i < allowedMimeTypes.length; i++) { 271520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.equals(mimeType, allowedMimeTypes[i])) { 271620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov valid = true; 271720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 271820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 271920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 272020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 272120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!valid) { 27227a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana throw new IllegalArgumentException("Data type mismatch: expected " 272320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov + Lists.newArrayList(allowedMimeTypes)); 272420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 272520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 272624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for write profile permission if the data belongs to the profile. 272724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 2728afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 272924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2730a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2731d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov return rowHandler.delete(mDb, mTransactionContext, c); 273220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 273320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 273420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 273520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 273620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 273720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov /** 2738ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 2739ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 2740f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2741f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2742f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2743f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2744e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final Account account = resolveAccount(uri, mValues); 2745ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2746ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 2747f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String packageName = mValues.getAsString(Groups.RES_PACKAGE); 274867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 2749f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 275067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 2751f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.remove(Groups.RES_PACKAGE); 2752ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2753dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final boolean isFavoritesGroup = mValues.getAsLong(Groups.FAVORITES) != null 2754dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ? mValues.getAsLong(Groups.FAVORITES) != 0 2755dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana : false; 2756dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2757f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2758f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(Groups.DIRTY, 1); 275973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 276073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 2761f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov long result = mDb.insert(Tables.GROUPS, Groups.TITLE, mValues); 2762ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2763dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && isFavoritesGroup) { 2764dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // add all starred raw contacts to this group 2765dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String selection; 2766dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs; 2767dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (account == null) { 2768dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + " IS NULL AND " 2769dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContacts.ACCOUNT_TYPE + " IS NULL"; 2770dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = null; 2771dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2772dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + "=? AND " 2773dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContacts.ACCOUNT_TYPE + "=?"; 2774dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = new String[]{account.name, account.type}; 2775dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2776dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Cursor c = mDb.query(Tables.RAW_CONTACTS, 2777dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{RawContacts._ID, RawContacts.STARRED}, 2778dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, selectionArgs, null, null, null); 2779892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov try { 2780892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov while (c.moveToNext()) { 2781892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (c.getLong(1) != 0) { 2782892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov final long rawContactId = c.getLong(0); 2783892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov insertDataGroupMembership(rawContactId, result); 2784d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 2785892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } 2786dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2787892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } finally { 2788892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov c.close(); 2789dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2790dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2791dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2792f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mValues.containsKey(Groups.GROUP_VISIBLE)) { 27931a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2794ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey } 2795ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2796ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey return result; 2797ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2798ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 27995aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private long insertSettings(Uri uri, ContentValues values) { 2800e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final long id = mDb.insert(Tables.SETTINGS, null, values); 28015aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey 28021a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 28031a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2804e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 28051a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 2806e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return id; 2807e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 2808e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 2809ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 281082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov * Inserts a status update. 28111f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 281282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov public long insertStatusUpdate(ContentValues values) { 281382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov final String handle = values.getAsString(StatusUpdates.IM_HANDLE); 28140a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL); 28154dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov String customProtocol = null; 28164dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov 28170a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) { 281882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL); 28194dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov if (TextUtils.isEmpty(customProtocol)) { 28204dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov throw new IllegalArgumentException( 28214dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM"); 28224dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov } 28231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 28241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2825dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long rawContactId = -1; 2826dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long contactId = -1; 282782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov Long dataId = values.getAsLong(StatusUpdates.DATA_ID); 28286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountType = null; 28296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountName = null; 2830f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov mSb.setLength(0); 28312526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.clear(); 2832dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (dataId != null) { 2833dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the contact info for the given data row. 2834dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 28352526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(Tables.DATA + "." + Data._ID + "=?"); 28362526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(dataId)); 28371f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 2838dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the data row to attach this presence update to 2839dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 28400a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(handle) || protocol == null) { 28410a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required"); 28420a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 28430a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 2844dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // TODO: generalize to allow other providers to match against email 2845dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol; 2846dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 28472a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov String mimeTypeIdIm = String.valueOf(mDbHelper.getMimeTypeIdForIm()); 2848dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (matchEmail) { 28492a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov String mimeTypeIdEmail = String.valueOf(mDbHelper.getMimeTypeIdForEmail()); 2850f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 2851f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise 2852f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the "OR" conjunction confuses it and it switches to a full scan of 2853f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the raw_contacts table. 2854f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 2855f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // This code relies on the fact that Im.DATA and Email.DATA are in fact the same 2856f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // column - Data.DATA1 28572526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + " IN (?,?)" + 28582526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Data.DATA1 + "=?" + 28592526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND ((" + DataColumns.MIMETYPE_ID + "=? AND " + Im.PROTOCOL + "=?"); 28602526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 28612526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 28622526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 28632526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 28642526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 2865dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 28662526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 28672526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 2868dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 28692526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=?))"); 28702526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 2871dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } else { 28722526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + "=?" + 28732526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.PROTOCOL + "=?" + 28742526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.DATA + "=?"); 28752526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 28762526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 28772526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 2878dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 28792526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 28802526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 2881dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 2882dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 28831f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 288482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.DATA_ID)) { 28852526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + DataColumns.CONCRETE_ID + "=?"); 28862526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(values.getAsString(StatusUpdates.DATA_ID)); 2887dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 288870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 288970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 28901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 28911f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 2892de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 28932526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null, 28944394086494fe7909aaca70f56fb4bb08beebf303Dmitri Plotnikov Clauses.CONTACT_VISIBLE + " DESC, " + Data.RAW_CONTACT_ID); 28951f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 289667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataId = cursor.getLong(DataContactsQuery.DATA_ID); 28975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID); 28986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountType = cursor.getString(DataContactsQuery.ACCOUNT_TYPE); 28996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountName = cursor.getString(DataContactsQuery.ACCOUNT_NAME); 2900e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 29011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 29021f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 29031f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 29041f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 29051f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 290631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 290731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 290831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 29091f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 29101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 291182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.PRESENCE)) { 2912a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (customProtocol == null) { 2913a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 2914a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // properly enforce uniqueness of null values 2915a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov customProtocol = ""; 2916a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 2917a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 2918a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.clear(); 291982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.DATA_ID, dataId); 2920a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId); 2921a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.CONTACT_ID, contactId); 292282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PROTOCOL, protocol); 292382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 292482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_HANDLE, handle); 292582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.IM_ACCOUNT)) { 292682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT)); 2927a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 292882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PRESENCE, 292982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov values.getAsString(StatusUpdates.PRESENCE)); 2930aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori mValues.put(StatusUpdates.CHAT_CAPABILITY, 2931aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori values.getAsString(StatusUpdates.CHAT_CAPABILITY)); 29321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2933a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // Insert the presence update 2934a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mDb.replace(Tables.PRESENCE, null, mValues); 2935a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 2936e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 29370a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 293882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.STATUS)) { 293982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String status = values.getAsString(StatusUpdates.STATUS); 29400a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE); 29410a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov Integer labelResource = values.getAsInteger(StatusUpdates.STATUS_LABEL); 29420a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 29430a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(resPackage) 29440a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov && (labelResource == null || labelResource == 0) 29450a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov && protocol != null) { 29460a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov labelResource = Im.getProtocolLabelResource(protocol); 29470a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 29480a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 29490a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov Long iconResource = values.getAsLong(StatusUpdates.STATUS_ICON); 29500a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov // TODO compute the default icon based on the protocol 29510a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 2952a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (TextUtils.isEmpty(status)) { 295378fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.deleteStatusUpdate(dataId); 2954a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } else { 29556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP); 29566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (timestamp != null) { 29576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mDbHelper.replaceStatusUpdate(dataId, timestamp, status, resPackage, 29586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro iconResource, labelResource); 29596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 29606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mDbHelper.insertStatusUpdate(dataId, status, resPackage, iconResource, 29616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro labelResource); 29626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 29636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 29646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For forward compatibility with the new stream item API, insert this status update 29656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // there as well. If we already have a stream item from this source, update that 29666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // one instead of inserting a new one (since the semantics of the old status update 29676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // API is to only have a single record). 29686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (rawContactId != -1 && !TextUtils.isEmpty(status)) { 29696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentValues streamItemValues = new ContentValues(); 29706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 29716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TEXT, status); 29726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.COMMENTS, ""); 29736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_PACKAGE, resPackage); 29746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_ICON, iconResource); 29756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_LABEL, labelResource); 29766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TIMESTAMP, 29776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro timestamp == null ? System.currentTimeMillis() : timestamp); 29786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 29796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Note: The following is basically a workaround for the fact that status 29806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates didn't do any sort of account enforcement, while social stream item 29816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates do. We can't expect callers of the old API to start passing account 29826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // information along, so we just populate the account params appropriately for 29836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // the raw contact. 29846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (accountName != null && accountType != null) { 29856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_NAME, accountName); 29866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_TYPE, accountType); 29876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 29886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 29896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Check for an existing stream item from this source, and insert or update. 29906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Uri streamUri = StreamItems.CONTENT_URI; 29916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = query(streamUri, new String[]{StreamItems._ID}, 29926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", 29936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{String.valueOf(rawContactId)}, null); 29946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 29956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (c.getCount() > 0) { 29966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.moveToFirst(); 29976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro update(ContentUris.withAppendedId(streamUri, c.getLong(0)), 29986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues, null, null); 29996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 30006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro insert(streamUri, streamItemValues); 30016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 30036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 30046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 3007e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3008e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3009bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov 3010a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (contactId != -1) { 3011f4015ab9ab7c26b766b5331fbf6655b8c54877eaDmitri Plotnikov mContactAggregator.updateLastStatusUpdateId(contactId); 3012a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3013a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3014a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov return dataId; 30151f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 30161f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 30174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3018de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 3019bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3020b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "deleteInTransaction: " + uri); 3021b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3022b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3023f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3024f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 3025508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 3026508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 302735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 3028b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().delete(mDb, selection, selectionArgs); 302935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3030b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: 3031b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3032b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3033b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3034b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().delete(mDb, selectionWithId, selectionArgs); 3035b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3036cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov case CONTACTS: { 3037cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov // TODO 3038cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return 0; 3039cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3040cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3041d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3042d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 3043dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 30446bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 30456bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 30469fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP: { 30472e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 30482e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 30492e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 3050fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 3051fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 30522e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 30532e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 30542e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final long contactId = lookupContactIdByLookupKey(mDb, lookupKey); 3055dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 30562e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 30572e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 30589fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP_ID: { 30599fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // lookup contact by id and lookup key to see if they still match the actual record 30609fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final List<String> pathSegments = uri.getPathSegments(); 30619fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final String lookupKey = pathSegments.get(2); 30629fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 30639fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann setTablesAndProjectionMapForContacts(lookupQb, uri, null); 3064a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 30659fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann String[] args; 30669fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (selectionArgs == null) { 30679fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[2]; 30689fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 30699fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[selectionArgs.length + 2]; 30709fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 30719fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 30729fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args[0] = String.valueOf(contactId); 307360de6f6c3c70e53b603a47b0efc80993353a8368Daniel Lehmann args[1] = Uri.encode(lookupKey); 30749fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?"); 30759fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 30769fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann Cursor c = query(db, lookupQb, null, selection, args, null, null, null); 30779fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann try { 30789fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (c.getCount() == 1) { 30799fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // contact was unmodified so go ahead and delete it 3080dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 30819fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 30829fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // row was changed (e.g. the merging might have changed), we got multiple 30839fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // rows or the supplied selection filtered the record out 30849fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann return 0; 30859fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 30869fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } finally { 30879fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann c.close(); 30889fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 30899fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 30909fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann 30912971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case RAW_CONTACTS: { 30922971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 3093fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov Cursor c = mDb.query(Tables.RAW_CONTACTS, 3094fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov new String[]{RawContacts._ID, RawContacts.CONTACT_ID}, 3095e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 30962971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 30972971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 30982971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = c.getLong(0); 3099fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov long contactId = c.getLong(1); 3100fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov numDeletes += deleteRawContact(rawContactId, contactId, 3101fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 31022971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31032971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 31042971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 31052971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31062971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 31072971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31082971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 31095ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 31102971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = ContentUris.parseId(uri); 3111fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return deleteRawContact(rawContactId, mDbHelper.getContactId(rawContactId), 3112fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 3113508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3114508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 311520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3116f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 3117944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong return deleteData(appendAccountToSelection(uri, selection), selectionArgs, 3118f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana callerIsSyncAdapter); 311920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 312020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 312148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 312248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 312348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 312448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3125508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 3126f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 31274da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 31284da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter); 3129ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3130ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3131ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3132f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 31335aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter); 31342971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31352971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 31362971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case GROUPS: { 31372971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 31382971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups._ID}, 3139e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 31402971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 31412971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 31425aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter); 31432971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31442971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 31452971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 31462971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 314781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (numDeletes > 0) { 3148f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 314981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 31502971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 3151508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3152508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 3153eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 315443880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3155e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs); 3156eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3157eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 315882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 31590a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov return deleteStatusUpdates(selection, selectionArgs); 31601f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 31611f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 31623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 31633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), selection, selectionArgs); 31653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 31673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 31683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), 31703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemsColumns.CONCRETE_ID + "=?", 31713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 31723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 31743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 31753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), selection, selectionArgs); 31773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 31793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 31803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 31823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 31833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), 31843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " 31853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + StreamItemPhotos.STREAM_ITEM_ID + "=?", 31863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 31873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 318981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 319081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 31913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return mLegacyApiSupport.delete(uri, selection, selectionArgs); 319281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3193508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 31944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 31954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 31961c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) { 3197ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3198b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final long groupMembershipMimetypeId = mDbHelper 319994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 3200de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 320194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 320294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupId, null); 320394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 320494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana try { 3205f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 3206de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 320794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } else { 320894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.clear(); 320994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.put(Groups.DELETED, 1); 3210f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mValues.put(Groups.DIRTY, 1); 3211de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null); 321294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 321394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } finally { 32141a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 321594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 321694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 321794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 32185aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int deleteSettings(Uri uri, String selection, String[] selectionArgs) { 3219e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final int count = mDb.delete(Tables.SETTINGS, selection, selectionArgs); 32201a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3221e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3222e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3223e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3224dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int deleteContact(long contactId, boolean callerIsSyncAdapter) { 3225afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(mDb, contactId, true); 322696b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(contactId); 3227cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, 322896b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker RawContacts.CONTACT_ID + "=?", mSelectionArgs1, 322996b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker null, null, null); 3230cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov try { 3231cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov while (c.moveToNext()) { 3232cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov long rawContactId = c.getLong(0); 3233dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 3234cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3235cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } finally { 3236cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov c.close(); 3237cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3238cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 32393826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 32403826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3241cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return mDb.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 3242cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3243cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3244fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) { 3245afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 32463389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov mContactAggregator.invalidateAggregationExceptionCache(); 32473826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 32483826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3249f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 325014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null); 3251fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov int count = mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null); 3252fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov mContactAggregator.updateDisplayNameForContact(mDb, contactId); 3253fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return count; 325433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } else { 3255b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.removeContactIfSingleton(rawContactId); 3256dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 325733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 325833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 325933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 32600a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private int deleteStatusUpdates(String selection, String[] selectionArgs) { 32619705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // delete from both tables: presence and status_updates 32629705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 32639705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (VERBOSE_LOGGING) { 32649705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori Log.v(TAG, "deleting data from status_updates for " + selection); 32659705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 32669705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mDb.delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection), 32679705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 32689705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mDb.delete(Tables.PRESENCE, selection, selectionArgs); 32690a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 32700a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 32713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItems(Uri uri, ContentValues values, String selection, 32723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 32733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream items to be deleted, and check that they belong 32743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // to the account. 32753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 32763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = enforceModifyingAccountForStreamItems( 32773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann account, selection, selectionArgs); 32783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 32803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann for (long streamItemId : streamItemIds) { 32813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(streamItemId); 32823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mVisibleTouched = true; 32853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds.size(); 32863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItem(long streamItemId) { 32893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 32903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItemPhotos(streamItemId); 32913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEMS, StreamItems._ID + "=?", 32923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 32933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(Uri uri, ContentValues values, String selection, 32963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 32973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream item photos to be deleted, and check that they 32983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // belong to the account. 32993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 33003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 33013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 33033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEM_PHOTOS, selection, selectionArgs); 33043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(long streamItemId) { 33073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 33083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEM_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID + "=?", 33093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 33103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 3312dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int markRawContactAsDeleted(long rawContactId, boolean callerIsSyncAdapter) { 331381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 331481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 3315cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.clear(); 3316cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DELETED, 1); 3317cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 3318cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1); 3319cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 3320cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3321dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return updateRawContact(rawContactId, mValues, callerIsSyncAdapter); 3322cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3323cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 33244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3325de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int updateInTransaction(Uri uri, ContentValues values, String selection, 3326de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov String[] selectionArgs) { 3327bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3328b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "updateInTransaction: " + uri); 3329b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3330b5a4add17815167d20a90645779df34cdf45280dFred Quintana 333135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 333200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 333300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 3334b5a4add17815167d20a90645779df34cdf45280dFred Quintana if (match == SYNCSTATE_ID && selection == null) { 3335b5a4add17815167d20a90645779df34cdf45280dFred Quintana long rowId = ContentUris.parseId(uri); 33361129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Object data = values.get(ContactsContract.SyncState.DATA); 3337d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.syncStateUpdated(rowId, data); 3338b5a4add17815167d20a90645779df34cdf45280dFred Quintana return 1; 3339b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3340b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3341f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3342f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 334300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 334435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 3345b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().update(mDb, values, 3346b5a4add17815167d20a90645779df34cdf45280dFred Quintana appendAccountToSelection(uri, selection), selectionArgs); 3347b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3348b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: { 3349b5a4add17815167d20a90645779df34cdf45280dFred Quintana selection = appendAccountToSelection(uri, selection); 3350b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3351b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3352b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3353b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().update(mDb, values, 3354b5a4add17815167d20a90645779df34cdf45280dFred Quintana selectionWithId, selectionArgs); 3355b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 335635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3357d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 3358dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter); 335900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 336000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 336100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3362d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3363dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(ContentUris.parseId(uri), values, callerIsSyncAdapter); 3364c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 3365c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 3366c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 336724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 336824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Restrict update to the user's profile. 336924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro StringBuilder profileSelection = new StringBuilder(); 337024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileSelection.append(Contacts.IS_USER_PROFILE + "=1"); 337124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(selection)) { 337224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileSelection.append(" AND (").append(selection).append(")"); 337324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 337424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro count = updateContactOptions(values, profileSelection.toString(), selectionArgs, 337524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro callerIsSyncAdapter); 337624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 337724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 337824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 33792e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP: 33802e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP_ID: { 33812e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 33822e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 33832e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 3384fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 3385fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 33862e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 33872e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 33882e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final long contactId = lookupContactIdByLookupKey(mDb, lookupKey); 3389dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(contactId, values, callerIsSyncAdapter); 33902e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey break; 33912e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 33922e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 33937d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh case RAW_CONTACTS_DATA: { 33947d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh final String rawContactId = uri.getPathSegments().get(1); 33957d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ") 33967d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh + (selection == null ? "" : " AND " + selection); 33977d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 33987d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter); 33997d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 34007d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh break; 34017d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh } 34027d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 340320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3404944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong count = updateData(uri, values, appendAccountToSelection(uri, selection), 3405f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 340681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3407f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 340881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 340920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 341020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3411c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 341248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 341348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 341448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 341548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3416f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter); 341781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3418f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 341981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 342000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 342100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 34227e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 34235ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 34245ac5c70d1165309302ebcc931f51723e37d31e0bJeff Sharkey selection = appendAccountToSelection(uri, selection); 3425dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, selection, selectionArgs, callerIsSyncAdapter); 34267e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 34277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 34287e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 34295ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 343033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 34314529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (selection != null) { 34324da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 34334da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov count = updateRawContacts(values, RawContacts._ID + "=?" 3434dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND(" + selection + ")", selectionArgs, 3435dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 34364529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } else { 34374da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 3438dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1, 3439dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 34404529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 34417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 34427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 34437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 3444ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 34455aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, appendAccountToSelection(uri, selection), 3446f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 344781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3448f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 344981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3450ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3451ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3452ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3453ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3454ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 34554da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId)); 34564da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String selectionWithId = Groups._ID + "=? " 345773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov + (selection == null ? "" : " AND " + selection); 34585aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, selectionWithId, selectionArgs, 34595aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey callerIsSyncAdapter); 346081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3461f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 346281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3463ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3464ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3465ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3466127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 3467de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov count = updateAggregationException(mDb, values); 3468b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 3469b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3470b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 3471eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 3472e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey count = updateSettings(uri, values, appendAccountToSelection(uri, selection), 3473e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey selectionArgs); 347443880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3475eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 3476eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3477eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 34789705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori case STATUS_UPDATES: { 34799705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori count = updateStatusUpdate(uri, values, selection, selectionArgs); 34809705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori break; 34819705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 34829705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 34833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 34843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, selection, selectionArgs); 34853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 34863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 34893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, StreamItemsColumns.CONCRETE_ID + "=?", 34903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 34913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 34923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 34953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, selection, selectionArgs); 34963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 34973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 35003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 35013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 35023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{streamItemId}); 35033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 35073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 35083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 35093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 35103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " + 35113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?", 35123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 35133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 351672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov case DIRECTORIES: { 3517bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanPackagesByUid(Binder.getCallingUid()); 351872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov count = 1; 3519d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 3520d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 3521d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 352246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa case DATA_USAGE_FEEDBACK_ID: { 352346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (handleDataUsageFeedback(uri)) { 352446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 1; 352546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 352646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 0; 352746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 352846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa break; 352946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 353046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 353181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 353281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 3533f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 353481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 353500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 353600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 353700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 35384f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 35394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 35409705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private int updateStatusUpdate(Uri uri, ContentValues values, String selection, 35419705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori String[] selectionArgs) { 35429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // update status_updates table, if status is provided 35439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 35449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori int updateCount = 0; 35459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values); 35469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 35479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori updateCount = mDb.update(Tables.STATUS_UPDATES, 35489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues, 35499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori getWhereClauseForStatusUpdatesTable(selection), 35509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 35519705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35529705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 35539705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // now update the Presence table 35549705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues = getSettableColumnsForPresenceTable(values); 35559705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 35569705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori updateCount = mDb.update(Tables.PRESENCE, settableValues, 35579705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selection, selectionArgs); 35589705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35599705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO updateCount is not entirely a valid count of updated rows because 2 tables could 35609705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // potentially get updated in this method. 35619705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return updateCount; 35629705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35639705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 35643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItems(Uri uri, ContentValues values, String selection, 35653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 35663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream items can't be moved to a new raw contact. 35673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItems.RAW_CONTACT_ID); 35683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream items being updated belong to the account. 35703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 35713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItems(account, selection, selectionArgs); 35723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream items table. 35746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 35756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 35766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 35773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If there's been no exception, the update should be fine. 35783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.update(Tables.STREAM_ITEMS, values, selection, selectionArgs); 35793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItemPhotos(Uri uri, ContentValues values, String selection, 35823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 35833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream item photos can't be moved to a new stream item. 35843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItemPhotos.STREAM_ITEM_ID); 35853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream item photos being updated belong to the account. 35873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 35883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 35893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream item 35916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 35926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 35936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 35946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 35956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo (since we're updating, it's valid for the photo to not be present). 35966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(values, true)) { 35976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // If there's been no exception, the update should be fine. 35986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return mDb.update(Tables.STREAM_ITEM_PHOTOS, values, selection, selectionArgs); 35996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 36006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 36013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36039705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori /** 36049705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori * Build a where clause to select the rows to be updated in status_updates table. 36059705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori */ 36069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private String getWhereClauseForStatusUpdatesTable(String selection) { 36079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.setLength(0); 36089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE); 36099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(selection); 36109705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(")"); 36119705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mSb.toString(); 36129705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36139705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36149705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) { 36159705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 36169705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values, 36179705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS); 36189705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values, 36199705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_TIMESTAMP); 36209705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values, 36219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_RES_PACKAGE); 36229705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values, 36239705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_LABEL); 36249705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values, 36259705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_ICON); 36269705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 36279705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36299705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForPresenceTable(ContentValues values) { 36309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 36319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values, 36329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.PRESENCE); 3633aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.CHAT_CAPABILITY, values, 3634aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori StatusUpdates.CHAT_CAPABILITY); 36359705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 36369705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36379705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36385aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int updateGroups(Uri uri, ContentValues values, String selectionWithId, 3639f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 364073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3641ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3642ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov 364373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov ContentValues updatedValues; 3644f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter && !values.containsKey(Groups.DIRTY)) { 364573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = mValues; 364673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.clear(); 364773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.putAll(values); 364873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.put(Groups.DIRTY, 1); 364973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } else { 365073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = values; 365173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 365273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3653ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey int count = mDb.update(Tables.GROUPS, updatedValues, selectionWithId, selectionArgs); 36541a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) { 36551a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 365694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 36576ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi if (updatedValues.containsKey(Groups.SHOULD_SYNC) 36581129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) { 36596ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups.ACCOUNT_NAME, 3660e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey Groups.ACCOUNT_TYPE}, selectionWithId, selectionArgs, null, 36616ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi null, null); 36626ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountName; 36636ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountType; 36646ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi try { 36656ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi while (c.moveToNext()) { 36666ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountName = c.getString(0); 36676ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountType = c.getString(1); 366824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 36696ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Account account = new Account(accountName, accountType); 3670ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov ContentResolver.requestSync(account, ContactsContract.AUTHORITY, 36716ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi new Bundle()); 36726ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi break; 36736ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 36746ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 36756ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } finally { 36766ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi c.close(); 36776ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 36786ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 367994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana return count; 368094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 368194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 3682b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private int updateSettings(Uri uri, ContentValues values, String selection, 3683b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov String[] selectionArgs) { 3684e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final int count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs); 36851a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 36861a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3687e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3688e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3689e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3690e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3691dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs, 3692dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 36934529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (values.containsKey(RawContacts.CONTACT_ID)) { 36944529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " + 36954529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov "in content values. Contact IDs are assigned automatically"); 36964529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 369773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 369897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 369997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 370097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0"); 370197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 370297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 37034529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov int count = 0; 3704ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.RAW_CONTACTS, 370551bf5ea9531b9da72caff607dbdf35fd6f61cbe2Jeff Sharkey new String[] { RawContacts._ID }, selection, 37064529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov selectionArgs, null, null, null); 37074529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov try { 37084529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov while (cursor.moveToNext()) { 37094529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov long rawContactId = cursor.getLong(0); 3710dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateRawContact(rawContactId, values, callerIsSyncAdapter); 37114529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov count++; 37124529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37134529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } finally { 37144529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov cursor.close(); 37154529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37164529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 37174529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov return count; 37184529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37194529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 3720dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContact(long rawContactId, ContentValues values, 3721dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 372224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 372324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Enforce profile permissions if the raw contact is in the user's profile. 3724afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 372524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 372696b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker final String selection = RawContacts._ID + " = ?"; 372796b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(rawContactId); 372819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED) 372919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka && values.getAsInteger(RawContacts.DELETED) == 0); 373019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int previousDeleted = 0; 3731ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType = null; 3732ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName = null; 373319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete) { 373419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka Cursor cursor = mDb.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, selection, 373596b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1, null, null, null); 373619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka try { 373719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (cursor.moveToFirst()) { 373819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka previousDeleted = cursor.getInt(RawContactsQuery.DELETED); 3739ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE); 3740ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME); 374119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 374219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } finally { 374319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka cursor.close(); 374419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 374519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 374619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT); 374719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 3748f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 374996b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker int count = mDb.update(Tables.RAW_CONTACTS, values, selection, mSelectionArgs1); 37505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count != 0) { 3751f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (values.containsKey(RawContacts.AGGREGATION_MODE)) { 3752f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = values.getAsInteger(RawContacts.AGGREGATION_MODE); 3753f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov 3754f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // As per ContactsContract documentation, changing aggregation mode 3755f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // to DEFAULT should not trigger aggregation 3756f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) { 375769cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, aggregationMode, false); 3758f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 3759f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 3760433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey if (values.containsKey(RawContacts.STARRED)) { 3761dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 3762dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 3763dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana values.getAsLong(RawContacts.STARRED) != 0); 3764dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 37654529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov mContactAggregator.updateStarred(rawContactId); 3766dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 3767dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then update the 3768dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // favorites group membership based on whether or not this contact is starred. 3769dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // If it is starred, add a group membership, if one doesn't already exist 3770dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // otherwise delete any matching group memberships. 3771dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 3772dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean starred = 0 != DatabaseUtils.longForQuery(mDb, 3773dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana SELECTION_STARRED_FROM_RAW_CONTACTS, 3774dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}); 3775dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred); 3776dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3777dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3778dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3779dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then add a 3780dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // group membership to the group marked as AutoAdd, if any. 3781dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 3782dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 3783433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey } 3784dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3785285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov if (values.containsKey(RawContacts.SOURCE_ID)) { 37862b7a632bba423357ae5641f94da6a2f71afc523bDmitri Plotnikov mContactAggregator.updateLookupKeyForRawContact(mDb, rawContactId); 3787285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 3788f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.containsKey(RawContacts.NAME_VERIFIED)) { 3789f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 3790f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // If setting NAME_VERIFIED for this raw contact, reset it for all 3791f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // other raw contacts in the same aggregate 3792f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) { 379378fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.resetNameVerifiedForOtherRawContacts(rawContactId); 3794f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 3795f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov mContactAggregator.updateDisplayNameForRawContact(mDb, rawContactId); 3796f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 379719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete && previousDeleted == 1) { 3798d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.rawContactInserted(rawContactId, 3799d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov new Account(accountName, accountType)); 380019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 38015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 38025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return count; 380333b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 380433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 3805321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana private int updateData(Uri uri, ContentValues values, String selection, 3806f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 380720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 380820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 380920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data._ID); 38105ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov mValues.remove(Data.RAW_CONTACT_ID); 381120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 381220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 381320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String packageName = values.getAsString(Data.RES_PACKAGE); 381420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (packageName != null) { 381520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 3816b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 381720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 381820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 381997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 382097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 382197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov Data.IS_READ_ONLY + "=0"); 382297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 382397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 3824653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov int count = 0; 382520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3826653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 3827653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // so we don't need to worry about updating data we don't have permission to read. 3828f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // This query will be allowed to return profiles, and we'll do the permission check 3829f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // within the loop. 38306ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Cursor c = queryLocal(uri.buildUpon() 3831f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "1").build(), 3832f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro DataRowHandler.DataUpdateQuery.COLUMNS, 38336ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro selection, selectionArgs, null, -1 /* directory ID */, 38346ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro true /* suppress profile check */); 3835653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov try { 3836653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov while(c.moveToNext()) { 383724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check profile permission for the raw contact that owns each data record. 383824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = c.getLong(DataRowHandler.DataUpdateQuery.RAW_CONTACT_ID); 3839afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 384024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 3841f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count += updateData(mValues, c, callerIsSyncAdapter); 384220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3843653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov } finally { 3844653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov c.close(); 384520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 384620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3847653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return count; 384820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 384920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3850f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) { 3851653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov if (values.size() == 0) { 3852653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return 0; 3853321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 3854653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov 3855f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String mimeType = c.getString(DataRowHandler.DataUpdateQuery.MIMETYPE); 3856a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 3857f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean updated = 3858f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro rowHandler.update(mDb, mTransactionContext, values, c, callerIsSyncAdapter); 3859f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) { 3860f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 3861a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov } 3862f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return updated ? 1 : 0; 3863321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 3864321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana 38658c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov private int updateContactOptions(ContentValues values, String selection, 3866dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 38678c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov int count = 0; 3868ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.CONTACTS, 386924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[] { Contacts._ID, Contacts.IS_USER_PROFILE }, selection, 38708c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov selectionArgs, null, null, null); 38718c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov try { 38728c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov while (cursor.moveToNext()) { 38738c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov long contactId = cursor.getLong(0); 387424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 387524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for profile write permission before updating a user's profile contact. 387624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean isProfile = cursor.getInt(1) == 1; 387724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (isProfile) { 387824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(true); 387924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 388024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 3881dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateContactOptions(contactId, values, callerIsSyncAdapter); 38828c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov count++; 38838c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 38848c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } finally { 38858c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov cursor.close(); 38868c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 38878c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 38888c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov return count; 38898c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 38908c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 3891dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateContactOptions(long contactId, ContentValues values, 3892dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 3893d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 389424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check write permission if the contact is the user's profile. 3895afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(mDb, contactId, true); 389624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 38978c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 3898b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 3899d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 3900b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 3901d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 3902b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 3903d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 3904b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 3905d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 3906b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 3907d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.STARRED); 3908d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 3909d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 39108c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.size() == 0) { 3911d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 3912d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 3913d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 39148c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.containsKey(RawContacts.STARRED)) { 3915c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey // Mark dirty when changing starred to trigger sync 39168c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3917c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey } 3918c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey 39194da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(contactId); 392097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov mDb.update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?" 392197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov + " AND " + RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0", mSelectionArgs1); 39228c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 3923dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (mValues.containsKey(RawContacts.STARRED) && !callerIsSyncAdapter) { 3924ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.RAW_CONTACTS, 3925dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=?", 3926dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mSelectionArgs1, null, null, null); 3927dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 3928dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (cursor.moveToNext()) { 3929dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana long rawContactId = cursor.getLong(0); 3930dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 3931dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mValues.getAsLong(RawContacts.STARRED) != 0); 3932dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3933dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 3934dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana cursor.close(); 3935dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3936dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3937dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 39388c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // Copy changeable values to prevent automatically managed fields from 39398c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // being explicitly updated by clients. 39408c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 3941b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 39428c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 3943b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 39448c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 3945b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 39468c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 3947b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 39488c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 3949b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 39508c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.STARRED); 39518c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 39529b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori int rslt = mDb.update(Tables.CONTACTS, mValues, Contacts._ID + "=?", mSelectionArgs1); 39536e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori 39549b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori if (values.containsKey(Contacts.LAST_TIME_CONTACTED) && 39559b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori !values.containsKey(Contacts.TIMES_CONTACTED)) { 39569b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 39579b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 39589b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori } 39599b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori return rslt; 3960f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 3961d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 3962127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 3963127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 39640c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1); 39650c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2); 396680c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 3967ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId1; 3968ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId2; 39690c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (rcId1 < rcId2) { 39700c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId1; 39710c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId2; 39720c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 39730c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId1; 39740c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId2; 3975b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3976127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 39770c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 39784da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[0] = String.valueOf(rawContactId1); 39794da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[1] = String.valueOf(rawContactId2); 39800c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, 39814da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov AggregationExceptions.RAW_CONTACT_ID1 + "=? AND " 39824da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2); 39830c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 39846bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 39856bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 39860c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 39870c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 39880c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 39890c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues); 3990127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 3991127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 39923389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov mContactAggregator.invalidateAggregationExceptionCache(); 399369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId1, 399469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 399569cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId2, 399669cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 3997dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov 3998bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateContact(mTransactionContext, db, rawContactId1); 3999bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateContact(mTransactionContext, db, rawContactId2); 4000127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 4001127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 4002127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 4003127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 4004b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4005b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 400670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong public void onAccountsUpdated(Account[] accounts) { 4007bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 40083826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 40093826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4010bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected boolean updateAccountsInBackground(Account[] accounts) { 4011f8536aaa7a52b9a7a353bc54e158becdbe79ec87Bai Tao // TODO : Check the unit test. 4012e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov boolean accountsChanged = false; 4013627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov HashSet<Account> existingAccounts = new HashSet<Account>(); 401449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov mDb = mDbHelper.getWritableDatabase(); 401570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.beginTransaction(); 401670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong try { 4017dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana findValidAccounts(existingAccounts); 4018743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov 4019743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov // Add a row to the ACCOUNTS table for each new account 4020743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov for (Account account : accounts) { 4021743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov if (!existingAccounts.contains(account)) { 4022e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 4023743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov mDb.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 4024743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov + ", " + RawContacts.ACCOUNT_TYPE + ") VALUES (?, ?)", 4025743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov new String[] {account.name, account.type}); 4026743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 4027743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 402848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 4029627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov // Remove all valid accounts from the existing account set. What is left 4030743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov // in the accountsToDelete set will be extra accounts whose data must be deleted. 4031627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov HashSet<Account> accountsToDelete = new HashSet<Account>(existingAccounts); 4032627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (Account account : accounts) { 4033627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov accountsToDelete.remove(account); 403470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 403570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong 403633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov if (!accountsToDelete.isEmpty()) { 4037e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 4038e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov for (Account account : accountsToDelete) { 4039e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov Log.d(TAG, "removing data for removed account " + account); 4040e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov String[] params = new String[] {account.name, account.type}; 4041e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4042e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.GROUPS + 4043e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Groups.ACCOUNT_NAME + " = ?" + 4044e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + Groups.ACCOUNT_TYPE + " = ?", params); 4045e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4046e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.PRESENCE + 4047e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" + 4048e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "SELECT " + RawContacts._ID + 4049e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 4050e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 4051e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + RawContacts.ACCOUNT_TYPE + " = ?)", params); 4052e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4053e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.RAW_CONTACTS + 4054e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 4055e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + RawContacts.ACCOUNT_TYPE + " = ?", params); 4056e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4057e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.SETTINGS + 4058e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Settings.ACCOUNT_NAME + " = ?" + 4059e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + Settings.ACCOUNT_TYPE + " = ?", params); 4060e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4061e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.ACCOUNTS + 4062e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + "=?" + 4063e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + RawContacts.ACCOUNT_TYPE + "=?", params); 4064d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov mDb.execSQL( 4065d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov "DELETE FROM " + Tables.DIRECTORIES + 4066d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov " WHERE " + Directory.ACCOUNT_NAME + "=?" + 4067d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov " AND " + Directory.ACCOUNT_TYPE + "=?", params); 40684458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov resetDirectoryCache(); 4069e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 4070e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov 407133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // Find all aggregated contacts that used to contain the raw contacts 407233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // we have just deleted and see if they are still referencing the deleted 4073e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov // names or photos. If so, fix up those contacts. 407433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov HashSet<Long> orphanContactIds = Sets.newHashSet(); 407533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Cursor cursor = mDb.rawQuery("SELECT " + Contacts._ID + 407633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " FROM " + Tables.CONTACTS + 407733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " WHERE (" + Contacts.NAME_RAW_CONTACT_ID + " NOT NULL AND " + 407869cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov Contacts.NAME_RAW_CONTACT_ID + " NOT IN " + 407969cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + RawContacts._ID + 408069cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + "))" + 408133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " OR (" + Contacts.PHOTO_ID + " NOT NULL AND " + 408233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Contacts.PHOTO_ID + " NOT IN " + 408369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + Data._ID + 408469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.DATA + "))", null); 408533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov try { 408633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov while (cursor.moveToNext()) { 408733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov orphanContactIds.add(cursor.getLong(0)); 408833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 408933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } finally { 409033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov cursor.close(); 409133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 409233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 409333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov for (Long contactId : orphanContactIds) { 4094bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.updateAggregateData(mTransactionContext, contactId); 409533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 4096e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDbHelper.updateAllVisible(); 4097bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 409833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 409933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 4100e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov if (accountsChanged) { 4101e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDbHelper.getSyncState().onAccountsChanged(mDb, accounts); 4102e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 410370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.setTransactionSuccessful(); 410470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } finally { 410570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.endTransaction(); 410670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 410773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.clear(); 41083826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 41093826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (accountsChanged) { 41103826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateContactsAccountCount(accounts); 41113826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 41123826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41133826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4114afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov return accountsChanged; 411570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 4116619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 41173826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateContactsAccountCount(Account[] accounts) { 41183826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov int count = 0; 41193826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov for (Account account : accounts) { 41203826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (isContactsAccount(account)) { 41213826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov count++; 41223826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41233826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41243826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mContactsAccountCount = count; 41253826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41263826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 41273826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov protected boolean isContactsAccount(Account account) { 41283826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov final IContentService cs = ContentResolver.getContentService(); 41293826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov try { 41303826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0; 41313826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } catch (RemoteException e) { 41323826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov Log.e(TAG, "Cannot obtain sync flag for account: " + account, e); 41333826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return false; 41343826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41353826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41363826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 413772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void onPackageChanged(String packageName) { 4138bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_DIRECTORIES, packageName); 4139d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4140d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4141619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 4142627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov * Finds all distinct accounts present in the specified table. 4143627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov */ 4144dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void findValidAccounts(Set<Account> validAccounts) { 4145743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov Cursor c = mDb.rawQuery( 4146743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov "SELECT " + RawContacts.ACCOUNT_NAME + "," + RawContacts.ACCOUNT_TYPE + 4147743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov " FROM " + Tables.ACCOUNTS, null); 4148627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 4149627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov while (c.moveToNext()) { 4150dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!c.isNull(0) || !c.isNull(1)) { 4151627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov validAccounts.add(new Account(c.getString(0), c.getString(1))); 4152627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4153627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4154627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } finally { 4155627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov c.close(); 4156627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4157627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4158627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov 41594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 41604f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 41614f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 416215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 416315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mReadAccessLatch); 416415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 4165d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY); 4166385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directory == null) { 41673716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 41686ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1, false)); 4169385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directory.equals("0")) { 41703716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 41713716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 41726ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Directory.DEFAULT, false)); 4173d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } else if (directory.equals("1")) { 41743716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 41753716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 41766ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Directory.LOCAL_INVISIBLE, false)); 4177d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4178d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4179d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov DirectoryInfo directoryInfo = getDirectoryAuthority(directory); 4180d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo == null) { 4181a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov Log.e(TAG, "Invalid directory ID: " + uri); 4182a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov return null; 4183d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4184d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4185d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Builder builder = new Uri.Builder(); 4186d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.scheme(ContentResolver.SCHEME_CONTENT); 4187d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.authority(directoryInfo.authority); 4188d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.encodedPath(uri.getEncodedPath()); 4189d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountName != null) { 4190d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName); 4191d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4192d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountType != null) { 4193d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType); 4194d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 41952e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 41962e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limit = getLimit(uri); 41972e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov if (limit != null) { 41982e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit); 41992e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov } 42002e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 4201d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Uri directoryUri = builder.build(); 420209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 420309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov if (projection == null) { 420409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov projection = getDefaultProjection(uri); 420509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 420609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 4207332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov Cursor cursor = getContext().getContentResolver().query(directoryUri, projection, selection, 4208d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov selectionArgs, sortOrder); 42096ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 42106ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (cursor == null) { 42116ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 42126ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42136ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 4214547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro CrossProcessCursor crossProcessCursor = getCrossProcessCursor(cursor); 4215547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (crossProcessCursor != null) { 4216547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return wrapCursor(uri, cursor); 4217547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } else { 4218547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return matrixCursorFromCursor(wrapCursor(uri, cursor)); 4219547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 42203716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 42213716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4222547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro private Cursor wrapCursor(Uri uri, Cursor cursor) { 4223547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 4224547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro // If the cursor doesn't contain a snippet column, don't bother wrapping it. 4225547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (cursor.getColumnIndex(SearchSnippetColumns.SNIPPET) < 0) { 4226547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return cursor; 4227547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 4228547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 42293716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Parse out snippet arguments for use when snippets are retrieved from the cursor. 42303716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String[] args = null; 42313716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String snippetArgs = 42323716f1447ceb21180d1301790eabd8b9453f486dDave Santoro getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 42333716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (snippetArgs != null) { 42343716f1447ceb21180d1301790eabd8b9453f486dDave Santoro args = snippetArgs.split(","); 42353716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 42363716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 42373716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String query = uri.getLastPathSegment(); 42383716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String startMatch = args != null && args.length > 0 ? args[0] 42393716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_START_MATCH; 42403716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String endMatch = args != null && args.length > 1 ? args[1] 42413716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_END_MATCH; 42423716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String ellipsis = args != null && args.length > 2 ? args[2] 42433716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_ELLIPSIS; 42443716f1447ceb21180d1301790eabd8b9453f486dDave Santoro int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 42453716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 42463716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4247547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return new SnippetizingCursorWrapper(cursor, query, startMatch, endMatch, ellipsis, 4248547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro maxTokens); 42496ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42506ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 42516ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov private CrossProcessCursor getCrossProcessCursor(Cursor cursor) { 42526ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov Cursor c = cursor; 42536ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (c instanceof CrossProcessCursor) { 42546ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return (CrossProcessCursor) c; 42556ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else if (c instanceof CursorWindow) { 42566ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return getCrossProcessCursor(((CursorWrapper) c).getWrappedCursor()); 42576ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else { 42586ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 42596ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42606ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42616ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 42626ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov public MatrixCursor matrixCursorFromCursor(Cursor cursor) { 42636ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); 42646ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov int numColumns = cursor.getColumnCount(); 42656ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov String data[] = new String[numColumns]; 42666ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov cursor.moveToPosition(-1); 42676ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov while (cursor.moveToNext()) { 42686ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov for (int i = 0; i < numColumns; i++) { 42696ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov data[i] = cursor.getString(i); 42706ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42716ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov newCursor.addRow(data); 4272332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov } 42736ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return newCursor; 4274d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4275d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4276d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final class DirectoryQuery { 4277d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final String[] COLUMNS = new String[] { 4278d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory._ID, 4279d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.DIRECTORY_AUTHORITY, 4280d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_NAME, 4281d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_TYPE 4282d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov }; 4283d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4284d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int DIRECTORY_ID = 0; 4285d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int AUTHORITY = 1; 4286d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_NAME = 2; 4287d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_TYPE = 3; 4288d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4289d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4290d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 4291d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Reads and caches directory information for the database. 4292d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 4293d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private DirectoryInfo getDirectoryAuthority(String directoryId) { 42944458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized (mDirectoryCache) { 42954458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov if (!mDirectoryCacheValid) { 42964458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.clear(); 429749d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov SQLiteDatabase db = mDbHelper.getReadableDatabase(); 429849d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Cursor cursor = db.query(Tables.DIRECTORIES, 42994458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryQuery.COLUMNS, 43004458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov null, null, null, null, null); 43014458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov try { 43024458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov while (cursor.moveToNext()) { 43034458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryInfo info = new DirectoryInfo(); 43044458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov String id = cursor.getString(DirectoryQuery.DIRECTORY_ID); 43054458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.authority = cursor.getString(DirectoryQuery.AUTHORITY); 43064458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME); 43074458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE); 43084458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.put(id, info); 43094458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 43104458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } finally { 43114458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov cursor.close(); 4312d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 43134458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = true; 4314d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4315d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 43164458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov return mDirectoryCache.get(directoryId); 43174458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 4318d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4319d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 432072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void resetDirectoryCache() { 43214458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized(mDirectoryCache) { 43224458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = false; 43234458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 432472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 432572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 43266ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private Cursor queryLocal(Uri uri, String[] projection, String selection, 43276ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro String[] selectionArgs, String sortOrder, long directoryId, 43286ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean suppressProfileCheck) { 4329bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 4330bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov Log.v(TAG, "query: " + uri); 4331bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov } 43320b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov 4333b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 433435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4335d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 43361f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 4337c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov String limit = getLimit(uri); 4338c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 4339a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 43404f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 434135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 4342b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().query(db, projection, selection, selectionArgs, 434335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana sortOrder); 434435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4345d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 4346763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 434724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean existingWhere = appendLocalDirectorySelectionIfNeeded(qb, directoryId); 43486ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, Contacts.IS_USER_PROFILE, existingWhere, 43496ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 43506ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro sortOrder = prependProfileSortIfNeeded(uri, sortOrder, suppressProfileCheck); 4351619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 4352619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 4353619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 4354d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 43554a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 4356afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 4357763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 43584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 43594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 43606bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 43616bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 43626bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 43635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP: 43645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP_ID: { 43655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 43665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = pathSegments.size(); 43675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount < 3) { 4368fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 4369fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 43705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 4371a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 43725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String lookupKey = pathSegments.get(2); 43735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount == 4) { 43745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4375afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 43765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4377763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 4378a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4379a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4380a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4381a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 4382a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 43835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return c; 43845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 43855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 43865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 4387763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 43884da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 43894da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 43904da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 43915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 43925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 43935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 43942149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_DATA: 43952149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_ID_DATA: { 43962149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 43972149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov int segmentCount = pathSegments.size(); 43982149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount < 4) { 43992149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 44002149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov "Missing a lookup key", uri)); 44012149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44022149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov String lookupKey = pathSegments.get(2); 44032149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount == 5) { 44042149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4405afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44062149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 44072149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(lookupQb, uri, projection, false); 4408a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 4409a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4410a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4411a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Data.CONTACT_ID, contactId, Data.LOOKUP_KEY, lookupKey); 4412a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 44132149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov return c; 44142149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44152149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 44162149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov // TODO see if the contact exists but has no data rows (rare) 44172149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44182149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 44192149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 442024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 4421afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44222149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 442324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 44242149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov qb.appendWhere(" AND " + Data.CONTACT_ID + "=?"); 44252149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov break; 44262149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44272149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 44283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_ID_STREAM_ITEMS: { 44293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4430afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 44323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 44333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContactsColumns.CONCRETE_CONTACT_ID + "=?"); 44343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 44353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 44373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_STREAM_ITEMS: 44383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_ID_STREAM_ITEMS: { 44393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<String> pathSegments = uri.getPathSegments(); 44403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int segmentCount = pathSegments.size(); 44413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount < 4) { 44423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new IllegalArgumentException(mDbHelper.exceptionMessage( 44433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann "Missing a lookup key", uri)); 44443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String lookupKey = pathSegments.get(2); 44463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount == 5) { 44473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(pathSegments.get(3)); 4448afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 44503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(lookupQb); 44513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 44523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann projection, selection, selectionArgs, sortOrder, groupBy, limit, 44533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RawContacts.CONTACT_ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 44543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c != null) { 44553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return c; 44563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 44593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 44603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = lookupContactIdByLookupKey(db, lookupKey); 4461afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 44633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContacts.CONTACT_ID + "=?"); 44643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 44653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4467f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: { 446842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKey = Uri.encode(uri.getPathSegments().get(2)); 446924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 4470afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 4471ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 4472f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey qb.setProjectionMap(sContactsVCardProjectionMap); 44734da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 447424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 44754da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 4476f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey break; 4477f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey } 4478f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey 447942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 448042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); 448142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann String currentDateString = dateFormat.format(new Date()).toString(); 448242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann return db.rawQuery( 448342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann "SELECT" + 448442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " 'vcards_' || ? || '.vcf' AS " + OpenableColumns.DISPLAY_NAME + "," + 448542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " NULL AS " + OpenableColumns.SIZE, 448642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann new String[] { currentDateString }); 448742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 448842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 4489ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_FILTER: { 4490916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov String filterParam = ""; 4491ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 4492916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov filterParam = uri.getLastPathSegment(); 4493ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 44947ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov setTablesAndProjectionMapForContactsWithSnippet( 44957ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov qb, uri, projection, filterParam, directoryId); 44966ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, Contacts.IS_USER_PROFILE, false, 44976ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 44986ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro sortOrder = prependProfileSortIfNeeded(uri, sortOrder, suppressProfileCheck); 4499ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4500ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4501ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 4502ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT_FILTER: 4503ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT: { 45042f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Basically the resultant SQL should look like this: 45052f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing starred items) 45062f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 45072f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing frequently contacted items) 45082f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // ORDER BY ... 45092f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 45102f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final boolean phoneOnly = readBooleanQueryParameter( 45112f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa uri, ContactsContract.STREQUENT_PHONE_ONLY, false); 45122f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (match == CONTACTS_STREQUENT_FILTER && uri.getPathSegments().size() > 3) { 45134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 45144a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4515e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(Contacts._ID + " IN "); 45165e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov appendContactFilterAsNestedQuery(sb, filterParam); 45172f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection = DbQueryUtils.concatenateClauses(selection, sb.toString()); 45184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 45194a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 45202f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] subProjection = null; 45215e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection != null) { 45222f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa subProjection = appendProjectionArg(projection, TIMES_USED_SORT_COLUMN); 45235e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 45245e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 45254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov // Build the first query for starred 45264928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 45274928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(phoneOnly ? 45284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa sStrequentPhoneOnlyStarredProjectionMap 45294928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa : sStrequentStarredProjectionMap); 45302f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 45312f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection, Contacts.IS_USER_PROFILE + "=0")); 45322f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 45332f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String starredQuery = qb.buildQuery(subProjection, 453424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Contacts.STARRED + "=1", Contacts._ID, null, null, null); 4535d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 45362f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Reset the builder. 4537d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 45382f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 45394928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 45404928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // Build the second query for frequent part. 45414928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final String frequentQuery; 45424928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (phoneOnly) { 45434928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final StringBuilder tableBuilder = new StringBuilder(); 45444928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // In phone only mode, we need to look at view_data instead of 45454928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // contacts/raw_contacts to obtain actual phone numbers. One problem is that 45464928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data is much larger than view_contacts, so our query might become much 45474928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // slower. 45484928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // 45494928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // To avoid the possible slow down, we start from data usage table and join 45504928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data to the table, assuming data usage table is quite smaller than 45514928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // data rows (almost always it should be), and we don't want any phone 45524928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // numbers not used by the user. This way sqlite is able to drop a number of 45534928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // rows in view_data in the early stage of data lookup. 45544928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa tableBuilder.append(Tables.DATA_USAGE_STAT 45554928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " INNER JOIN " + Views.DATA + " " + Tables.DATA 45564928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" 45574928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataColumns.CONCRETE_ID + " AND " 45584928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" 45594928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT_CALL + ")"); 45604928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactPresenceJoin(tableBuilder, projection, RawContacts.CONTACT_ID); 45614928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactStatusUpdateJoin(tableBuilder, projection, 45624928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa ContactsColumns.LAST_STATUS_UPDATE_ID); 45634928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 45644928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setTables(tableBuilder.toString()); 45654928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentPhoneOnlyFrequentProjectionMap); 45664928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 45674928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 45684928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.STARRED + "=0 OR " + Contacts.STARRED + " IS NULL", 45694928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa MimetypesColumns.MIMETYPE + " IN (" 45704928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + Phone.CONTENT_ITEM_TYPE + "', " 45714928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + SipAddress.CONTENT_ITEM_TYPE + "')")); 45724928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, null, null, null, null, null); 45734928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } else { 45744928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 45754928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 45764928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 45774928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 45784928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa "(" + Contacts.STARRED + " =0 OR " + Contacts.STARRED + " IS NULL)", 45794928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.IS_USER_PROFILE + "=0")); 45804928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, 45814928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa null, Contacts._ID, null, null, null); 45824928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } 4583d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 4584d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 45852f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String unionQuery = 45862f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, 45872f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa STREQUENT_ORDER_BY, STREQUENT_LIMIT); 45882f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 45892f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Here, we need to use selection / selectionArgs (supplied from users) "twice", 45902f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // as we want them both for starred items and for frequently contacted items. 45912f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // 45922f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // e.g. if the user specify selection = "starred =?" and selectionArgs = "0", 45932f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // the resultant SQL should be like: 45942f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 45952f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 45962f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 45972f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] doubledSelectionArgs = null; 45982f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (selectionArgs != null) { 45992f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final int length = selectionArgs.length; 46002f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa doubledSelectionArgs = new String[length * 2]; 46017d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, 0, length); 46027d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, length, length); 46032f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 46042f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 46052f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa Cursor cursor = db.rawQuery(unionQuery, doubledSelectionArgs); 46062f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (cursor != null) { 46072f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa cursor.setNotificationUri(getContext().getContentResolver(), 4608d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 4609d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 46102f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa return cursor; 4611d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 4612d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 461345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa case CONTACTS_FREQUENT: { 461445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 461545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 461645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 461745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa selection, 461845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa Contacts.IS_USER_PROFILE + "=0")); 461945ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa groupBy = Contacts._ID; 462045ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa if (!TextUtils.isEmpty(sortOrder)) { 462145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY + ", " + sortOrder; 462245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } else { 462345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY; 462445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 462545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa break; 462645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 462745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 4628ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_GROUP: { 4629763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 4630b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 463171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 46324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 4633b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4634b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 4635b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4636b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 463724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 463824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 463924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 464024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(Contacts.IS_USER_PROFILE + "=1"); 464124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 464224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 464324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 464424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: { 464524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 464624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForEntities(qb, uri, projection); 464724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + Contacts.IS_USER_PROFILE + "=1"); 464824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 464924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 465024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 465124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: { 465224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 465324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 465424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 465524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 465624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 465724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 465824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA_ID: { 465924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 466024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 466124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 466224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + Data._ID + "=? AND " 466324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 466424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 466524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 466624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 466724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: { 466824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 4669ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 467024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.setProjectionMap(sContactsVCardProjectionMap); 467124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(Contacts.IS_USER_PROFILE + "=1"); 467224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 467324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 467424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 4675a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_DATA: { 46764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 467782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 46784da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 46794da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 46806bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 46816bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 468200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 4683a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 46843653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4685afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 468682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 46874da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 46884da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 46893653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 46903653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov break; 46913653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov } 46923653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 4693a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_ENTITIES: { 4694a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4695a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 4696a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 4697a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 4698a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 4699a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4700a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4701a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ENTITIES: 4702a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ID_ENTITIES: { 4703a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 4704a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov int segmentCount = pathSegments.size(); 4705a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount < 4) { 4706a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 4707a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov "Missing a lookup key", uri)); 4708a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4709a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lookupKey = pathSegments.get(2); 4710a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount == 5) { 4711a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4712a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4713a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(lookupQb, uri, projection); 4714a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 4715a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4716a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4717a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4718a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.CONTACT_ID, contactId, 4719a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.LOOKUP_KEY, lookupKey); 4720a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 4721a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 4722a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4723a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4724a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4725a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 4726a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 4727a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 4728a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + Contacts.Entity.CONTACT_ID + "=?"); 4729a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 4730a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4731a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 47323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 47333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 47343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 47383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 47393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 47403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemsColumns.CONCRETE_ID + "=?"); 47413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_LIMIT: { 47456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro MatrixCursor cursor = new MatrixCursor(new String[]{StreamItems.MAX_ITEMS}, 1); 47466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro cursor.addRow(new Object[]{MAX_STREAM_ITEMS_PER_RAW_CONTACT}); 47473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return cursor; 47483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 47513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 47523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 47563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 47573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 47583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 47593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?"); 47603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 47643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 47653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 47663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 47673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemPhotoId); 47683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 47693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=? AND " + 47703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=?"); 47713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4774f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case PHOTO_DIMENSIONS: { 4775f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro MatrixCursor cursor = new MatrixCursor( 4776f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM}, 4777f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1); 4778f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cursor.addRow(new Object[]{mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim}); 4779f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return cursor; 4780f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 4781f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 47824a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case PHONES: { 478382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 478489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 47852815f58f72f109790585931f601a63ddc02536a5Evan Millar break; 47862815f58f72f109790585931f601a63ddc02536a5Evan Millar } 47872815f58f72f109790585931f601a63ddc02536a5Evan Millar 478848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: { 478982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 47904da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 479148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 47924da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 479348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 479448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 479548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 4796ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES_FILTER: { 479746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 479846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 479946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 480046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_CALL; 480146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 480246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 480389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 4804ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 48054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 48064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4807a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(" AND ("); 48085e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 480945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov boolean hasCondition = false; 48105e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov boolean orNeeded = false; 48115e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov String normalizedName = NameNormalizer.normalize(filterParam); 48125e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (normalizedName.length() > 0) { 4813155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(Data.RAW_CONTACT_ID + " IN " + 4814155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 4815155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 4816155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 4817155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 4818155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 4819155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 48202352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 4821155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 48225e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov orNeeded = true; 482345d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 48245e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 48255e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 4826892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String number = PhoneNumberUtils.normalizeNumber(filterParam); 4827892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (!TextUtils.isEmpty(number)) { 48285e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (orNeeded) { 48295e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(" OR "); 48305e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 48315e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(Data._ID + 4832892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID 4833892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " FROM " + Tables.PHONE_LOOKUP 4834892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 4835892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append(number); 4836892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append("%')"); 483745d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 483845d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov } 483945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov 484045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov if (!hasCondition) { 484145d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // If it is neither a phone number nor a name, the query should return 484245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // an empty cursor. Let's ensure that. 484345d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov sb.append("0"); 48445e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 48455e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 4846a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 4847ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 48485e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = PhoneColumns.NORMALIZED_NUMBER + "," + RawContacts.CONTACT_ID; 4849a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 485046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 485146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 485246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + PHONE_FILTER_SORT_ORDER; 485346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 485446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = PHONE_FILTER_SORT_ORDER; 485546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 4856a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 4857ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4858ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4859ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 48604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case EMAILS: { 486182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 486289c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 48634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov break; 48644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 48654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 486648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: { 486782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 48684da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 48694da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'" 48704da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + " AND " + Data._ID + "=?"); 487148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 487248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 487348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 48745e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_LOOKUP: { 487582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 487689c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 48774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov if (uri.getPathSegments().size() > 2) { 487808768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String email = uri.getLastPathSegment(); 487908768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String address = mDbHelper.extractAddressFromEmailAddress(email); 488008768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, address); 488108768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)"); 48824a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 4883ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4884ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4885ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 48865e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_FILTER: { 488746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 488846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 488946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 489046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT; 489146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 489246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 489307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov String filterParam = null; 48947d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa 489507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 489607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = uri.getLastPathSegment(); 489707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (TextUtils.isEmpty(filterParam)) { 489807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = null; 489907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 490007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 49015e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 490207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (filterParam == null) { 490307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov // If the filter is unspecified, return nothing 490407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov qb.appendWhere(" AND 0"); 490507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } else { 490607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov StringBuilder sb = new StringBuilder(); 490707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append(" AND " + Data._ID + " IN ("); 490807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append( 490907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov "SELECT " + Data._ID + 491007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov " FROM " + Tables.DATA + 49112a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov " WHERE " + DataColumns.MIMETYPE_ID + "="); 49122a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(mDbHelper.getMimeTypeIdForEmail()); 49132a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(" AND " + Data.DATA1 + " LIKE "); 491407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 491520938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov if (!filterParam.contains("@")) { 4916155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append( 4917155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " UNION SELECT " + Data._ID + 4918155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.DATA + 4919155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE +" + DataColumns.MIMETYPE_ID + "="); 4920155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(mDbHelper.getMimeTypeIdForEmail()); 4921155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(" AND " + Data.RAW_CONTACT_ID + " IN " + 4922155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 4923155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 4924155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 4925155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 4926155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 4927155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 49282352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 4929155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 49305e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49315e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 4932a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 49335e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49345e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = Email.DATA + "," + RawContacts.CONTACT_ID; 4935a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 493646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 493746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 493846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + EMAIL_FILTER_SORT_ORDER; 49397d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } else { 49407d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa sortOrder = EMAIL_FILTER_SORT_ORDER; 49417d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } 4942a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 49435e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov break; 49445e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49455e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 4946ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 494782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 494889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 494989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 4950ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4951ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4952ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 495348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 495482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 49554da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 495648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 495748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 49584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 495948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 496048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 496148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 49625ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 4963763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 49646ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, RawContacts.RAW_CONTACT_IS_USER_PROFILE, true, 49656ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 49664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 49674f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 49684f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 49695ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 49705ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 4971afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 4972763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 49734da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 49744da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 49754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 49764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 49774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 49785ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 49795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 498082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 49814da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 49824da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?"); 49836ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, RawContacts.RAW_CONTACT_IS_USER_PROFILE, true, 49846ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 498524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 498624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 498724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 49883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 49893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 4990afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 49913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 49923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 49933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=?"); 49943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 49953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 499624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 499724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 499824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 499924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 500024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 500124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 500224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 500324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 500424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: { 500524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 500624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = ContentUris.parseId(uri); 500724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 500824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 500924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 501024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts._ID + "=?"); 501124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 501224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 501324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 501424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 501524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 501624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 501724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 501824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 501924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 502024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + Data.RAW_CONTACT_ID + "=?"); 502124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 502224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 502324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 502424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_ENTITIES: { 502524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 502624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 502724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 502824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawEntities(qb, uri); 502924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 503024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts._ID + "=?"); 5031e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5032e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5033e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 5034e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey case DATA: { 503582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50366ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, RawContacts.RAW_CONTACT_IS_USER_PROFILE, true, 50376ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 5038e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5039e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5040e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 50414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case DATA_ID: { 504224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = ContentUris.parseId(uri); 5043afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForData(db, dataId, false); 504482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50454da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 50464da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 5047a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov break; 5048a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov } 5049a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov 5050a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 50514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 5052a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton if (TextUtils.isEmpty(sortOrder)) { 5053a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Default the sort order to something reasonable so we get consistent 5054a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // results when callers don't request an ordering 5055892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sortOrder = " length(lookup.normalized_number) DESC"; 5056a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5057a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5058e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : ""; 5059e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov String numberE164 = PhoneNumberUtils.formatNumberToE164(number, 5060e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov mDbHelper.getCurrentCountryIso()); 5061892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String normalizedNumber = 5062892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov PhoneNumberUtils.normalizeNumber(number); 5063892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov mDbHelper.buildPhoneLookupAndContactQuery(qb, normalizedNumber, numberE164); 5064e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov qb.setProjectionMap(sPhoneLookupProjectionMap); 5065e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov // Phone lookup cannot be combined with a selection 5066e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selection = null; 5067e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selectionArgs = null; 5068a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 5069a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5070a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5071ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 5072ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5073ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 507489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov appendAccountFromParameter(qb, uri); 5075ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5076ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5077ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5078ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 5079ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5080ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 50814da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 50824da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Groups._ID + "=?"); 5083ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5084ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5085ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5086ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 5087ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS + " AS groups"); 5088ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsSummaryProjectionMap); 508989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov appendAccountFromParameter(qb, uri); 509089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov groupBy = Groups._ID; 5091ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5092ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5093ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5094b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 50950c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS); 5096b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 5097b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 5098b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 5099b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 510031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 5101d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 51022d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov String filter = null; 51032d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 51042d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov filter = uri.getPathSegments().get(3); 51052d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov } 510631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 5107d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov if (limit != null) { 5108d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov maxSuggestions = Integer.parseInt(limit); 510931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 511031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 511131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 511231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 51135b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ArrayList<AggregationSuggestionParameter> parameters = null; 51145b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov List<String> query = uri.getQueryParameters("query"); 51155b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov if (query != null && !query.isEmpty()) { 51165b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters = new ArrayList<AggregationSuggestionParameter>(query.size()); 51175b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov for (String parameter : query) { 51185b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov int offset = parameter.indexOf(':'); 51195b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters.add(offset == -1 51205b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ? new AggregationSuggestionParameter( 512176dfa406e2cde19c824983c37fc92c1c5bf63eecDaniel Lehmann AggregationSuggestions.PARAMETER_MATCH_NAME, 51225b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter) 51235b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov : new AggregationSuggestionParameter( 51245b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(0, offset), 51255b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(offset + 1))); 51265b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 51275b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 51285b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 5129763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 51307581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov 51317581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov return mContactAggregator.queryAggregationSuggestions(qb, projection, contactId, 51325b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov maxSuggestions, filter, parameters); 513331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 513431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 5135eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 5136eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setTables(Tables.SETTINGS); 5137eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setProjectionMap(sSettingsProjectionMap); 513889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov appendAccountFromParameter(qb, uri); 5139e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5140e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // When requesting specific columns, this query requires 5141e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // late-binding of the GroupMembership MIME-type. 5142b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final String groupMembershipMimetypeId = Long.toString(mDbHelper 5143e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 514482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 5145b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.isInProjection(projection, Settings.UNGROUPED_COUNT)) { 5146e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5147e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 514882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 5149b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.isInProjection(projection, Settings.UNGROUPED_WITH_PHONES)) { 5150e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5151e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 5152e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5153eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 5154eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 5155eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 515682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 51570a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 51585ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 51595ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 51605ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 516182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES_ID: { 51620a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 51634da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 51644da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(DataColumns.CONCRETE_ID + "=?"); 51655ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 51665ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 51675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 5168c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: { 5169174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchSuggestionsQuery( 5170174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, uri, projection, limit); 5171c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5172c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 5173c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: { 51742d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill String lookupKey = uri.getLastPathSegment(); 5175174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String filter = getQueryParameter( 5176174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov uri, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 5177174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchShortcutRefresh( 5178174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, projection, lookupKey, filter); 5179c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5180c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 51811b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS: 5182ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 51831b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 51841b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 51851b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 51861b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_WITH_PHONES: 5187ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 51881b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 51891b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1"); 51901b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 51911b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 51921b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_FAVORITES: 5193ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 51941b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 51951b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.STARRED + "=1"); 51961b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 51971b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 51981b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_GROUP_NAME: 5199ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 52001b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 520171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 52021b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 52031b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 52041b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 520546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITIES: { 5206a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 520746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 520846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 520946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 521046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITY_ID: { 521146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5212a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 52134da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 52144da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 521546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 521646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 521746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 521809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov case PROVIDER_STATUS: { 521909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return queryProviderStatus(uri, projection); 522009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 522109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5222d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES : { 5223d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5224d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5225d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5226d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5227d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 5228d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID : { 5229385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov long id = ContentUris.parseId(uri); 5230d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5231d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5232385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(id)); 5233d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.appendWhere(Directory._ID + "=?"); 5234d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5235d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5236d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 52377a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov case COMPLETE_NAME: { 52387a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return completeName(uri, projection); 52397a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 52407a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 52414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 5242f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 5243c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov sortOrder, limit); 52444f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 52454f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 524609e69522745551522c55dff27424496f255def46Daniel Lehmann qb.setStrict(true); 52477f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov 5248ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov Cursor cursor = 5249ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit); 5250ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) { 5251ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov cursor = bundleLetterCountExtras(cursor, db, qb, selection, selectionArgs, sortOrder); 5252ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5253ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov return cursor; 52545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 52555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 52565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection, 52575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String selection, String[] selectionArgs, String sortOrder, String groupBy, 52585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String limit) { 5259038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana if (projection != null && projection.length == 1 5260038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana && BaseColumns._COUNT.equals(projection[0])) { 5261038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana qb.setProjectionMap(sCountProjectionMap); 5262038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana } 52635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null, 52645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sortOrder, limit); 52654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 52664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 52674f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 52684f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 52694f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 52704f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 527109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov /** 527209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov * Creates a single-row cursor containing the current status of the provider. 527309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov */ 527409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private Cursor queryProviderStatus(Uri uri, String[] projection) { 527509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 527609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov RowBuilder row = cursor.newRow(); 527709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov for (int i = 0; i < projection.length; i++) { 527809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov if (ProviderStatus.STATUS.equals(projection[i])) { 527909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mProviderStatus); 528009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } else if (ProviderStatus.DATA1.equals(projection[i])) { 528109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mEstimatedStorageRequirement); 528209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 528309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 528409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return cursor; 528509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 528609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5287a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** 5288a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * Runs the query with the supplied contact ID and lookup ID. If the query succeeds, 5289a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * it returns the resulting cursor, otherwise it returns null and the calling 5290a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * method needs to resolve the lookup key and rerun the query. 5291a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov */ 5292a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private Cursor queryWithContactIdAndLookupKey(SQLiteQueryBuilder lookupQb, 5293a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteDatabase db, Uri uri, 5294a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection, String selection, String[] selectionArgs, 5295a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String sortOrder, String groupBy, String limit, 5296a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn, long contactId, String lookupKeyColumn, String lookupKey) { 5297a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] args; 5298a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (selectionArgs == null) { 5299a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[2]; 5300a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } else { 5301a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[selectionArgs.length + 2]; 5302a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 5303a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5304a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[0] = String.valueOf(contactId); 5305a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[1] = Uri.encode(lookupKey); 5306a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(contactIdColumn + "=? AND " + lookupKeyColumn + "=?"); 5307a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = query(db, lookupQb, projection, selection, args, sortOrder, 5308a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov groupBy, limit); 5309a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c.getCount() != 0) { 5310a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5311a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5312a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5313a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov c.close(); 5314a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return null; 5315a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 531609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5317bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov private static final class AddressBookIndexQuery { 5318bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String LETTER = "letter"; 5319bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String TITLE = "title"; 5320bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String COUNT = "count"; 5321ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5322bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String[] COLUMNS = new String[] { 5323bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov LETTER, TITLE, COUNT 5324ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov }; 5325ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5326bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_LETTER = 0; 5327bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_TITLE = 1; 5328bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_COUNT = 2; 5329bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 533024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The first letter of the sort key column is what is used for the index headings, except 533124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // in the case of the user's profile, in which case it is empty. 533224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro public static final String SECTION_HEADING_TEMPLATE = 533324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "(CASE WHEN %1$s=1 THEN '' ELSE SUBSTR(%2$s,1,1) END)"; 533424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5335de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa public static final String ORDER_BY = LETTER + " COLLATE " + PHONEBOOK_COLLATOR_NAME; 5336ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5337ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5338ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov /** 5339ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * Computes counts by the address book index titles and adds the resulting tally 5340ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * to the returned cursor as a bundle of extras. 5341ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov */ 5342ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov private Cursor bundleLetterCountExtras(Cursor cursor, final SQLiteDatabase db, 5343ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov SQLiteQueryBuilder qb, String selection, String[] selectionArgs, String sortOrder) { 5344ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortKey; 5345ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5346ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // The sort order suffix could be something like "DESC". 5347ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // We want to preserve it in the query even though we will change 5348ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // the sort column itself. 5349ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortOrderSuffix = ""; 5350ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (sortOrder != null) { 535124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 535224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // If the sort order contains one of the "is_profile" columns, we need to strip it out 535324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // first. 535424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (sortOrder.contains(Contacts.IS_USER_PROFILE) 535524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro || sortOrder.contains(RawContacts.RAW_CONTACT_IS_USER_PROFILE)) { 535624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String[] splitOrderClauses = sortOrder.split(","); 535724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro StringBuilder rejoinedClause = new StringBuilder(); 535824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro for (String orderClause : splitOrderClauses) { 535924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!orderClause.contains(Contacts.IS_USER_PROFILE) 536024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro && !orderClause.contains(RawContacts.RAW_CONTACT_IS_USER_PROFILE)) { 536124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (rejoinedClause.length() > 0) { 536224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro rejoinedClause.append(", "); 536324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 536424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro rejoinedClause.append(orderClause.trim()); 536524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 536624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 536724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sortOrder = rejoinedClause.toString(); 536824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 536924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5370ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int spaceIndex = sortOrder.indexOf(' '); 5371ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (spaceIndex != -1) { 5372ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder.substring(0, spaceIndex); 5373ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortOrderSuffix = sortOrder.substring(spaceIndex); 5374ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5375ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder; 5376ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5377ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5378ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = Contacts.SORT_KEY_PRIMARY; 5379ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5380ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5381bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String locale = getLocale().toString(); 5382ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov HashMap<String, String> projectionMap = Maps.newHashMap(); 538324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 538424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The user profile column varies depending on the view. 5385ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann String profileColumn = qb.getTables().contains(Views.CONTACTS) 538624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro ? Contacts.IS_USER_PROFILE 538724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro : RawContacts.RAW_CONTACT_IS_USER_PROFILE; 538824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String sectionHeading = String.format( 538924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro AddressBookIndexQuery.SECTION_HEADING_TEMPLATE, profileColumn, sortKey); 5390bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov projectionMap.put(AddressBookIndexQuery.LETTER, 539124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sectionHeading + " AS " + AddressBookIndexQuery.LETTER); 5392bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5393bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov /** 5394bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * Use the GET_PHONEBOOK_INDEX function, which is an android extension for SQLite3, 5395bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * to map the first letter of the sort key to a character that is traditionally 5396bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * used in phonebooks to represent that letter. For example, in Korean it will 5397bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * be the first consonant in the letter; for Japanese it will be Hiragana rather 5398bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * than Katakana. 5399bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov */ 5400ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.TITLE, 540124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "GET_PHONEBOOK_INDEX(" + sectionHeading + ",'" + locale + "')" 5402bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov + " AS " + AddressBookIndexQuery.TITLE); 5403ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.COUNT, 5404ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov "COUNT(" + Contacts._ID + ") AS " + AddressBookIndexQuery.COUNT); 5405ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov qb.setProjectionMap(projectionMap); 5406ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5407f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs, 5408ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY, null /* having */, 5409ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY + sortOrderSuffix); 5410ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5411ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov try { 5412f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov int groupCount = indexCursor.getCount(); 5413ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String titles[] = new String[groupCount]; 5414ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int counts[] = new int[groupCount]; 5415bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int indexCount = 0; 5416bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String currentTitle = null; 5417bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5418bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // Since GET_PHONEBOOK_INDEX is a many-to-1 function, we may end up 5419bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // with multiple entries for the same title. The following code 5420bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // collapses those duplicates. 5421ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov for (int i = 0; i < groupCount; i++) { 5422f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.moveToNext(); 5423bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String title = indexCursor.getString(AddressBookIndexQuery.COLUMN_TITLE); 5424bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int count = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT); 5425bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount == 0 || !TextUtils.equals(title, currentTitle)) { 5426bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles[indexCount] = currentTitle = title; 5427bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount] = count; 5428bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov indexCount++; 5429bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } else { 5430bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount - 1] += count; 5431bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5432bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5433bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5434bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount < groupCount) { 5435bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String[] newTitles = new String[indexCount]; 5436bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(titles, 0, newTitles, 0, indexCount); 5437bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles = newTitles; 5438bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5439bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int[] newCounts = new int[indexCount]; 5440bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(counts, 0, newCounts, 0, indexCount); 5441bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts = newCounts; 5442ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5443ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5444e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return new AddressBookCursor((CrossProcessCursor) cursor, titles, counts); 5445ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } finally { 5446f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.close(); 5447ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5448ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5449ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 54502d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill /** 545192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Returns the contact Id for the contact identified by the lookupKey. 545292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Robust against changes in the lookup key: if the key has changed, will 545392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * look up the contact by the raw contact IDs or name encoded in the lookup 545492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * key. 54552d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill */ 54562d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) { 54575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey key = new ContactLookupKey(); 54585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments = key.parse(lookupKey); 54595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 546092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov long contactId = -1; 546192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_SOURCE_ID)) { 546292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdBySourceIds(db, segments); 546392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 546492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 546592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 546692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 546792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 546892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov boolean hasRawContactIds = 546992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID); 547092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds) { 547192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdByRawContactIds(db, segments); 547292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 547392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 547492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 547592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 547692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 547792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds 547892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME)) { 54795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = lookupContactIdByDisplayNames(db, segments); 54805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 54815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 54835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 54845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private interface LookupBySourceIdQuery { 54865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String TABLE = Tables.RAW_CONTACTS; 54875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 54895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 54905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 54915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 54925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.SOURCE_ID 54935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 54945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 54955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 54965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_TYPE = 1; 54975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 54985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int SOURCE_ID = 3; 54995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long lookupContactIdBySourceIds(SQLiteDatabase db, 55025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments) { 55035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 55045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(RawContacts.SOURCE_ID + " IN ("); 55055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 55065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 550792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID) { 55085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 55095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 55105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 55135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 55145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS, 55165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 55175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 55185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 55195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountType = c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE); 55205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME); 55215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 55225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey.getAccountHashCode(accountType, accountName); 55235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID); 55245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 55255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 552692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID 552792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 55285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(sourceId)) { 55295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID); 55305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 55315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 55355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 55365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 55395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 554192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByRawContactIdQuery { 554292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.RAW_CONTACTS; 55435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 55455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 55465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 55475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 554892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts._ID, 55495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 55505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 55525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_TYPE = 1; 55535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 555492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ID = 3; 55555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 555792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByRawContactIds(SQLiteDatabase db, 555892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 555992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 556092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(RawContacts._ID + " IN ("); 55615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 55625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 556392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 556492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(segment.rawContactId); 556592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(","); 55665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 556892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 556992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 55705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 557192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov Cursor c = db.query(LookupByRawContactIdQuery.TABLE, LookupByRawContactIdQuery.COLUMNS, 557292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.toString(), null, null, null, null); 557392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov try { 557492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov while (c.moveToNext()) { 557592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountType = c.getString(LookupByRawContactIdQuery.ACCOUNT_TYPE); 557692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountName = c.getString(LookupByRawContactIdQuery.ACCOUNT_NAME); 557792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int accountHashCode = 557892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ContactLookupKey.getAccountHashCode(accountType, accountName); 557992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String rawContactId = c.getString(LookupByRawContactIdQuery.ID); 558092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 558192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 558292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID 558392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 558492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && segment.rawContactId.equals(rawContactId)) { 558592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov segment.contactId = c.getLong(LookupByRawContactIdQuery.CONTACT_ID); 558692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov break; 558792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 558892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 558992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 559092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } finally { 559192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov c.close(); 55925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 559492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return getMostReferencedContactId(segments); 559592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 559692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 559792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByDisplayNameQuery { 559892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS; 559992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 560092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String COLUMNS[] = { 560192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.CONTACT_ID, 560292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 560392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 560492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov NameLookupColumns.NORMALIZED_NAME 560592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov }; 560692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 560792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int CONTACT_ID = 0; 560892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_TYPE = 1; 560992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_NAME = 2; 561092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int NORMALIZED_NAME = 3; 561192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 561292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 561392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByDisplayNames(SQLiteDatabase db, 561492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 56155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 56165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(NameLookupColumns.NORMALIZED_NAME + " IN ("); 56175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 56185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 561992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 562092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 56215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 56225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 56235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 56265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY 56275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov + " AND " + RawContacts.CONTACT_ID + " NOT NULL"); 56285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS, 56305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 56315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 56325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 56335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountType = c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE); 56345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME); 56355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 56365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey.getAccountHashCode(accountType, accountName); 56375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME); 56385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 56395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 564092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if ((segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 564192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) 564292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 56435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(name)) { 56445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID); 56455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 56465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 56505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 56515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 56545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 565692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private boolean lookupKeyContainsType(ArrayList<LookupKeySegment> segments, int lookupType) { 565792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 565892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 565992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == lookupType) { 566092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return true; 566192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 566292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 566392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 566492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return false; 566592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 566692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 5667ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateLookupKeyForRawContact(SQLiteDatabase db, long rawContactId) { 5668ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov mContactAggregator.updateLookupKeyForRawContact(db, rawContactId); 5669ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov } 5670ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov 56715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov /** 56725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov * Returns the contact ID that is mentioned the highest number of times. 56735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov */ 56745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) { 56755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Collections.sort(segments); 56765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long bestContactId = -1; 56785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int bestRefCount = 0; 56795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = -1; 56815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int count = 0; 56825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = segments.size(); 56845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segmentCount; i++) { 56855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 56865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId != -1) { 56875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId == contactId) { 56885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count++; 56895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 56905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 56915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestContactId = contactId; 56925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestRefCount = count; 56935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = segment.contactId; 56955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count = 1; 56965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 57005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 57015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 57025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return bestContactId; 57035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 5706763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 5707763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar String[] projection) { 57084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 57092f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 57102f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 57112f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 57124928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * @param includeDataUsageStat true when the table should include DataUsageStat table. 57134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Note that this uses INNER JOIN instead of LEFT OUTER JOIN, so some of data in Contacts 57144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * may be dropped. 57152f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 57162f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 57174928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa String[] projection, boolean includeDataUsageStat) { 571882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 5719ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 57202f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 57212f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Just for frequently contacted contacts in Strequent Uri handling. 57224928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (includeDataUsageStat) { 57232f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa sb.append(" INNER JOIN " + 5724ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA_USAGE_STAT + " AS " + Tables.DATA_USAGE_STAT + 57252f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa " ON (" + 57262f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DbQueryUtils.concatenateClauses( 57272f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DataUsageStatColumns.CONCRETE_TIMES_USED + " > 0", 57284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) + 57292f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa ")"); 57302f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 57312f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 57327ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 57337ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 5734916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setTables(sb.toString()); 5735916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionMap); 5736916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov } 5737916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 5738916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** 5739916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * Finds name lookup records matching the supplied filter, picks one arbitrary match per 5740916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * contact and joins that with other contacts tables. 5741916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov */ 5742916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private void setTablesAndProjectionMapForContactsWithSnippet(SQLiteQueryBuilder qb, Uri uri, 57437ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov String[] projection, String filter, long directoryId) { 57447ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov 57457ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5746ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 5747916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 574803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (filter != null) { 574903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov filter = filter.trim(); 575003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 575103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 575230cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov if (TextUtils.isEmpty(filter) || (directoryId != -1 && directoryId != Directory.DEFAULT)) { 575330cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov sb.append(" JOIN (SELECT NULL AS " + SearchSnippetColumns.SNIPPET + " WHERE 0)"); 57545e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } else { 57555e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov appendSearchIndexJoin(sb, uri, projection, filter); 57565e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 57577ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 57587ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 575903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setTables(sb.toString()); 576003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionWithSnippetMap); 576103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 5762916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 576303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private void appendSearchIndexJoin( 576403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov StringBuilder sb, Uri uri, String[] projection, String filter) { 5765916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 5766174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET)) { 576703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String[] args = null; 576803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String snippetArgs = 576903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 577003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (snippetArgs != null) { 577103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov args = snippetArgs.split(","); 577203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 577303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 57745e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String startMatch = args != null && args.length > 0 ? args[0] 57755e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_START_MATCH; 57765e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String endMatch = args != null && args.length > 1 ? args[1] 57775e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_END_MATCH; 57785e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String ellipsis = args != null && args.length > 2 ? args[2] 57795e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_ELLIPSIS; 57805e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 57815e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 57825e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 5783174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin( 5784174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb, filter, true, startMatch, endMatch, ellipsis, maxTokens); 5785174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 5786174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin(sb, filter, false, null, null, null, 0); 5787174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5788174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5789174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 5790174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public void appendSearchIndexJoin(StringBuilder sb, String filter, 5791174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean snippetNeeded, String startMatch, String endMatch, String ellipsis, 5792174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int maxTokens) { 5793174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isEmailAddress = false; 5794174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String emailAddress = null; 5795174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isPhoneNumber = false; 5796174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String phoneNumber = null; 5797174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String numberE164 = null; 5798174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 57993716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // If the query consists of a single word, we can do snippetizing after-the-fact for a 58003716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // performance boost. 58013716f1447ceb21180d1301790eabd8b9453f486dDave Santoro boolean singleTokenSearch = filter.split(QUERY_TOKENIZER_REGEX).length == 1; 58023716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 5803174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (filter.indexOf('@') != -1) { 5804174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov emailAddress = mDbHelper.extractAddressFromEmailAddress(filter); 5805174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isEmailAddress = !TextUtils.isEmpty(emailAddress); 5806174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 5807174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isPhoneNumber = isPhoneNumber(filter); 580804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (isPhoneNumber) { 580904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann phoneNumber = PhoneNumberUtils.normalizeNumber(filter); 581004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann numberE164 = PhoneNumberUtils.formatNumberToE164(phoneNumber, 581104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann mDbHelper.getCountryIso()); 581204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 5813174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5814174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 5815174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(" JOIN (SELECT " + SearchIndexColumns.CONTACT_ID + " AS snippet_contact_id"); 5816174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (snippetNeeded) { 58175e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(", "); 58185e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 58193d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 58205e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 582104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Email.ADDRESS + ")"); 582204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + Tables.DATA_JOIN_RAW_CONTACTS); 582304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 582404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID + " AND " + Email.ADDRESS + " LIKE "); 582504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann DatabaseUtils.appendEscapedSQLString(sb, filter + "%"); 582604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 58273d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 58283d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(","); 58293716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 58303716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 58313716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 58323716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 58333716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 58343716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 58353716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 58363d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(")"); 58373d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 58383d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 58393d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 584004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Phone.NUMBER + ")"); 584104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + 584204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann Tables.DATA_JOIN_RAW_CONTACTS + " JOIN " + Tables.PHONE_LOOKUP); 584304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" ON " + DataColumns.CONCRETE_ID); 584404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID); 584504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 584604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID); 584704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" AND " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 584804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(phoneNumber); 584904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 585004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(numberE164)) { 585104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" OR " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 585204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(numberE164); 585304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 585404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 585504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 58565e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 58575e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 58583716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 58593716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 58603716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 58613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 58623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 58633716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 58643716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 58655e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 586603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 586704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann final String normalizedFilter = NameNormalizer.normalize(filter); 586804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(normalizedFilter)) { 58693716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 58703716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 58713716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 58723716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 58733716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("(CASE WHEN EXISTS (SELECT 1 FROM "); 58743716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.RAW_CONTACTS + " AS rc INNER JOIN "); 58753716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.NAME_LOOKUP + " AS nl ON (rc." + RawContacts._ID); 58763716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=nl." + NameLookupColumns.RAW_CONTACT_ID); 58773716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") WHERE nl." + NameLookupColumns.NORMALIZED_NAME); 58783716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" GLOB '" + normalizedFilter + "*' AND "); 58793716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("nl." + NameLookupColumns.NAME_TYPE + "="); 58803716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(NameLookupType.NAME_COLLATION_KEY + " AND "); 58813716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 58823716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=rc." + RawContacts.CONTACT_ID); 58833716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") THEN NULL ELSE "); 58843716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 58853716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" END)"); 58863716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 588704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } else { 588804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("NULL"); 588904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 589003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 58915e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" AS " + SearchSnippetColumns.SNIPPET); 58925e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 589303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 58945e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" FROM " + Tables.SEARCH_INDEX); 58955e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" WHERE "); 58965e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(Tables.SEARCH_INDEX + " MATCH "); 58975e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 58982352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, "\"" + sanitizeMatch(filter) + "*\""); 58993d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 59002352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, 590104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann "\"" + sanitizeMatch(filter) + "*\" OR \"" + phoneNumber + "*\"" 59022352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov + (numberE164 != null ? " OR \"" + numberE164 + "\"" : "")); 590303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 59042352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filter) + "*"); 59059c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov } 590603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov sb.append(") ON (" + Contacts._ID + "=snippet_contact_id)"); 5907a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov } 5908a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov 59092352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov private String sanitizeMatch(String filter) { 59102352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov // TODO more robust preprocessing of match expressions 59112352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov return filter.replace('-', ' ').replace('\"', ' '); 59122352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov } 59132352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov 59145e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov private void appendSnippetFunction( 59155e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov StringBuilder sb, String startMatch, String endMatch, String ellipsis, int maxTokens) { 59165e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append("snippet(" + Tables.SEARCH_INDEX + ","); 59175e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 59185e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 59195e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 59205e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 59215e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, ellipsis); 59225e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 59235e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov // The index of the column used for the snippet, "content" 59245e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(",1,"); 59255e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(maxTokens); 59265e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 59275e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 59285e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 5929763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) { 5930763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar StringBuilder sb = new StringBuilder(); 5931ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.RAW_CONTACTS); 5932763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setTables(sb.toString()); 5933763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setProjectionMap(sRawContactsProjectionMap); 5934763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar appendAccountFromParameter(qb, uri); 5935763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar } 5936763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar 5937a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForRawEntities(SQLiteQueryBuilder qb, Uri uri) { 5938ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.RAW_ENTITIES); 5939a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sRawEntityProjectionMap); 594046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana appendAccountFromParameter(qb, uri); 594146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 594246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 594382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 594482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String[] projection, boolean distinct) { 594546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, distinct, null); 594646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 594746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 594846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 594946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @param usageType when non-null {@link Tables#DATA_USAGE_STAT} is joined with the specified 595046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type. 595146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 595246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 595346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String[] projection, boolean distinct, Integer usageType) { 595482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 5955ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 595682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov sb.append(" data"); 595782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov 5958a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID); 5959a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 5960a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 5961a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 59623296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey 596346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (usageType != null) { 596446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa appendDataUsageStatJoin(sb, usageType, DataColumns.CONCRETE_ID); 596546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 596646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 596782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov qb.setTables(sb.toString()); 5968f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov 5969f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov boolean useDistinct = distinct 5970f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov || !mDbHelper.isInProjection(projection, DISTINCT_DATA_PROHIBITING_COLUMNS); 5971f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setDistinct(useDistinct); 5972f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setProjectionMap(useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap); 597382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov appendAccountFromParameter(qb, uri); 5974ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov } 5975ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov 59760a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb, 59770a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String[] projection) { 59780a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StringBuilder sb = new StringBuilder(); 5979ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 59800a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" data"); 5981a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 5982a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 59830a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 5984a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 5985a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sStatusUpdatesProjectionMap); 5986a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5987a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 59883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItems(SQLiteQueryBuilder qb) { 59891dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.STREAM_ITEMS 59901dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.RAW_CONTACTS + " ON (" 59911dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemsColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 59921dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.CONTACTS + " ON (" 59931dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + RawContactsColumns.CONCRETE_CONTACT_ID + "=" + ContactsColumns.CONCRETE_ID + ")"); 59943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemsProjectionMap); 59953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 59963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 59973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItemPhotos(SQLiteQueryBuilder qb) { 59981dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.PHOTO_FILES 59991dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.STREAM_ITEM_PHOTOS + " ON (" 60001dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_PHOTO_FILE_ID + "=" 60011dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + PhotoFilesColumns.CONCRETE_ID 60021dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.STREAM_ITEMS + " ON (" 60031dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=" 60041dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemsColumns.CONCRETE_ID + ")"); 60053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemPhotosProjectionMap); 60063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 60073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 6008a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForEntities(SQLiteQueryBuilder qb, Uri uri, 6009a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection) { 6010a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6011ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.ENTITIES); 6012a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" data"); 6013a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6014a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts.Entity.CONTACT_ID); 6015a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6016a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, Contacts.Entity.DATA_ID); 6017a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, Contacts.Entity.DATA_ID); 6018a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6019a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6020a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sEntityProjectionMap); 6021a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendAccountFromParameter(qb, uri); 6022a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6023a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6024a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactStatusUpdateJoin(StringBuilder sb, String[] projection, 6025a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lastStatusUpdateIdColumn) { 6026a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, 6027a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS, 6028a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_RES_PACKAGE, 6029a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_ICON, 6030a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_LABEL, 6031a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_TIMESTAMP)) { 6032a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " " 6033a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.ALIAS + 6034a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + lastStatusUpdateIdColumn + "=" 6035a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")"); 60360a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6037a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 60380a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6039a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataStatusUpdateJoin(StringBuilder sb, String[] projection, 6040a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 6041b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov if (mDbHelper.isInProjection(projection, 60420a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS, 60430a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_RES_PACKAGE, 60440a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_ICON, 60450a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_LABEL, 60460a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_TIMESTAMP)) { 60470a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + 6048a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "=" 6049a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + dataIdColumn + ")"); 60500a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6051a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6052a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 605346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void appendDataUsageStatJoin(StringBuilder sb, int usageType, String dataIdColumn) { 605446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" LEFT OUTER JOIN " + Tables.DATA_USAGE_STAT + 605546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" + dataIdColumn + 605646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " AND " + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" + usageType + ")"); 605746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 605846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 6059a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactPresenceJoin(StringBuilder sb, String[] projection, 6060a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn) { 6061a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, 6062a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_PRESENCE, Contacts.CONTACT_CHAT_CAPABILITY)) { 6063a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + 6064a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + contactIdColumn + " = " 6065a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + ")"); 6066a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6067a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6068a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6069a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataPresenceJoin(StringBuilder sb, String[] projection, 6070a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 6071a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, Data.PRESENCE, Data.CHAT_CAPABILITY)) { 6072a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE + 6073a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdates.DATA_ID + "=" + dataIdColumn + ")"); 6074a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6075a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6076a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 607724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private boolean appendLocalDirectorySelectionIfNeeded(SQLiteQueryBuilder qb, long directoryId) { 6078385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directoryId == Directory.DEFAULT) { 6079385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY); 608024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 6081385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directoryId == Directory.LOCAL_INVISIBLE){ 6082385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " NOT IN " + Tables.DEFAULT_DIRECTORY); 608324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 608424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 608524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return false; 608624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 608724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 608824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void appendProfileRestriction(SQLiteQueryBuilder qb, Uri uri, String profileColumn, 60896ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean andRequired, boolean suppressProfileCheck) { 60906ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (!shouldIncludeProfile(uri, suppressProfileCheck)) { 609124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere((andRequired ? " AND (" : "") 609224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + profileColumn + " IS NULL OR " 609324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + profileColumn + "=0" 609424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + (andRequired ? ")" : "")); 6095385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } 6096385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } 6097385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov 60986ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private String prependProfileSortIfNeeded(Uri uri, String sortOrder, 60996ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean suppressProfileCheck) { 61006ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (shouldIncludeProfile(uri, suppressProfileCheck)) { 610124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (TextUtils.isEmpty(sortOrder)) { 610224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return Contacts.IS_USER_PROFILE + " DESC"; 610324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else { 610424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return Contacts.IS_USER_PROFILE + " DESC, " + sortOrder; 610524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 610624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 610724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return sortOrder; 610824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 610924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 61106ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private boolean shouldIncludeProfile(Uri uri, boolean suppressProfileCheck) { 611124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The user's profile may be returned alongside other contacts if it was requested and 611224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // the calling application has permission to read profile data. 6113377850d2dfd28eaf1b22273a50cfe066f6667ab9Dave Santoro boolean profileRequested = readBooleanQueryParameter(uri, ContactsContract.ALLOW_PROFILE, 611424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro false); 61156ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (profileRequested && !suppressProfileCheck) { 611624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 611724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 611824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return profileRequested; 611924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 612024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 61214a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) { 6122f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6123f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 6124e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6125e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6126e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6127e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 6128fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6129fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6130e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6131e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6132e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6133e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6134e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6135e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 61364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere(RawContacts.ACCOUNT_NAME + "=" 61374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + DatabaseUtils.sqlEscapeString(accountName) + " AND " 61384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + RawContacts.ACCOUNT_TYPE + "=" 61394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + DatabaseUtils.sqlEscapeString(accountType)); 61404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } else { 61414a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere("1"); 61424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 61434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 61444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 6145e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong private String appendAccountToSelection(Uri uri, String selection) { 6146f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6147f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 6148e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6149e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6150e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6151e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 6152fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6153fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6154e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6155e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6156e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6157e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6158e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6159e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 6160e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "=" 6161e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountName) + " AND " 6162e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + RawContacts.ACCOUNT_TYPE + "=" 6163e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountType)); 6164e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong if (!TextUtils.isEmpty(selection)) { 6165e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(" AND ("); 6166e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(selection); 6167e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(')'); 6168e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6169e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selectionSb.toString(); 6170e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } else { 6171e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selection; 6172e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6173e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6174e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong 61757e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 6176c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * Gets the value of the "limit" URI query parameter. 6177c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * 6178c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * @return A string containing a non-negative integer, or <code>null</code> if 6179c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * the parameter is not set, or is set to an invalid value. 6180c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov */ 6181f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private String getLimit(Uri uri) { 61822e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limitParam = getQueryParameter(uri, ContactsContract.LIMIT_PARAM_KEY); 6183c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (limitParam == null) { 6184c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6185c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6186c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov // make sure that the limit is a non-negative integer 6187c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov try { 6188c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov int l = Integer.parseInt(limitParam); 6189c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (l < 0) { 6190c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6191c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6192c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6193c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return String.valueOf(l); 6194c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } catch (NumberFormatException ex) { 6195c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6196c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6197c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6198c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6199c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 6200b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov @Override 6201f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 6202415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6203f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mode.equals("r")) { 6204f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mReadAccessLatch); 6205f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6206f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mWriteAccessLatch); 6207f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6208415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6209b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov int match = sUriMatcher.match(uri); 6210b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov switch (match) { 6211a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 6212afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 621324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6214afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 6215afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro return openPhotoAssetFile(db, uri, mode, 621624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Data._ID + "=" + Contacts.PHOTO_ID + " AND " + 621724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContacts.CONTACT_ID + "=?", 621824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(rawContactId)}); 6219e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6220b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6221f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: { 6222f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6223f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6224f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact ID can only be read."); 6225f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6226afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6227f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 6228afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6229afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = db.query(Tables.CONTACTS, 6230f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{Contacts.PHOTO_FILE_ID}, 6231f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID + "=?", new String[]{String.valueOf(contactId)}, 6232f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, null); 6233f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6234f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6235f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(0); 6236f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6237f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6238f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6239f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6240f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6241f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6242f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6243f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: { 6244f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6245f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6246f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact lookup key can only be read."); 6247f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6248f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro List<String> pathSegments = uri.getPathSegments(); 6249f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int segmentCount = pathSegments.size(); 6250f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount < 4) { 6251f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6252f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Missing a lookup key", uri)); 6253f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6254afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6255f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String lookupKey = pathSegments.get(2); 6256f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Contacts.PHOTO_FILE_ID}; 6257f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount == 5) { 6258f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(pathSegments.get(3)); 6259afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6260f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 6261f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 6262afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 6263f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro projection, null, null, null, null, null, 6264f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 6265f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c != null) { 6266f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6267f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6268f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6269f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6270f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6273f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6274f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6275f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6276f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6277f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 6278afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 6279afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6280afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = qb.query(db, projection, Contacts._ID + "=?", 6281f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(contactId)}, null, null, null); 6282f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6283f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6284f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6285f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6286f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6287f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6288f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6289f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6290f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6291f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: { 6292f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6293f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean writeable = !mode.equals("r"); 6294afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6295afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, writeable); 6296f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6297f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Find the primary photo data record for this raw contact. 6298f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6299f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Data._ID, Photo.PHOTO_FILE_ID}; 6300f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 6301afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = qb.query(db, projection, 6302f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?", 6303f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(rawContactId), Photo.CONTENT_ITEM_TYPE}, 6304f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, Data.IS_PRIMARY + " DESC"); 6305f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long dataId = 0; 6306f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = 0; 6307f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6308f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c.getCount() >= 1) { 6309f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6310f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro dataId = c.getLong(0); 6311f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro photoFileId = c.getLong(1); 6312f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6313f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6314f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6315f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6316f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6317f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If writeable, open a writeable file descriptor that we can monitor. 6318f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // When the caller finishes writing content, we'll process the photo and 6319f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // update the data record. 6320f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (writeable) { 6321f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForWrite(rawContactId, dataId, uri, mode); 6322f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6323f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6324f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6325f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6326f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6327f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: { 6328f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = ContentUris.parseId(uri); 6329f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6330f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6331f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by key can only be read."); 6332f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6333f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6334f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6335f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6336e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov case DATA_ID: { 6337afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 633824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = Long.parseLong(uri.getPathSegments().get(1)); 6339afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForData(db, dataId, false); 6340afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro return openPhotoAssetFile(db, uri, mode, 6341e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov Data._ID + "=? AND " + Data.MIMETYPE + "='" + Photo.CONTENT_ITEM_TYPE + "'", 634224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(dataId)}); 6343d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6344d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6345fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case PROFILE_AS_VCARD: { 6346fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // When opening a contact as file, we pass back contents as a 6347fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // vCard-encoded stream. We build into a local buffer first, 6348fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // then pipe into MemoryFile once the exact size is known. 6349fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6350fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6351fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen return buildAssetFileDescriptor(localStream); 6352fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 635342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 6354fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case CONTACTS_AS_VCARD: { 635542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // When opening a contact as file, we pass back contents as a 635642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // vCard-encoded stream. We build into a local buffer first, 635742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // then pipe into MemoryFile once the exact size is known. 635842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6359fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6360f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 636142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 636242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 636342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 636449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov SQLiteDatabase db = mDbHelper.getReadableDatabase(); 636542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKeys = uri.getPathSegments().get(2); 636642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String[] loopupKeyList = lookupKeys.split(":"); 636742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final StringBuilder inBuilder = new StringBuilder(); 6368fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Uri queryUri = Contacts.CONTENT_URI; 636942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann int index = 0; 6370fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen 6371d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // SQLite has limits on how many parameters can be used 6372d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // so the IDs are concatenated to a query string here instead 637342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann for (String lookupKey : loopupKeyList) { 637442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann if (index == 0) { 6375d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append("("); 637642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } else { 6377d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append(","); 637842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 637924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 6380afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 638124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro inBuilder.append(contactId); 6382fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (mProfileIdCache.profileContactId == contactId) { 6383fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen queryUri = queryUri.buildUpon().appendQueryParameter( 6384377850d2dfd28eaf1b22273a50cfe066f6667ab9Dave Santoro ContactsContract.ALLOW_PROFILE, "true").build(); 6385fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 638642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann index++; 638742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 638842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann inBuilder.append(')'); 638942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String selection = Contacts._ID + " IN " + inBuilder.toString(); 6390d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6391d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // When opening a contact as file, we pass back contents as a 6392d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // vCard-encoded stream. We build into a local buffer first, 6393d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // then pipe into MemoryFile once the exact size is known. 6394d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6395fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(queryUri, localStream, selection, null); 6396f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 6397d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6398b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6399b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov default: 6400fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new FileNotFoundException(mDbHelper.exceptionMessage("File does not exist", 6401fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov uri)); 6402b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6403b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6404b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6405afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private AssetFileDescriptor openPhotoAssetFile(SQLiteDatabase db, Uri uri, String mode, 6406afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro String selection, String[] selectionArgs) 6407e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throws FileNotFoundException { 6408e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov if (!"r".equals(mode)) { 6409e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throw new FileNotFoundException(mDbHelper.exceptionMessage("Mode " + mode 6410e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov + " not supported.", uri)); 6411e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6412e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6413e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov String sql = 6414ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann "SELECT " + Photo.PHOTO + " FROM " + Views.DATA + 6415e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov " WHERE " + selection; 641608ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood try { 6417f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6418f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert DatabaseUtils.blobFileDescriptorForQuery(db, sql, selectionArgs)); 641908ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } catch (SQLiteDoneException e) { 642008ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood // this will happen if the DB query returns no rows (i.e. contact does not exist) 642108ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood throw new FileNotFoundException(uri.toString()); 642208ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } 6423e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6424e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6425f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6426f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a display photo from the photo store for reading. 6427f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoFileId The display photo file ID 6428f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor that allows the file to be read. 6429f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @throws FileNotFoundException If no photo file for the given ID exists. 6430f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6431f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForRead(long photoFileId) 6432f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throws FileNotFoundException { 6433f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoStore.Entry entry = mPhotoStore.get(photoFileId); 6434f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 6435f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return makeAssetFileDescriptor( 6436f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(new File(entry.path), 6437f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.MODE_READ_ONLY), 6438f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro entry.size); 6439f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6440f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 6441f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new FileNotFoundException("No photo file found for ID " + photoFileId); 6442f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6443f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6444f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6445f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6446f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a file descriptor for a photo to be written. When the caller completes writing 6447f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to the file (closing the output stream), the image will be parsed out and processed. 6448f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If processing succeeds, the given raw contact ID's primary photo record will be 6449f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * populated with the inserted image (if no primary photo record exists, the data ID can 6450f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * be left as 0, and a new data record will be inserted). 6451f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rawContactId Raw contact ID this photo entry should be associated with. 6452f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param dataId Data ID for a photo mimetype that will be updated with the inserted 6453f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * image. May be set to 0, in which case the inserted image will trigger creation 6454f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * of a new primary photo image data row for the raw contact. 6455f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param uri The URI being used to access this file. 6456f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param mode Read/write mode string. 6457f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor the caller can use to write an image file for the 6458f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact. 6459f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6460f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForWrite(long rawContactId, long dataId, Uri uri, 6461f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String mode) { 6462f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6463f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return new AssetFileDescriptor(new MonitoredParcelFileDescriptor(rawContactId, dataId, 6464f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(File.createTempFile("img", null), 6465f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentResolver.modeToMode(uri, mode))), 6466f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 0, AssetFileDescriptor.UNKNOWN_LENGTH); 6467f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException ioe) { 6468f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Could not create temp image file in mode " + mode); 6469f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return null; 6470f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6471f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6472f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6473f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6474f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Parcel file descriptor wrapper that monitors when the file is closed. 6475f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If the file contains a valid image, the image is either inserted into the given 6476f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact or updated in the given data row. 6477f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6478f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private class MonitoredParcelFileDescriptor extends ParcelFileDescriptor { 6479f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mRawContactId; 6480f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mDataId; 6481f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private MonitoredParcelFileDescriptor(long rawContactId, long dataId, 6482f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor descriptor) { 6483f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro super(descriptor); 6484f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mRawContactId = rawContactId; 6485f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDataId = dataId; 6486f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6487f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6488f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro @Override 6489f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public void close() throws IOException { 6490f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6491f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check to see whether a valid image was written out. 6492f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Bitmap b = BitmapFactory.decodeFileDescriptor(getFileDescriptor()); 6493f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (b != null) { 6494f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoProcessor processor = new PhotoProcessor(b, mMaxDisplayPhotoDim, 6495f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim); 6496f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6497f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Store the compressed photo in the photo store. 6498f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = mPhotoStore.insert(processor); 6499f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6500f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Depending on whether we already had a data row to attach the photo to, 6501f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // do an update or insert. 6502f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mDataId != 0) { 6503f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Update the data record with the new photo. 6504f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 6505f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6506f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6507f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6508f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6509f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6510f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6511f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6512f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6513f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro update(ContentUris.withAppendedId(Data.CONTENT_URI, mDataId), updateValues, 6514f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null); 6515f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6516f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Insert a new primary data record with the photo. 6517f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues insertValues = new ContentValues(); 6518f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6519f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6520f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6521f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6522f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 6523f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.IS_PRIMARY, 1); 6524f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6525f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6526f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6527f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6528f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insert(RawContacts.CONTENT_URI.buildUpon() 6529f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(String.valueOf(mRawContactId)) 6530f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(RawContacts.Data.CONTENT_DIRECTORY).build(), 6531f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues); 6532f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6533f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6534f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6535f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro super.close(); 6536f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6537f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6538f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6539f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6540d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile"; 6541d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6542d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6543f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert * Returns an {@link AssetFileDescriptor} backed by the 6544d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * contents of the given {@link ByteArrayOutputStream}. 6545d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6546f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) { 6547d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey try { 6548d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey stream.flush(); 6549d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6550d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final byte[] byteData = stream.toByteArray(); 6551d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6552f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6553f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert ParcelFileDescriptor.fromData(byteData, CONTACT_MEMORY_FILE_NAME), 6554f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert byteData.length); 6555d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } catch (IOException e) { 6556ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert Log.w(TAG, "Problem writing stream into an ParcelFileDescriptor: " + e.toString()); 6557ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert return null; 6558d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6559d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6560d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6561f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd) { 6562f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor(fd, AssetFileDescriptor.UNKNOWN_LENGTH); 6563f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6564f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6565f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd, long length) { 6566f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return fd != null ? new AssetFileDescriptor(fd, 0, length) : null; 6567f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6568f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6569d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6570d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * Output {@link RawContacts} matching the requested selection in the vCard 6571d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * format to the given {@link OutputStream}. This method returns silently if 6572d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * any errors encountered. 6573d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6574fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen private void outputRawContactsAsVCard(Uri uri, OutputStream stream, 6575fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen String selection, String[] selectionArgs) { 6576d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final Context context = this.getContext(); 6577dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen int vcardconfig = VCardConfig.VCARD_TYPE_DEFAULT; 6578fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if(uri.getBooleanQueryParameter( 6579fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, false)) { 6580dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen vcardconfig |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT; 6581dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen } 65827a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa final VCardComposer composer = 6583dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen new VCardComposer(context, vcardconfig, false); 6584108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Writer writer = null; 6585108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6586108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer = new BufferedWriter(new OutputStreamWriter(stream)); 6587fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (!composer.init(uri, selection, selectionArgs, null)) { 6588108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "Failed to init VCardComposer"); 6589108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa return; 6590108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6591d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6592108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa while (!composer.isAfterLast()) { 6593108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.write(composer.createOneEntry()); 6594108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6595108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6596108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.e(TAG, "IOException: " + e); 6597108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } finally { 6598108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa composer.terminate(); 6599108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa if (writer != null) { 6600108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6601108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.close(); 6602108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6603108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "IOException during closing output stream: " + e); 6604108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6605d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6606d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6607d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6608b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 66094f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 66104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 6611415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6612415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov waitForAccess(mReadAccessLatch); 6613415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6614a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 66154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 6616b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS: 6617be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return Contacts.CONTENT_TYPE; 66182d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill case CONTACTS_LOOKUP: 6619b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_ID: 6620b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_LOOKUP_ID: 662124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 6622b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_ITEM_TYPE; 6623f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: 662442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: 662524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 6626f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey return Contacts.CONTENT_VCARD_TYPE; 6627f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov case CONTACTS_ID_PHOTO: 6628f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: 6629f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6630f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: 6631f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: 6632f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: 6633f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return "image/jpeg"; 6634b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS: 663524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 6636be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return RawContacts.CONTENT_TYPE; 6637b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS_ID: 663824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 6639b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return RawContacts.CONTENT_ITEM_TYPE; 6640f481f22a9323fe338672f99b88b26c5f0725cd42David Brown case DATA: 664124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 6642f481f22a9323fe338672f99b88b26c5f0725cd42David Brown return Data.CONTENT_TYPE; 6643508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 6644b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getDataMimeType(ContentUris.parseId(uri)); 664548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES: 664648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_TYPE; 664748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 664848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_ITEM_TYPE; 66499005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov case PHONE_LOOKUP: 66509005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov return PhoneLookup.CONTENT_TYPE; 665148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS: 665248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_TYPE; 665348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 665448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_ITEM_TYPE; 665548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS: 665648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_TYPE; 665748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: 665848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_ITEM_TYPE; 6659b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 6660b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_TYPE; 6661b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 6662b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_ITEM_TYPE; 6663b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case SETTINGS: 6664b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Settings.CONTENT_TYPE; 6665b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 6666b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_TYPE; 6667c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: 6668c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SUGGEST_MIME_TYPE; 6669c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: 6670c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SHORTCUT_MIME_TYPE; 6671d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES: 6672d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_TYPE; 6673d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID: 6674d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_ITEM_TYPE; 667561efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov default: 667661efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov return mLegacyApiSupport.getType(uri); 66774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 66784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 66797e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 668009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov public String[] getDefaultProjection(Uri uri) { 668109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov final int match = sUriMatcher.match(uri); 668209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov switch (match) { 668309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS: 668409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP: 668509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_ID: 668609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP_ID: 668709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 668824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 668909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsProjectionMap.getColumnNames(); 669009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 66918727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov case CONTACTS_ID_ENTITIES: 669224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: 66938727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov return sEntityProjectionMap.getColumnNames(); 66948727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov 669509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_VCARD: 669609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_MULTI_VCARD: 669724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 669809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsVCardProjectionMap.getColumnNames(); 669909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 670009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS: 670109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS_ID: 670224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 670324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 670409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sRawContactsProjectionMap.getColumnNames(); 670509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 670609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DATA_ID: 670709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES: 670809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES_ID: 670909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS: 671009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS_ID: 671109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS: 671209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS_ID: 671324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 671409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDataProjectionMap.getColumnNames(); 671509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 671609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONE_LOOKUP: 671709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sPhoneLookupProjectionMap.getColumnNames(); 671809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 671909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 672009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 672109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sAggregationExceptionsProjectionMap.getColumnNames(); 672209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 672309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case SETTINGS: 672409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sSettingsProjectionMap.getColumnNames(); 672509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 672609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES: 672709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES_ID: 672809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDirectoryProjectionMap.getColumnNames(); 672909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 673009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov default: 673109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return null; 673209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 673309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 673409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 6735f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private class StructuredNameLookupBuilder extends NameLookupBuilder { 6736f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6737f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov public StructuredNameLookupBuilder(NameSplitter splitter) { 6738f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov super(splitter); 6739f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6740f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6741f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 6742f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected void insertNameLookup(long rawContactId, long dataId, int lookupType, 6743f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov String name) { 674478fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.insertNameLookup(rawContactId, dataId, lookupType, name); 6745f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6746f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6747f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 6748f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected String[] getCommonNicknameClusters(String normalizedName) { 6749d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); 6750f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6751f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6752f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 67532d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) { 6754d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov sb.append("(" + 6755d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov "SELECT DISTINCT " + RawContacts.CONTACT_ID + 6756d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 6757d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " JOIN " + Tables.NAME_LOOKUP + 6758d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " ON(" + RawContactsColumns.CONCRETE_ID + "=" 6759d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov + NameLookupColumns.RAW_CONTACT_ID + ")" + 6760d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " WHERE normalized_name GLOB '"); 6761e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(NameNormalizer.normalize(filterParam)); 6762916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov sb.append("*' AND " + NameLookupColumns.NAME_TYPE + 6763916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov " IN(" + CONTACT_LOOKUP_NAME_TYPES + "))"); 6764e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 6765e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 67669a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov public boolean isPhoneNumber(String filter) { 67679a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean atLeastOneDigit = false; 67689a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov int len = filter.length(); 67699a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov for (int i = 0; i < len; i++) { 67709a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov char c = filter.charAt(i); 67719a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (c >= '0' && c <= '9') { 67729a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov atLeastOneDigit = true; 67739a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } else if (c != '*' && c != '#' && c != '+' && c != 'N' && c != '.' && c != ';' 67749a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov && c != '-' && c != '(' && c != ')' && c != ' ') { 67759a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return false; 67769a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 67779a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 67789a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return atLeastOneDigit; 67799a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 67809a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 67814a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** 67827a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * Takes components of a name from the query parameters and returns a cursor with those 67837a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * components as well as all missing components. There is no database activity involved 67847a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * in this so the call can be made on the UI thread. 67857a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov */ 67867a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private Cursor completeName(Uri uri, String[] projection) { 67877a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (projection == null) { 67887a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov projection = sDataProjectionMap.getColumnNames(); 67897a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 67907a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 67917a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ContentValues values = new ContentValues(); 6792f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataRowHandlerForStructuredName handler = (DataRowHandlerForStructuredName) 6793f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov getDataRowHandler(StructuredName.CONTENT_ITEM_TYPE); 67947a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 67957a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov copyQueryParamsToContentValues(values, uri, 67967a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.DISPLAY_NAME, 67977a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PREFIX, 67987a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.GIVEN_NAME, 67997a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.MIDDLE_NAME, 68007a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.FAMILY_NAME, 68017a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.SUFFIX, 68027a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_NAME, 68037a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_FAMILY_NAME, 68047a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_MIDDLE_NAME, 68057a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_GIVEN_NAME 68067a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ); 68077a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68087a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov handler.fixStructuredNameComponents(values, values); 68097a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68107a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 68117a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov Object[] row = new Object[projection.length]; 68127a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 68137a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov row[i] = values.get(projection[i]); 68147a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68157a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov cursor.addRow(row); 68167a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return cursor; 68177a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68187a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68197a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private void copyQueryParamsToContentValues(ContentValues values, Uri uri, String... columns) { 68207a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (String column : columns) { 68217a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov String param = uri.getQueryParameter(column); 68227a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (param != null) { 68237a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov values.put(column, param); 68247a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68257a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68267a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68277a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68287a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68297a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov /** 68304a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov * Inserts an argument at the beginning of the selection arg list. 68314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov */ 68324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private String[] insertSelectionArg(String[] selectionArgs, String arg) { 6833b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 6834b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 6835b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 6836b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 6837b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 68384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov newSelectionArgs[0] = arg; 68394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length); 6840b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 6841b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 6842b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 6843caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 68445e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar private String[] appendProjectionArg(String[] projection, String arg) { 68455e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection == null) { 68465e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return null; 68475e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 68485e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar final int length = projection.length; 68495e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar String[] newProjection = new String[length + 1]; 68505e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar System.arraycopy(projection, 0, newProjection, 0, length); 68515e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar newProjection[length] = arg; 68525e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return newProjection; 68535e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 68545e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 6855caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov protected Account getDefaultAccount() { 6856caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov AccountManager accountManager = AccountManager.get(getContext()); 6857caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov try { 68585f1f4a062ac34d75d2dbf586702cbeb121cf09caDmitri Plotnikov Account[] accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE); 6859caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov if (accounts != null && accounts.length > 0) { 6860caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov return accounts[0]; 6861caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 6862caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } catch (Throwable e) { 68636f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov Log.e(TAG, "Cannot determine the default account for contacts compatibility", e); 6864caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 68656f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov return null; 6866caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 6867f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 686873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov /** 686973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov * Returns true if the specified account type is writable. 687073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov */ 687173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov protected boolean isWritableAccount(String accountType) { 6872bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov if (accountType == null) { 6873bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov return true; 6874bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov } 6875bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov 687673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov Boolean writable = mAccountWritability.get(accountType); 687773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable != null) { 687873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 687973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 688073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 6881627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov IContentService contentService = ContentResolver.getContentService(); 6882627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 6883627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) { 6884627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov if (ContactsContract.AUTHORITY.equals(sync.authority) && 688573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov accountType.equals(sync.accountType)) { 688673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = sync.supportsUploading(); 688773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov break; 6888627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 6889627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 6890627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } catch (RemoteException e) { 6891627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov Log.e(TAG, "Could not acquire sync adapter types"); 6892627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 689373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 689473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable == null) { 689573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = false; 689673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 689773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 689873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.put(accountType, writable); 689973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 6900627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 6901b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov 6902d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 6903f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter, 6904f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean defaultValue) { 6905f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6906f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov // Manually parse the query, which is much faster than calling uri.getQueryParameter 6907f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 6908f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 6909f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 6910f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6911f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6912f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = query.indexOf(parameter); 6913f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 6914f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 6915f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6916f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6917f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameter.length(); 6918f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6919f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return !matchQueryParameter(query, index, "=0", false) 6920f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && !matchQueryParameter(query, index, "=false", true); 6921f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6922f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6923f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private static boolean matchQueryParameter(String query, int index, String value, 6924f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean ignoreCase) { 6925f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int length = value.length(); 6926f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return query.regionMatches(ignoreCase, index, value, 0, length) 6927f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && (query.length() == index + length || query.charAt(index + length) == '&'); 6928f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6929f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6930f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /** 6931f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * A fast re-implementation of {@link Uri#getQueryParameter} 6932f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov */ 6933f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static String getQueryParameter(Uri uri, String parameter) { 6934f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 6935f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 6936f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 6937f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6938f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6939f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int queryLength = query.length(); 6940f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int parameterLength = parameter.length(); 6941f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6942f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String value; 6943f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = 0; 6944f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov while (true) { 6945f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index = query.indexOf(parameter, index); 6946f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 6947f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 69485fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 69495fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa 69505fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // Should match against the whole parameter instead of its suffix. 69515fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // e.g. The parameter "param" must not be found in "some_param=val". 69525fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (index > 0) { 69535fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa char prevChar = query.charAt(index - 1); 69545fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (prevChar != '?' && prevChar != '&') { 69555fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // With "some_param=val1¶m=val2", we should find second "param" occurrence. 69565fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa index += parameterLength; 69575fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa continue; 69585fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 6959f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6960f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6961f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameterLength; 6962f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6963f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (queryLength == index) { 6964f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 6965f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6966f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6967f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query.charAt(index) == '=') { 6968f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index++; 6969f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov break; 6970f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6971f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6972f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6973f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int ampIndex = query.indexOf('&', index); 6974f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (ampIndex == -1) { 6975f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index); 6976f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } else { 6977f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index, ampIndex); 6978f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6979f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6980f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return Uri.decode(value); 6981f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 69825dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 69830dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov protected boolean isAggregationUpgradeNeeded() { 69840dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov if (!mContactAggregator.isEnabled()) { 69850dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return false; 69860dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 69870dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 69880dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_AGGREGATION_ALGORITHM, "1")); 69890dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return version < PROPERTY_AGGREGATION_ALGORITHM_VERSION; 69900dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 69910dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 6992bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void upgradeAggregationAlgorithmInBackground() { 69930dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // This upgrade will affect very few contacts, so it can be performed on the 69940dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // main thread during the initial boot after an OTA 69950dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 69960dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Upgrading aggregation algorithm"); 69970dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int count = 0; 69980dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long start = SystemClock.currentThreadTimeMillis(); 69990dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 700049d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov mDb = mDbHelper.getWritableDatabase(); 70010dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.beginTransaction(); 70020dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Cursor cursor = mDb.query(true, 70030dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Tables.RAW_CONTACTS + " r1 JOIN " + Tables.RAW_CONTACTS + " r2", 70040dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov new String[]{"r1." + RawContacts._ID}, 70050dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov "r1." + RawContacts._ID + "!=r2." + RawContacts._ID + 70060dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.CONTACT_ID + "=r2." + RawContacts.CONTACT_ID + 70070dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.ACCOUNT_NAME + "=r2." + RawContacts.ACCOUNT_NAME + 70080dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.ACCOUNT_TYPE + "=r2." + RawContacts.ACCOUNT_TYPE, 70090dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov null, null, null, null, null); 70100dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 70110dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov while (cursor.moveToNext()) { 70120dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long rawContactId = cursor.getLong(0); 70130dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, 70140dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 70150dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov count++; 70160dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 70170dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 70180dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov cursor.close(); 70190dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 7020bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateInTransaction(mTransactionContext, mDb); 7021bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 70220dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.setTransactionSuccessful(); 70230dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDbHelper.setProperty(PROPERTY_AGGREGATION_ALGORITHM, 70240dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov String.valueOf(PROPERTY_AGGREGATION_ALGORITHM_VERSION)); 70250dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 70260dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.endTransaction(); 70270dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long end = SystemClock.currentThreadTimeMillis(); 70280dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Aggregation algorithm upgraded for " + count 70290dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov + " contacts, in " + (end - start) + "ms"); 70300dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 70310dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 70329a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 70339a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov /* Visible for testing */ 70349a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean isPhone() { 70359a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (!sIsPhoneInitialized) { 70369a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhone = new TelephonyManager(getContext()).isVoiceCapable(); 70379a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhoneInitialized = true; 70389a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 70399a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return sIsPhone; 70409a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 704146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 704246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private boolean handleDataUsageFeedback(Uri uri) { 704346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final long currentTimeMillis = System.currentTimeMillis(); 704446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 704546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] ids = uri.getLastPathSegment().trim().split(","); 704646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ArrayList<Long> dataIds = new ArrayList<Long>(); 704746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 704846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (String id : ids) { 704946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa dataIds.add(Long.valueOf(id)); 705046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 705146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final boolean successful; 705246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (TextUtils.isEmpty(usageType)) { 705346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.w(TAG, "Method for data usage feedback isn't specified. Ignoring."); 705446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = false; 705546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 705646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = updateDataUsageStat(dataIds, usageType, currentTimeMillis) > 0; 705746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 705846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 705946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Handle old API. This doesn't affect the result of this entire method. 706046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] questionMarks = new String[ids.length]; 706146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Arrays.fill(questionMarks, "?"); 706246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = Data._ID + " IN (" + TextUtils.join(",", questionMarks) + ")"; 706346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final Cursor cursor = mDb.query( 7064ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA, 706546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { Data.CONTACT_ID }, 706646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa where, ids, null, null, null); 706746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 706846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa while (cursor.moveToNext()) { 706946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mSelectionArgs1[0] = cursor.getString(0); 707046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa ContentValues values2 = new ContentValues(); 707146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values2.put(Contacts.LAST_TIME_CONTACTED, currentTimeMillis); 707246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.update(Tables.CONTACTS, values2, Contacts._ID + "=?", mSelectionArgs1); 707346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 707446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 707546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 707646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 707746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 707846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 707946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 708046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return successful; 708146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 708246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 708346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 708446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Update {@link Tables#DATA_USAGE_STAT}. 708546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * 708646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @return the number of rows affected. 708746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 7088f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa @VisibleForTesting 7089f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa /* package */ int updateDataUsageStat( 7090f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa List<Long> dataIds, String type, long currentTimeMillis) { 709146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final int typeInt = sDataUsageTypeMap.get(type); 709246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = DataUsageStatColumns.DATA_ID + " =? AND " 709346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT + " =?"; 709446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] columns = 709546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { DataUsageStatColumns._ID, DataUsageStatColumns.TIMES_USED }; 709646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ContentValues values = new ContentValues(); 709746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (Long dataId : dataIds) { 709846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] args = new String[] { dataId.toString(), String.valueOf(typeInt) }; 709946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.beginTransaction(); 710046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 710146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final Cursor cursor = mDb.query(Tables.DATA_USAGE_STAT, columns, where, args, 710246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa null, null, null); 710346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 710446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (cursor.getCount() > 0) { 710546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!cursor.moveToFirst()) { 710646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.e(TAG, 710746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa "moveToFirst() failed while getAccount() returned non-zero."); 710846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 710946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 711046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, cursor.getInt(1) + 1); 711146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 711246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.update(Tables.DATA_USAGE_STAT, values, 711346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns._ID + " =?", 711446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { cursor.getString(0) }); 711546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 711646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 711746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 711846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.DATA_ID, dataId); 711946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.USAGE_TYPE_INT, typeInt); 712046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, 1); 712146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 712246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.insert(Tables.DATA_USAGE_STAT, null, values); 712346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 712446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.setTransactionSuccessful(); 712546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 712646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 712746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 712846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 712946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.endTransaction(); 713046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 713146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 713246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 713346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return dataIds.size(); 713446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 713546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 713646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 713746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Returns a sort order String for promoting data rows (email addresses, phone numbers, etc.) 713846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * associated with a primary account. The primary account should be supplied from applications 713946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * with {@link ContactsContract#PRIMARY_ACCOUNT_NAME} and 714046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * {@link ContactsContract#PRIMARY_ACCOUNT_TYPE}. Null will be returned when the primary 714146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * account isn't available. 714246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 714346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private String getAccountPromotionSortOrder(Uri uri) { 714446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountName = 714546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME); 714646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountType = 714746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE); 714846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 714946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Data rows associated with primary account should be promoted. 715046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountName)) { 715146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa StringBuilder sb = new StringBuilder(); 715246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append("(CASE WHEN " + RawContacts.ACCOUNT_NAME + "="); 715346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountName); 715446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountType)) { 715546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 715646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountType); 715746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 715846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" THEN 0 ELSE 1 END)"); 715946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return sb.toString(); 716046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 716146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return null; 716246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 716346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 71644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 7165