ContactsProvider2.java revision 4b64b6e8f448938434cb1e022a4e7dfaae8f9c8c
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, 839f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 840f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 841f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")") 842f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_WITH_PHONES, 843f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 844f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 845f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " WHERE " + Contacts.HAS_PHONE_NUMBER + ")") 846f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .build(); 847f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa 848f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa // This is only exposed as hidden API for the contacts app, so we can be very specific in 849f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa // the filtering 850f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa private static final ProjectionMap sGroupsSummaryProjectionMapWithGroupCountPerAccount = 851f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa ProjectionMap.builder() 852f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .addAll(sGroupsSummaryProjectionMap) 853f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .add(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 854f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(*) FROM " + Views.GROUPS + " WHERE " 855f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + "(" + Groups.ACCOUNT_NAME + "=" 856f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + GroupsColumns.CONCRETE_ACCOUNT_NAME 857f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " AND " 858f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.ACCOUNT_TYPE + "=" + GroupsColumns.CONCRETE_ACCOUNT_TYPE 859f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " AND " 860f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.DELETED + "=0 AND " 861f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.FAVORITES + "=0 AND " 862f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.AUTO_ADD + "=0" 863f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")" 864f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " GROUP BY " 865f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.ACCOUNT_NAME + ", " + Groups.ACCOUNT_TYPE 866f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")") 867f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 868f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 869373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov /** Contains the agg_exceptions columns */ 870f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sAggregationExceptionsProjectionMap = ProjectionMap.builder() 871f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id") 872f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.TYPE) 873f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID1) 874f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID2) 875f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 876f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 877eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey /** Contains the agg_exceptions columns */ 878f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSettingsProjectionMap = ProjectionMap.builder() 879f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_NAME) 880f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_TYPE) 881f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_VISIBLE) 882f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.SHOULD_SYNC) 883f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ANY_UNSYNCED, 884f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN MIN(" + Settings.SHOULD_SYNC 885f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ",(SELECT " 886f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "(CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL" 887f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 888f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE MIN(" + Groups.SHOULD_SYNC + ")" 889f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)" 890f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.GROUPS 891f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 892f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_NAME 893f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 894f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_TYPE + "))=0" 895f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 896f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE 0" 897f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)") 898f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_COUNT, 899f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 900f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 901f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 902f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 903f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 904f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 905f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_WITH_PHONES, 906f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 907f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 908f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 909f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Contacts.HAS_PHONE_NUMBER 910f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 911f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 912f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 913f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 914f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 91582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov /** Contains StatusUpdates columns */ 916f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStatusUpdatesProjectionMap = ProjectionMap.builder() 917f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PresenceColumns.RAW_CONTACT_ID) 918f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.DATA_ID, DataColumns.CONCRETE_ID) 919f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_ACCOUNT) 920f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_HANDLE) 921f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PROTOCOL) 922f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 923f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // properly enforce uniqueness of null values 924f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CUSTOM_PROTOCOL, 925f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL + "=''" 926f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN NULL" 927f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END)") 928f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PRESENCE) 929f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CHAT_CAPABILITY) 930f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS) 931f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_TIMESTAMP) 932f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_RES_PACKAGE) 933f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_ICON) 934f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_LABEL) 935f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 936f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 9373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Contains StreamItems columns */ 9383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemsProjectionMap = ProjectionMap.builder() 9393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems._ID, StreamItemsColumns.CONCRETE_ID) 9403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(RawContacts.CONTACT_ID) 9413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_PACKAGE) 9433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_ICON) 9443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_LABEL) 9453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TEXT) 9463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TIMESTAMP) 9473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.COMMENTS) 9483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.ACTION) 9493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.ACTION_URI) 9503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemPhotosProjectionMap = ProjectionMap.builder() 9533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos._ID, StreamItemPhotosColumns.CONCRETE_ID) 9543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.STREAM_ITEM_ID) 9563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.SORT_INDEX) 9576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_FILE_ID) 9586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_URI, 9596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro "'" + DisplayPhoto.CONTENT_URI + "'||'/'||" + StreamItemPhotos.PHOTO_FILE_ID) 9603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.ACTION, StreamItemPhotosColumns.CONCRETE_ACTION) 9613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.ACTION_URI, StreamItemPhotosColumns.CONCRETE_ACTION_URI) 9621dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.HEIGHT) 9631dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.WIDTH) 9641dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.FILESIZE) 9653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9671b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov /** Contains Live Folders columns */ 968f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sLiveFoldersProjectionMap = ProjectionMap.builder() 969f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders._ID, Contacts._ID) 970f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders.NAME, Contacts.DISPLAY_NAME) 971f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // TODO: Put contact photo back when we have a way to display a default icon 972f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // for contacts without a photo 973f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // .add(LiveFolders.ICON_BITMAP, Photos.DATA) 974f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 975f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 976d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** Contains {@link Directory} columns */ 977f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDirectoryProjectionMap = ProjectionMap.builder() 978f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory._ID) 979f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.PACKAGE_NAME) 980f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.TYPE_RESOURCE_ID) 981f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DISPLAY_NAME) 982f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DIRECTORY_AUTHORITY) 983f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_TYPE) 984f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_NAME) 985f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.EXPORT_SUPPORT) 986778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.SHORTCUT_SUPPORT) 987778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.PHOTO_SUPPORT) 988f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 9897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 9909705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // where clause to update the status_updates table 9919705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE = 9929705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID + 9939705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE + 9949705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE "; 9959705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 9962526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private static final String[] EMPTY_STRING_ARRAY = new String[0]; 9972526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 998bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 999bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Notification ID for failure to import contacts. 1000bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1001bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private static final int LEGACY_IMPORT_FAILED_NOTIFICATION = 1; 100251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 100303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_START_MATCH = "["; 100403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_END_MATCH = "]"; 100503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_ELLIPSIS = "..."; 100603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final int DEFAULT_SNIPPET_ARG_MAX_TOKENS = -10; 100703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 10089a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhoneInitialized; 10099a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhone; 10109a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 1011f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov private StringBuilder mSb = new StringBuilder(); 10121129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs1 = new String[1]; 10131129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs2 = new String[2]; 10142526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private ArrayList<String> mSelectionArgs = Lists.newArrayList(); 10152526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1016f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private Account mAccount; 1017f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 101846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 101946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Stores mapping from type Strings exposed via {@link DataUsageFeedback} to 102046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type integers in {@link DataUsageStatColumns}. 102146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 102246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final Map<String, Integer> sDataUsageTypeMap; 102346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 10244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 10254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 1026a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 1027d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 1028d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 1029a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA); 1030a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES); 10313653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", 10323653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 10332d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", 10342d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov AGGREGATION_SUGGESTIONS); 1035a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO); 1036f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", 1037f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_ID_DISPLAY_PHOTO); 10383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", 10393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_ID_STREAM_ITEMS); 1040c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER); 10415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER); 10425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP); 10432149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA); 10445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID); 10452149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", 10462149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov CONTACTS_LOOKUP_ID_DATA); 1047f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", 1048f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_DISPLAY_PHOTO); 1049f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo", 1050f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_ID_DISPLAY_PHOTO); 1051a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities", 1052a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ENTITIES); 1053a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities", 1054a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ID_ENTITIES); 10553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items", 10563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_STREAM_ITEMS); 10573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items", 10583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_ID_STREAM_ITEMS); 1059f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD); 106042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*", 106142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann CONTACTS_AS_MULTI_VCARD); 10625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT); 1063ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*", 1064ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov CONTACTS_STREQUENT_FILTER); 10655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP); 106645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "contacts/frequent", CONTACTS_FREQUENT); 10673653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 10685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); 10695ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); 10705ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA); 1071f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/display_photo", 1072f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro RAW_CONTACTS_ID_DISPLAY_PHOTO); 107346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ENTITY_ID); 10743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items", 10753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RAW_CONTACTS_ID_STREAM_ITEMS); 107646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 107746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES); 1078b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 10794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 10804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 1081ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 108248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID); 10835e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER); 1084ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 10854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS); 108648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID); 10871dac83b8fa58944acfd00f44e717a7dddc659d2dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP); 10885e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP); 10895e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER); 10904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER); 1091ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 109248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID); 109346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** "*" is in CSV form with data ids ("123,456,789") */ 109446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/usagefeedback/*", DATA_USAGE_FEEDBACK_ID); 10951f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1096ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 1097ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 1098ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 1099ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 110035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 1101b5a4add17815167d20a90645779df34cdf45280dFred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#", 1102b5a4add17815167d20a90645779df34cdf45280dFred Quintana SYNCSTATE_ID); 110335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1104a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 1105b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 1106b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 1107b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 1108b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 11094f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1110eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS); 1111eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 111282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES); 111382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID); 11141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1115c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, 1116c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 1117c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 1118c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 11192d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 1120c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SHORTCUT); 1121c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 11221b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts", 11231b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS); 11241b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*", 11251b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_GROUP_NAME); 11261b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones", 11271b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_WITH_PHONES); 11281b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites", 11291b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_FAVORITES); 113009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 113109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS); 1132d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1133d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES); 1134d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID); 11357a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 11367a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME); 113724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 113824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile", PROFILE); 113924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/entities", PROFILE_ENTITIES); 114024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data", PROFILE_DATA); 114124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data/#", PROFILE_DATA_ID); 114224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/as_vcard", PROFILE_AS_VCARD); 114324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts", PROFILE_RAW_CONTACTS); 114424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#", 114524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID); 114624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/data", 114724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_DATA); 114824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/entity", 114924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_ENTITIES); 115046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 11513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items", STREAM_ITEMS); 11523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/photo", STREAM_ITEMS_PHOTOS); 11533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#", STREAM_ITEMS_ID); 11543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo", STREAM_ITEMS_ID_PHOTOS); 11553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo/#", 11563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann STREAM_ITEMS_ID_PHOTOS_ID); 11573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items_limit", STREAM_ITEMS_LIMIT); 11583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 1159f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "display_photo/*", DISPLAY_PHOTO); 1160f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS); 1161f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 116246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa HashMap<String, Integer> tmpTypeMap = new HashMap<String, Integer>(); 116346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_CALL, DataUsageStatColumns.USAGE_TYPE_INT_CALL); 116446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, 116546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT); 116646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, 116746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT); 116846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sDataUsageTypeMap = Collections.unmodifiableMap(tmpTypeMap); 116919a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov } 117019a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov 1171d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static class DirectoryInfo { 1172d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String authority; 1173d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountName; 1174d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountType; 1175d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 1176d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1177d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 1178d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Cached information about contact directories. 1179d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 11804458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private HashMap<String, DirectoryInfo> mDirectoryCache = new HashMap<String, DirectoryInfo>(); 11814458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private boolean mDirectoryCacheValid = false; 1182d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 11833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 1184ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov * An entry in group id cache. It maps the combination of (account type, account name 1185ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov * and source id) to group row id. 1186ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov */ 1187e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov public static class GroupIdCacheEntry { 1188ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType; 1189ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName; 1190ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String sourceId; 1191ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov long groupId; 1192ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov } 1193a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov 1194e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // We don't need a soft cache for groups - the assumption is that there will only 1195e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // be a small number of contact groups. The cache is keyed off source id. The value 1196e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // is a list of groups with this group id. 1197e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap(); 1198e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov 119924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 120024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Cached information about the contact ID and raw contact IDs that make up the user's 120124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile entry. 120224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 120324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static class ProfileIdCache { 120424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean inited; 120524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long profileContactId; 120624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Set<Long> profileRawContactIds = Sets.newHashSet(); 120724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Set<Long> profileDataIds = Sets.newHashSet(); 120824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 120924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 121024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Initializes the cache of profile contact and raw contact IDs. Does nothing if 121124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * the cache is already initialized (unless forceRefresh is set to true). 121224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param db The contacts database. 121324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forceRefresh Whether to force re-initialization of the cache. 121424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 121524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void init(SQLiteDatabase db, boolean forceRefresh) { 121624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!inited || forceRefresh) { 121724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileContactId = 0; 121824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactIds.clear(); 121924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileDataIds.clear(); 122024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Cursor c = db.rawQuery("SELECT " + 122124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_CONTACT_ID + "," + 122224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "," + 122324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro DataColumns.CONCRETE_ID + 122424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro " FROM " + Tables.RAW_CONTACTS + " JOIN " + Tables.ACCOUNTS + " ON " + 122524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "=" + 122624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro AccountsColumns.PROFILE_RAW_CONTACT_ID + 122724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro " JOIN " + Tables.DATA + " ON " + 122824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "=" + DataColumns.CONCRETE_RAW_CONTACT_ID, 122924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro null); 123024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro try { 123124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro while (c.moveToNext()) { 123224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (profileContactId == 0) { 123324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileContactId = c.getLong(0); 123424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 123524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactIds.add(c.getLong(1)); 123624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileDataIds.add(c.getLong(2)); 123724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 123824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } finally { 123924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro c.close(); 124024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 124124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 124224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 124324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 124424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 124524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private ProfileIdCache mProfileIdCache; 124624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1247f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1248f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of display photos. Larger images will be scaled 1249f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to fit. 1250f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1251f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxDisplayPhotoDim; 1252f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1253f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1254f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of photo thumbnails. 1255f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1256f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxThumbnailPhotoDim; 1257f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private HashMap<String, DataRowHandler> mDataRowHandlers; 1259b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private ContactsDatabaseHelper mDbHelper; 126031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1261f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private PhotoStore mPhotoStore; 1262f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12634097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 1264f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private NameLookupBuilder mNameLookupBuilder; 1265315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov 1266622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private PostalSplitter mPostalSplitter; 1267622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey 126872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov private ContactDirectoryManager mContactDirectoryManager; 1269622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private ContactAggregator mContactAggregator; 1270f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 1271a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private GlobalSearchSupport mGlobalSearchSupport; 1272d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov private CommonNicknameCache mCommonNicknameCache; 1273f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov private SearchIndexManager mSearchIndexManager; 1274a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 127520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private ContentValues mValues = new ContentValues(); 127673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov private HashMap<String, Boolean> mAccountWritability = Maps.newHashMap(); 127720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 127809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private int mProviderStatus = ProviderStatus.STATUS_NORMAL; 12793826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private boolean mProviderStatusUpdateNeeded; 128009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private long mEstimatedStorageRequirement = 0; 128115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mReadAccessLatch; 128215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mWriteAccessLatch; 128315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private boolean mAccountUpdateListenerRegistered; 1284bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private boolean mOkToOpenAccess = true; 128573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 1286d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private TransactionContext mTransactionContext = new TransactionContext(); 1287de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov 12881a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey private boolean mVisibleTouched = false; 12891a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 129081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov private boolean mSyncToNetwork; 129181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 12924cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao private Locale mCurrentLocale; 12933826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private int mContactsAccountCount; 1294d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov 1295bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private HandlerThread mBackgroundThread; 1296bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private Handler mBackgroundHandler; 1297bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1298f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mLastPhotoCleanup = 0; 1299f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 13004f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 13014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 1302de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov super.onCreate(); 1303ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov try { 1304ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return initialize(); 1305ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } catch (RuntimeException e) { 1306ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov Log.e(TAG, "Cannot start provider", e); 1307ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return false; 1308ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 1309ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 131035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1311ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov private boolean initialize() { 131215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov StrictMode.setThreadPolicy( 131315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 131415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 13153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Resources resources = getContext().getResources(); 1316f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxDisplayPhotoDim = resources.getInteger( 1317f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_display_photo_dim); 1318f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim = resources.getInteger( 1319f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_thumbnail_photo_dim); 13203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 132124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mProfileIdCache = new ProfileIdCache(); 1322b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper = (ContactsDatabaseHelper)getDatabaseHelper(); 132372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov mContactDirectoryManager = new ContactDirectoryManager(this); 1324a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov mGlobalSearchSupport = new GlobalSearchSupport(this); 1325f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mPhotoStore = new PhotoStore(getContext().getFilesDir(), mDbHelper); 132665ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov 1327bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // The provider is closed for business until fully initialized 132815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = new CountDownLatch(1); 132915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = new CountDownLatch(1); 133072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1331bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread = new HandlerThread("ContactsProviderWorker", 1332bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov Process.THREAD_PRIORITY_BACKGROUND); 1333bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread.start(); 1334bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler = new Handler(mBackgroundThread.getLooper()) { 1335bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov @Override 1336bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov public void handleMessage(Message msg) { 1337bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov performBackgroundTask(msg.what, msg.obj); 1338bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1339bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov }; 13402a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov 134115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_INITIALIZE); 1342bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1343bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 1344bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_LOCALE); 1345bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM); 134605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_SEARCH_INDEX); 1347bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_PROVIDER_STATUS); 134815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_OPEN_WRITE_ACCESS); 1349f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 13503826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 135149d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov return true; 13524f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 13534f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1354767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov /** 135551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * (Re)allocates all locale-sensitive structures. 135651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 135704b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov private void initForDefaultLocale() { 135815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 135915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mLegacyApiSupport = new LegacyApiSupport(context, mDbHelper, this, mGlobalSearchSupport); 13604cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mCurrentLocale = getLocale(); 136104b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov mNameSplitter = mDbHelper.createNameSplitter(); 13624cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter); 13634cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mPostalSplitter = new PostalSplitter(mCurrentLocale); 136451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov mCommonNicknameCache = new CommonNicknameCache(mDbHelper.getReadableDatabase()); 1365cdd03b2ba03718a7fa85663a2438136284a1557cBai Tao ContactLocaleUtils.getIntance().setLocale(mCurrentLocale); 13665b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator = new ContactAggregator(this, mDbHelper, 136715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 13685b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 1369f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov mSearchIndexManager = new SearchIndexManager(this); 13705b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 1371bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers = new HashMap<String, DataRowHandler>(); 1372bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1373bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, 13746d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForEmail(context, mDbHelper, mContactAggregator)); 1375bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE, 13766d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForIm(context, mDbHelper, mContactAggregator)); 1377bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, 13786d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForOrganization(context, mDbHelper, mContactAggregator)); 1379bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, 13806d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForPhoneNumber(context, mDbHelper, mContactAggregator)); 1381bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, 13826d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForNickname(context, mDbHelper, mContactAggregator)); 1383bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE, 13846d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForStructuredName(context, mDbHelper, mContactAggregator, 1385bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mNameSplitter, mNameLookupBuilder)); 1386bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(StructuredPostal.CONTENT_ITEM_TYPE, 13876d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForStructuredPostal(context, mDbHelper, mContactAggregator, 1388bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mPostalSplitter)); 1389bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE, 13906d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForGroupMembership(context, mDbHelper, mContactAggregator, 1391bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mGroupIdCache)); 1392bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Photo.CONTENT_ITEM_TYPE, 1393f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new DataRowHandlerForPhoto(context, mDbHelper, mContactAggregator, mPhotoStore)); 13946d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov mDataRowHandlers.put(Note.CONTENT_ITEM_TYPE, 13956d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForNote(context, mDbHelper, mContactAggregator)); 1396bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1397bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1398bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /** 1399bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Visible for testing. 1400bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov */ 1401bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /* package */ PhotoPriorityResolver createPhotoPriorityResolver(Context context) { 1402bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov return new PhotoPriorityResolver(context); 1403bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1404bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1405bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task) { 1406bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendEmptyMessage(task); 1407bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1408bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1409bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task, Object arg) { 1410bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(task, arg)); 1411bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1412bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1413bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void performBackgroundTask(int task, Object arg) { 1414bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov switch (task) { 141515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_INITIALIZE: { 141615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov initForDefaultLocale(); 141715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch.countDown(); 141815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = null; 141915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov break; 142015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 142115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 142215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_OPEN_WRITE_ACCESS: { 1423bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (mOkToOpenAccess) { 142415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch.countDown(); 142515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = null; 1426bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1427bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1428bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1429bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1430bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS: { 1431bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isLegacyContactImportNeeded()) { 1432bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov importLegacyContactsInBackground(); 1433bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1434bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1435bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1436bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1437bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_ACCOUNTS: { 143815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 143915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (!mAccountUpdateListenerRegistered) { 144015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov AccountManager.get(context).addOnAccountsUpdatedListener(this, null, false); 144115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mAccountUpdateListenerRegistered = true; 144215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 144315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 144415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Account[] accounts = AccountManager.get(context).getAccounts(); 1445bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov boolean accountsChanged = updateAccountsInBackground(accounts); 1446bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateContactsAccountCount(accounts); 1447bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateDirectoriesInBackground(accountsChanged); 1448bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1449bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1450bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1451bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_LOCALE: { 1452bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateLocaleInBackground(); 1453bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1454bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1455bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1456fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov case BACKGROUND_TASK_CHANGE_LOCALE: { 1457fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov changeLocaleInBackground(); 1458fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov break; 1459fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1460fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1461bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM: { 1462bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isAggregationUpgradeNeeded()) { 1463bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov upgradeAggregationAlgorithmInBackground(); 1464bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1465bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1466bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1467bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 146805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_SEARCH_INDEX: { 146905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov updateSearchIndexInBackground(); 147005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov break; 147105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 147205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1473bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_PROVIDER_STATUS: { 1474bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateProviderStatus(); 1475bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1476bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1477bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1478bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_DIRECTORIES: { 1479bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (arg != null) { 1480bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.onPackageChanged((String) arg); 1481bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1482bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1483bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1484f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1485f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case BACKGROUND_TASK_CLEANUP_PHOTOS: { 1486f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check rate limit. 1487f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long now = System.currentTimeMillis(); 1488f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (now - mLastPhotoCleanup > PHOTO_CLEANUP_RATE_LIMIT) { 1489f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mLastPhotoCleanup = now; 1490f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupPhotoStore(); 1491f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro break; 1492f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1493f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1494bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 14954cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 14964cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao 149753fac8f99f3884c372c907a76766d27fa9e1d95fDmitri Plotnikov public void onLocaleChanged() { 14983826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 14993826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 15004f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov return; 15014f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov } 15024f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov 1503fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_CHANGE_LOCALE); 15044cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 150551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 150651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov /** 150751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * Verifies that the contacts database is properly configured for the current locale. 150851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * If not, changes the database locale to the current locale using an asynchronous task. 150951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * This needs to be done asynchronously because the process involves rebuilding 151051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * large data structures (name lookup, sort keys), which can take minutes on 151151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * a large set of contacts. 151251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 1513bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateLocaleInBackground() { 1514f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 1515f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov // The process is already running - postpone the change 1516f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov if (mProviderStatus == ProviderStatus.STATUS_CHANGING_LOCALE) { 1517f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov return; 1518f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov } 1519f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 152051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 152151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final String providerLocale = prefs.getString(PREF_LOCALE, null); 152251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final Locale currentLocale = mCurrentLocale; 152351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov if (currentLocale.toString().equals(providerLocale)) { 152451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov return; 152551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 152651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 152751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov int providerStatus = mProviderStatus; 152851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_CHANGING_LOCALE); 1529bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDbHelper.setLocale(this, currentLocale); 1530bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).apply(); 1531bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov setProviderStatus(providerStatus); 1532bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 153351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 1534fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov /** 1535fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov * Reinitializes the provider for a new locale. 1536fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov */ 1537fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov private void changeLocaleInBackground() { 1538fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Re-initializing the provider without stopping it. 1539fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Locking the database will prevent inserts/updates/deletes from 1540fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // running at the same time, but queries may still be running 1541fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // on other threads. Those queries may return inconsistent results. 1542fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov SQLiteDatabase db = mDbHelper.getWritableDatabase(); 1543fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.beginTransaction(); 1544fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov try { 1545fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov initForDefaultLocale(); 1546fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.setTransactionSuccessful(); 1547fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } finally { 1548fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.endTransaction(); 1549fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1550fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1551fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov updateLocaleInBackground(); 1552fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1553fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 155405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov protected void updateSearchIndexInBackground() { 155505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov mSearchIndexManager.updateIndex(); 155605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 155705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1558bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateDirectoriesInBackground(boolean rescan) { 1559bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanAllPackages(rescan); 156051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 156151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 15623826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateProviderStatus() { 15633826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 15643826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 15653826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return; 15663826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15673826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 15683826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mContactsAccountCount == 0 156949d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov && DatabaseUtils.queryNumEntries(mDbHelper.getReadableDatabase(), 157049d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Tables.CONTACTS, null) == 0) { 15713826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 15723826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } else { 15733826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 15743826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15753826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15763826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 157731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* Visible for testing */ 1578f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro protected void cleanupPhotoStore() { 15796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro SQLiteDatabase db = mDbHelper.getWritableDatabase(); 15806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 15816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Assemble the set of photo store file IDs that are in use, and send those to the photo 1582f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // store. Any photos that aren't in that set will be deleted, and any photos that no 1583f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // longer exist in the photo store will be returned for us to clear out in the DB. 15846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = db.query(Views.DATA, new String[]{Data._ID, Photo.PHOTO_FILE_ID}, 1585f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.MIMETYPE + "=" + Photo.MIMETYPE + " AND " 1586f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro + Photo.PHOTO_FILE_ID + " IS NOT NULL", null, null, null, null); 15876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> usedPhotoFileIds = Sets.newHashSet(); 15886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToDataId = Maps.newHashMap(); 1589f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1590f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro while (c.moveToNext()) { 15916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = c.getLong(0); 15926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(1); 15936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 15946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToDataId.put(photoFileId, dataId); 15956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 15966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 15976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 15986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 15996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 16006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Also query for all social stream item photos. 16016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c = db.query(Tables.STREAM_ITEM_PHOTOS, 16026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{ 16036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos._ID, 16046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.STREAM_ITEM_ID, 16056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.PHOTO_FILE_ID 16066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro }, 16076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro null, null, null, null, null); 16086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToStreamItemPhotoId = Maps.newHashMap(); 16096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> streamItemPhotoIdToStreamItemId = Maps.newHashMap(); 16106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 16116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro while (c.moveToNext()) { 16126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = c.getLong(0); 16136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = c.getLong(1); 16146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(2); 16156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 16166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToStreamItemPhotoId.put(photoFileId, streamItemPhotoId); 16176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemPhotoIdToStreamItemId.put(streamItemPhotoId, streamItemId); 1618f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1619f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 1620f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 1621f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1622f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1623f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Run the photo store cleanup. 16246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> missingPhotoIds = mPhotoStore.cleanup(usedPhotoFileIds); 1625f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1626f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If any of the keys we're using no longer exist, clean them up. 16276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!missingPhotoIds.isEmpty()) { 1628f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 16296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro for (long missingPhotoId : missingPhotoIds) { 16306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToDataId.containsKey(missingPhotoId)) { 16316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = photoFileIdToDataId.get(missingPhotoId); 1632f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 1633f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.putNull(Photo.PHOTO_FILE_ID); 1634f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ops.add(ContentProviderOperation.newUpdate( 16356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentUris.withAppendedId(Data.CONTENT_URI, dataId)) 1636f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .withValues(updateValues).build()); 1637f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 16386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToStreamItemPhotoId.containsKey(missingPhotoId)) { 16396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For missing photos that were in stream item photos, just delete the stream 16406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // item photo. 16416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = photoFileIdToStreamItemPhotoId.get(missingPhotoId); 16426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = streamItemPhotoIdToStreamItemId.get(streamItemPhotoId); 16436802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ops.add(ContentProviderOperation.newDelete( 16446802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.CONTENT_URI.buildUpon() 16456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemId)) 16466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY) 16476802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemPhotoId)) 16486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .build()).build()); 16496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 1650f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1651f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1652f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro applyBatch(ops); 1653f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (OperationApplicationException oae) { 1654f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Not a fatal problem (and we'll try again on the next cleanup). 1655f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Failed to clean up outdated photo references", oae); 1656f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1657f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1658f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1659f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1660f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* Visible for testing */ 1661de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov @Override 1662b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 1663b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return ContactsDatabaseHelper.getInstance(context); 166431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 166531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1666f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* package */ PhotoStore getPhotoStore() { 1667f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return mPhotoStore; 1668f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1669f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 167087614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxDisplayPhotoDim() { 167187614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxDisplayPhotoDim; 167287614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 167387614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 167487614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxThumbnailPhotoDim() { 167587614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxThumbnailPhotoDim; 167687614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 167787614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1678013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov /* package */ NameSplitter getNameSplitter() { 1679013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov return mNameSplitter; 1680013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov } 1681013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov 16825df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov /* package */ NameLookupBuilder getNameLookupBuilder() { 16835df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov return mNameLookupBuilder; 16845df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov } 16855df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov 16865dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov /* Visible for testing */ 1687ed78fd6df5e9f3a2d572162e5d374d1f4a625bddDmitri Plotnikov public ContactDirectoryManager getContactDirectoryManagerForTest() { 168872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov return mContactDirectoryManager; 168972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 169072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 169172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov /* Visible for testing */ 16925dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov protected Locale getLocale() { 16935dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov return Locale.getDefault(); 16945dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov } 16955dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 16963d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov protected boolean isLegacyContactImportNeeded() { 1697b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_CONTACTS_IMPORTED, "0")); 1698b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov return version < PROPERTY_CONTACTS_IMPORT_VERSION; 16993d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17003d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1701568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov protected LegacyContactImporter getLegacyContactImporter() { 1702568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return new LegacyContactImporter(getContext(), this); 1703568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1704568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1705568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 1706bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Imports legacy contacts as a background task. 1707568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 1708bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private void importLegacyContactsInBackground() { 1709bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Importing legacy contacts"); 1710bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADING); 1711568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1712bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 1713bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDbHelper.setLocale(this, mCurrentLocale); 1714bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, mCurrentLocale.toString()).commit(); 1715568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1716bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov LegacyContactImporter importer = getLegacyContactImporter(); 1717bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (importLegacyContacts(importer)) { 1718bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportSuccess(); 1719bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } else { 1720bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportFailure(); 1721bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1722568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1723568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1724bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1725bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Unlocks the provider and declares that the import process is complete. 1726bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1727bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportSuccess() { 1728bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1729bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)getContext().getSystemService(Context.NOTIFICATION_SERVICE); 1730bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.cancel(LEGACY_IMPORT_FAILED_NOTIFICATION); 1731bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1732b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov // Store a property in the database indicating that the conversion process succeeded 1733b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov mDbHelper.setProperty(PROPERTY_CONTACTS_IMPORTED, 1734b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov String.valueOf(PROPERTY_CONTACTS_IMPORT_VERSION)); 1735bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 1736bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Completed import of legacy contacts"); 1737bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1738bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1739bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1740bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Announces the provider status and keeps the provider locked. 1741bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1742bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportFailure() { 1743bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Context context = getContext(); 1744bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1745bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); 1746bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1747bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // Show a notification 1748bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Notification n = new Notification(android.R.drawable.stat_notify_error, 1749bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_ticker), 1750bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov System.currentTimeMillis()); 1751bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.setLatestEventInfo(context, 1752bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_title), 1753bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_text), 1754bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov PendingIntent.getActivity(context, 0, new Intent(Intents.UI.LIST_DEFAULT), 0)); 1755bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; 1756bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1757bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.notify(LEGACY_IMPORT_FAILED_NOTIFICATION, n); 1758bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1759bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADE_OUT_OF_MEMORY); 1760bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Failed to import legacy contacts"); 1761bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1762bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // Do not let any database changes until this issue is resolved. 1763bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mOkToOpenAccess = false; 17643d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17653d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 17663d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /* Visible for testing */ 1767568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /* package */ boolean importLegacyContacts(LegacyContactImporter importer) { 17680e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff boolean aggregatorEnabled = mContactAggregator.isEnabled(); 17693d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov mContactAggregator.setEnabled(false); 17703d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov try { 1771bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (importer.importContacts()) { 1772bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1773bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // TODO aggregate all newly added raw contacts 1774bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mContactAggregator.setEnabled(aggregatorEnabled); 1775bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return true; 1776bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 17773d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } catch (Throwable e) { 17783d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov Log.e(TAG, "Legacy contact import failed", e); 17793d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 1780bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mEstimatedStorageRequirement = importer.getEstimatedStorageRequirement(); 1781bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return false; 17823d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17833d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1784a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 1785a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 1786a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 1787a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /* package */ void wipeData() { 1788b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.wipeData(); 1789f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mPhotoStore.clear(); 17903826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS; 1791a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 1792a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1793568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 179415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov * During intialization, this content provider will 1795568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * block all attempts to change contacts data. In particular, it will hold 1796568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * up all contact syncs. As soon as the import process is complete, all 1797568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * processes waiting to write to the provider are unblocked and can proceed 1798568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * to compete for the database transaction monitor. 1799568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 180015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private void waitForAccess(CountDownLatch latch) { 180115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (latch == null) { 180215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 180315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 180415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 180515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov while (true) { 180615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov try { 180715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov latch.await(); 180815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 180915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } catch (InterruptedException e) { 181015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Thread.currentThread().interrupt(); 1811ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov } 1812568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1813568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1814568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1815568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1816568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public Uri insert(Uri uri, ContentValues values) { 181715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1818568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.insert(uri, values); 1819568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1820568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1821568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1822568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 182315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (mWriteAccessLatch != null) { 1824bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // We are stuck trying to upgrade contacts db. The only update request 1825bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // allowed in this case is an update of provider status, which will trigger 1826bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // an attempt to upgrade contacts again. 1827bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov int match = sUriMatcher.match(uri); 1828bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (match == PROVIDER_STATUS) { 1829bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Integer newStatus = values.getAsInteger(ProviderStatus.STATUS); 1830bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (newStatus != null && newStatus == ProviderStatus.STATUS_UPGRADING) { 1831bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1832bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 1; 1833bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } else { 1834bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 0; 1835bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1836bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1837bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 183815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1839568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.update(uri, values, selection, selectionArgs); 1840568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1841568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1842568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1843568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int delete(Uri uri, String selection, String[] selectionArgs) { 184415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1845568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.delete(uri, selection, selectionArgs); 1846568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1847568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1848568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1849568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 1850568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov throws OperationApplicationException { 185115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1852568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.applyBatch(operations); 1853568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1854568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 18554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 18567b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov public int bulkInsert(Uri uri, ContentValues[] values) { 18577b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov waitForAccess(mWriteAccessLatch); 18587b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov return super.bulkInsert(uri, values); 18597b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov } 18607b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov 18617b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov @Override 1862285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void onBeginTransaction() { 1863bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1864b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "onBeginTransaction"); 1865b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1866285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.onBeginTransaction(); 18671ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana mContactAggregator.clearPendingAggregations(); 1868d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.clear(); 1869b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1870b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1871285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 1872285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 1873285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void beforeTransactionCommit() { 18741129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 1875bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1876b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "beforeTransactionCommit"); 1877b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1878285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.beforeTransactionCommit(); 1879b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 1880bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateInTransaction(mTransactionContext, mDb); 18811a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (mVisibleTouched) { 18821a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = false; 1883b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.updateAllVisible(); 18841a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey } 18853826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 1886bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 1887bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 18883826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatusUpdateNeeded) { 18893826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 18903826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = false; 18913826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 1892b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1893b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1894bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov private void updateSearchIndexInTransaction() { 1895bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov Set<Long> staleContacts = mTransactionContext.getStaleSearchIndexContactIds(); 1896bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov Set<Long> staleRawContacts = mTransactionContext.getStaleSearchIndexRawContactIds(); 1897bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov if (!staleContacts.isEmpty() || !staleRawContacts.isEmpty()) { 1898bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mSearchIndexManager.updateIndexForRawContacts(staleContacts, staleRawContacts); 1899bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mTransactionContext.clearSearchIndexUpdates(); 1900bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 1901bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 1902bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 1903b5a4add17815167d20a90645779df34cdf45280dFred Quintana private void flushTransactionalChanges() { 1904bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1905b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "flushTransactionChanges"); 1906b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 19071129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 190824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Determine whether we need to refresh the profile ID cache. 190924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean profileCacheRefreshNeeded = false; 191024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1911d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov for (long rawContactId : mTransactionContext.getInsertedRawContactIds()) { 19128ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(mDb, rawContactId); 1913bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.onRawContactInsert(mTransactionContext, mDb, rawContactId); 1914285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 1915b5a4add17815167d20a90645779df34cdf45280dFred Quintana 191624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Map<Long, Account> insertedProfileRawContactAccountMap = 191724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.getInsertedProfileRawContactIds(); 191824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!insertedProfileRawContactAccountMap.isEmpty()) { 191924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro for (long profileRawContactId : insertedProfileRawContactAccountMap.keySet()) { 192024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mDbHelper.updateRawContactDisplayName(mDb, profileRawContactId); 192124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mContactAggregator.onProfileRawContactInsert(mTransactionContext, mDb, 192224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactId, 192324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro insertedProfileRawContactAccountMap.get(profileRawContactId)); 192424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 192524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = true; 192624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 192724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1928d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov Set<Long> dirtyRawContacts = mTransactionContext.getDirtyRawContactIds(); 1929d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!dirtyRawContacts.isEmpty()) { 1930a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 1931a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL); 1932d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, dirtyRawContacts); 1933a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 1934a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mDb.execSQL(mSb.toString()); 193524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 193624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = profileCacheRefreshNeeded || 193724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro !Collections.disjoint(mProfileIdCache.profileRawContactIds, dirtyRawContacts); 1938a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov } 1939a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 1940d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov Set<Long> updatedRawContacts = mTransactionContext.getUpdatedRawContactIds(); 1941d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!updatedRawContacts.isEmpty()) { 1942a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 1943a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL); 1944d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, updatedRawContacts); 1945a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 1946a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mDb.execSQL(mSb.toString()); 194724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 194824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = profileCacheRefreshNeeded || 194924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro !Collections.disjoint(mProfileIdCache.profileRawContactIds, updatedRawContacts); 1950b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1951b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1952d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov for (Map.Entry<Long, Object> entry : mTransactionContext.getUpdatedSyncStates()) { 1953b5a4add17815167d20a90645779df34cdf45280dFred Quintana long id = entry.getKey(); 19549d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana if (mDbHelper.getSyncState().update(mDb, id, entry.getValue()) <= 0) { 19559d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana throw new IllegalStateException( 19569d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana "unable to update sync state, does it still exist?"); 19579d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana } 1958b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1959b5a4add17815167d20a90645779df34cdf45280dFred Quintana 196024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (profileCacheRefreshNeeded) { 196124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Force the profile ID cache to refresh. 196224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mProfileIdCache.init(mDb, true); 196324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 196424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1965d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.clear(); 1966b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1967b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1968a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** 1969a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * Appends comma separated ids. 1970a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * @param ids Should not be empty 1971a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov */ 1972d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private void appendIds(StringBuilder sb, Set<Long> ids) { 1973b5a4add17815167d20a90645779df34cdf45280dFred Quintana for (long id : ids) { 1974a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(id).append(','); 1975b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1976a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 1977a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.setLength(sb.length() - 1); // Yank the last comma 1978285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 1979285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 198024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 198124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given contact ID represents the user's personal profile - if it is, calls 198224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * a permission check (for writing the profile if forWrite is true, for reading the profile 198324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * otherwise). If the contact ID is not the user's profile, no check is executed. 1984afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 198524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param contactId The 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 enforceProfilePermissionForContact(SQLiteDatabase db, long contactId, 1989afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro boolean forWrite) { 1990afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 199124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileContactId == contactId) { 199224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 199324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 199424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 199524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 199624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 199724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given raw contact ID is a member of the user's personal profile - if it 199824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * is, calls a permission check (for writing the profile if forWrite is true, for reading the 199924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile otherwise). If the raw contact ID is not in the user's profile, no check is 200024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * executed. 2001afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 200224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param rawContactId The raw contact ID to be checked. 200324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 200424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 2005afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForRawContact(SQLiteDatabase db, long rawContactId, 2006afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro boolean forWrite) { 2007afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 200824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileRawContactIds.contains(rawContactId)) { 200924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 201024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 201124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 201224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 201324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 201424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given data ID is a member of the user's personal profile - if it is, 201524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * calls a permission check (for writing the profile if forWrite is true, for reading the 201624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile otherwise). If the data ID is not in the user's profile, no check is executed. 2017afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 201824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param dataId The data ID to be checked. 201924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 202024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 2021afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForData(SQLiteDatabase db, long dataId, boolean forWrite) { 2022afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 202324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileDataIds.contains(dataId)) { 202424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 202524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 202624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 202724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 202824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 202924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Performs a permission check for WRITE_PROFILE or READ_PROFILE (depending on the parameter). 203024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * If the permission check fails, this will throw a SecurityException. 203124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 203224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 203324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void enforceProfilePermission(boolean forWrite) { 203424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String profilePermission = forWrite 203524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro ? "android.permission.WRITE_PROFILE" 203624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro : "android.permission.READ_PROFILE"; 203724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro getContext().enforceCallingOrSelfPermission(profilePermission, null); 203824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 203924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2040285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2041cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov protected void notifyChange() { 204281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov notifyChange(mSyncToNetwork); 204381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = false; 204481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 204581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 204681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov protected void notifyChange(boolean syncToNetwork) { 204781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null, 204881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov syncToNetwork); 2049cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov } 2050568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 205151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov protected void setProviderStatus(int status) { 20523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != status) { 20533826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = status; 20543826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov getContext().getContentResolver().notifyChange(ProviderStatus.CONTENT_URI, null, false); 20553826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 205651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 205751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 2058f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public DataRowHandler getDataRowHandler(final String mimeType) { 20593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataRowHandler handler = mDataRowHandlers.get(mimeType); 20603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (handler == null) { 20616d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov handler = new DataRowHandlerForCustomMimetype( 20626d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov getContext(), mDbHelper, mContactAggregator, mimeType); 20633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(mimeType, handler); 20643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 20653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return handler; 20663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 20673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 20684f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 2069de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected Uri insertInTransaction(Uri uri, ContentValues values) { 2070bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 20711129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Log.v(TAG, "insertInTransaction: " + uri + " " + values); 2072b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2073f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2074f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 2075f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 2076f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2077a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 2078a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 207935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2080a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 208135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 2082b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov id = mDbHelper.getSyncState().insert(mDb, values); 208335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 208435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2085d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 2086d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov insertContact(values); 20876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 20886bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 20896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 209024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 209124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro throw new UnsupportedOperationException( 209224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "The profile contact is created automatically"); 209324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 209424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 20955ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 209624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter, false); 2097f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2098a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2099a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2100a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21015ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 21025ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 2103f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2104f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2105a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2106a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2107a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 21093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItems.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 21103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 21113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 211524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 211624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(true); 211724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter, true); 211824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mSyncToNetwork |= !callerIsSyncAdapter; 211924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 212024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 212124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2122a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case DATA: { 2123f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2124f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2125a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2126a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2127a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2128ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 2129f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov id = insertGroup(uri, values, callerIsSyncAdapter); 2130f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2131ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2132ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2133ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2134eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 21355aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey id = insertSettings(uri, values); 213643880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 2137eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 2138eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 2139eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 214082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 214182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov id = insertStatusUpdate(values); 21421f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 21431f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 21441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 21453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 21463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 21473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 21513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 21523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 21533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 21573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 21583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItemPhotos.STREAM_ITEM_ID, uri.getPathSegments().get(1)); 21593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 21603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2164a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 216581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 2166f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 2167a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2168a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 21707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 21717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 21727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2173de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return ContentUris.withAppendedId(uri, id); 2174a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2175a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2176a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2177e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * If account is non-null then store it in the values. If the account is 2178e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * already specified in the values then it must be consistent with the 2179e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * account, if it is non-null. 2180e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * 2181e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param uri Current {@link Uri} being operated on. 2182e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param values {@link ContentValues} to read and possibly update. 2183e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when only one of 2184e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_NAME} or 2185e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the 2186e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * other undefined. 2187e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME} 2188e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between 2189e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * the given {@link Uri} and {@link ContentValues}. 21907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 2191e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException { 2192f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 2193f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 2194e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 2195f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2196f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME); 2197f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 2198e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialValues = TextUtils.isEmpty(valueAccountName) 2199e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey ^ TextUtils.isEmpty(valueAccountType); 2200e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2201e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri || partialValues) { 2202e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 2203fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 2204fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 2205e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2206e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2207e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 2208e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 2209e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validUri = !TextUtils.isEmpty(accountName); 2210e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validValues = !TextUtils.isEmpty(valueAccountName); 2211e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2212e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validValues && validUri) { 2213e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Check that accounts match when both present 2214e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean accountMatch = TextUtils.equals(accountName, valueAccountName) 2215e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey && TextUtils.equals(accountType, valueAccountType); 2216e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (!accountMatch) { 2217fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 2218fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "When both specified, ACCOUNT_NAME and ACCOUNT_TYPE must match", uri)); 2219e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2220e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validUri) { 2221e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Fill values from Uri when not present 2222f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_NAME, accountName); 2223f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_TYPE, accountType); 2224e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validValues) { 2225f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountName = valueAccountName; 2226f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountType = valueAccountType; 2227e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else { 2228e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return null; 2229f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 2230f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2231e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Use cached Account object when matches, otherwise create 2232f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mAccount == null 2233f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.name.equals(accountName) 2234f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.type.equals(accountType)) { 2235f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mAccount = new Account(accountName, accountType); 2236035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 2237f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2238e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return mAccount; 22397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 22407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 22417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 2242d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov * Inserts an item in the contacts table 22436bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 22446bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 22456bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 22466bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 2247d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private long insertContact(ContentValues values) { 2248de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new UnsupportedOperationException("Aggregate contacts are created automatically"); 22496bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 22506bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 22516bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 225224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Inserts an item in the raw contacts table 2253a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2254f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param uri the values for the new row 2255f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param values the account this contact should be associated with. may be null. 2256dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana * @param callerIsSyncAdapter 225724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forProfile Whether this raw contact is being inserted into the user's profile. 2258a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2259a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 226024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private long insertRawContact(Uri uri, ContentValues values, boolean callerIsSyncAdapter, 226124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean forProfile) { 2262f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2263f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2264f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 2265f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2266e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final Account account = resolveAccount(uri, mValues); 22677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 22683d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov if (values.containsKey(RawContacts.DELETED) 22693d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov && values.getAsInteger(RawContacts.DELETED) != 0) { 2270f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 22713d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 22723d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2273f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov long rawContactId = mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, mValues); 2274f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = RawContacts.AGGREGATION_MODE_DEFAULT; 227524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (forProfile) { 227624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Profile raw contacts should never be aggregated by the aggregator; they are always 227724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // aggregated under a single profile contact. 227824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro aggregationMode = RawContacts.AGGREGATION_MODE_DISABLED; 227924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else if (mValues.containsKey(RawContacts.AGGREGATION_MODE)) { 2280f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov aggregationMode = mValues.getAsInteger(RawContacts.AGGREGATION_MODE); 2281f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 2282f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov mContactAggregator.markNewForAggregation(rawContactId, aggregationMode); 2283285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 228424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (forProfile) { 228524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Trigger creation of the user profile Contact (or association with the existing one) 228624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // at the end of the transaction. 228724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.profileRawContactInserted(rawContactId, account); 228824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else { 228924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Trigger creation of a Contact based on this RawContact at the end of transaction 229024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.rawContactInserted(rawContactId, account); 229124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 2292f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2293dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 2294dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 2295dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long starred = values.getAsLong(RawContacts.STARRED); 2296dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (starred != null && starred != 0) { 2297dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred != 0); 2298dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2299dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2300dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 23013826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 2302023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov return rawContactId; 2303a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2304a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2305dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void addAutoAddMembership(long rawContactId) { 2306dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID, 2307dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2308dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2309dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2310dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2311dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2312dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2313dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private Long findGroupByRawContactId(String selection, long rawContactId) { 2314dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Cursor c = mDb.query(Tables.GROUPS + "," + Tables.RAW_CONTACTS, PROJECTION_GROUP_ID, 2315dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, 2316dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}, 2317dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana null /* groupBy */, null /* having */, null /* orderBy */); 2318dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 2319dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (c.moveToNext()) { 2320dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return c.getLong(0); 2321dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2322dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return null; 2323dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 2324dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana c.close(); 2325dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2326dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2327dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2328dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void updateFavoritesMembership(long rawContactId, boolean isStarred) { 2329dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID, 2330dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2331dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2332dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (isStarred) { 2333dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2334dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2335dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana deleteDataGroupMembership(rawContactId, groupId); 2336dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2337dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2338dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2339dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2340dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void insertDataGroupMembership(long rawContactId, long groupId) { 2341dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ContentValues groupMembershipValues = new ContentValues(); 2342dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.GROUP_ROW_ID, groupId); 2343dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 2344dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(DataColumns.MIMETYPE_ID, 2345dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 2346dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDb.insert(Tables.DATA, null, groupMembershipValues); 2347dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2348dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2349dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void deleteDataGroupMembership(long rawContactId, long groupId) { 2350dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final String[] selectionArgs = { 2351dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)), 2352dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(groupId), 2353dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(rawContactId)}; 2354dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDb.delete(Tables.DATA, SELECTION_GROUPMEMBERSHIP_DATA, selectionArgs); 2355dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2356dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2357a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2358a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 2359a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2360a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 2361a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2362a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 2363f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private long insertData(ContentValues values, boolean callerIsSyncAdapter) { 2364a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 2365de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.clear(); 2366de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.putAll(values); 236767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 2368de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID); 236920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 237024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // If the data being inserted belongs to the user's profile entry, check for the 237124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // WRITE_PROFILE permission before proceeding. 2372afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 237324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2374de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace package with internal mapping 2375de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String packageName = mValues.getAsString(Data.RES_PACKAGE); 2376de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (packageName != null) { 2377b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 2378de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 2379de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 2380508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 2381de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace mimetype with internal mapping 2382de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String mimeType = mValues.getAsString(Data.MIMETYPE); 2383de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (TextUtils.isEmpty(mimeType)) { 2384de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new IllegalArgumentException(Data.MIMETYPE + " is required"); 2385de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 23864097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 2387b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.getMimeTypeId(mimeType)); 2388de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 2389a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2390a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2391d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov id = rowHandler.insert(mDb, mTransactionContext, rawContactId, mValues); 2392f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2393d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 2394a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2395d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.rawContactUpdated(rawContactId); 2396a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 23974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 23984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 23993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_items table. The account is checked against the 24013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account in the raw contact for which the stream item is being inserted. If the 24023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * new stream item results in more stream items under this raw contact than the limit, 24033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest one will be deleted (note that if the stream item inserted was the 24043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * oldest, it will be immediately deleted, and this will return 0). 24053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 24063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 24073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 24083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return the stream item _ID of the newly created row, or 0 if it was not created 24093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 24103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItem(Uri uri, ContentValues values) { 24113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 24123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 24133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 24143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = mValues.getAsLong(StreamItems.RAW_CONTACT_ID); 24163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If the data being inserted belongs to the user's profile entry, check for the 24183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // WRITE_PROFILE permission before proceeding. 2419afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 24203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 24223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 24233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 24243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream items table. 24266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 24276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 24286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 24293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Insert the new stream item. 24306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro id = mDb.insert(Tables.STREAM_ITEMS, null, mValues); 24316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (id == -1) { 24326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insertion failed. 24336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 24346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check to see if we're over the limit for stream items under this raw contact. 24373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // It's possible that the inserted stream item is older than the the existing 24383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // ones, in which case it may be deleted immediately (resetting the ID to 0). 24393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = cleanUpOldStreamItems(rawContactId, id); 24403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 24423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_item_photos table. The account is checked against 24463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the account in the raw contact that owns the stream item being modified. 24473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 24483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 24493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 24506802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return the stream item photo _ID of the newly created row, or 0 if there was an issue 24516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * with processing the photo or creating the row 24523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 24533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItemPhoto(Uri uri, ContentValues values) { 24543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 24553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 24563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 24573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = mValues.getAsLong(StreamItemPhotos.STREAM_ITEM_ID); 24593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemId != 0) { 24603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = lookupRawContactIdForStreamId(streamItemId); 24613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If the data being inserted belongs to the user's profile entry, check for the 24633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // WRITE_PROFILE permission before proceeding. 2464afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 24653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 24673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 24683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 24693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream item 24716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 24726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 24736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 24743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 24766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(mValues, false)) { 24776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insert the stream item photo. 24786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro id = mDb.insert(Tables.STREAM_ITEM_PHOTOS, null, mValues); 24796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 24823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Processes the photo contained in the {@link ContactsContract.StreamItemPhotos#PHOTO} 24866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * field of the given values, attempting to store it in the photo store. If successful, 24876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * the resulting photo file ID will be added to the values for insert/update in the table. 24886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * <p> 24896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * If updating, it is valid for the picture to be empty or unspecified (the function will 24906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * still return true). If inserting, a valid picture must be specified. 24916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param values The content values provided by the caller. 24926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param forUpdate Whether this photo is being processed for update (vs. insert). 24936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return Whether the insert or update should proceed. 24946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 24956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro private boolean processStreamItemPhoto(ContentValues values, boolean forUpdate) { 24966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!values.containsKey(StreamItemPhotos.PHOTO)) { 24976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 24986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro byte[] photoBytes = values.getAsByteArray(StreamItemPhotos.PHOTO); 25006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoBytes == null) { 25016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 25026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 25046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 25056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 25066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = mPhotoStore.insert(new PhotoProcessor(photoBytes, 25071dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim, true), true); 25086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileId != 0) { 25096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.put(StreamItemPhotos.PHOTO_FILE_ID, photoFileId); 25106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(StreamItemPhotos.PHOTO); 25116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return true; 25126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 25136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Couldn't store the photo, return 0. 25146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert"); 25156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 25166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } catch (IOException ioe) { 25186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert", ioe); 25196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 25206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 25236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 25243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Looks up the raw contact ID that owns the specified stream item. 25253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param streamItemId The ID of the stream item. 25263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The associated raw contact ID, or -1 if no such stream item exists. 25273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long lookupRawContactIdForStreamId(long streamItemId) { 25293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = -1; 25303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = mDb.query(Tables.STREAM_ITEMS, new String[]{StreamItems.RAW_CONTACT_ID}, 25313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems._ID + "=?", new String[]{String.valueOf(streamItemId)}, 25323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c.moveToFirst()) { 25353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann rawContactId = c.getLong(0); 25363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 25383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 25393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return rawContactId; 25413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given raw contact ID is owned by the given account. 25453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account is null, this will return true iff the raw contact 25463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * is also associated with the "null" account. 25473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 25483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account does not match, this will throw a security exception. 25493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 25503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to check for. 25513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void enforceModifyingAccount(Account account, long rawContactId) { 25533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String accountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 25543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + "=? AND " 25553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + "=?"; 25563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String noAccountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 25573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " IS NULL AND " 25583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " IS NULL"; 25593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c; 25603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (account != null) { 25613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContactsColumns.CONCRETE_ID}, 25623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann accountSelection, 25633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(rawContactId), mAccount.name, mAccount.type}, 25643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 25663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContactsColumns.CONCRETE_ID}, 25673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann noAccountSelection, new String[]{String.valueOf(rawContactId)}, 25683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if(c.getCount() == 0) { 25723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new SecurityException("Caller account does not match raw contact ID " 25733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + rawContactId); 25743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 25763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 25773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream items matches up with the given 25823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 25833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 25843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 25853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 25863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 25873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item IDs that would be included in this selection. 25883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItems(Account account, String selection, 25903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 25913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = Lists.newArrayList(); 25923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 25933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 25943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = qb.query(mDb, 25953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{StreamItems._ID, StreamItems.RAW_CONTACT_ID}, 25963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 25973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 25993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemIds.add(c.getLong(0)); 26003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 26023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 26033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds; 26083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream item photos matches up with the given 26123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 26133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 26143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 26153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 26163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 26173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item photo IDs that would be included in this selection. 26183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItemPhotos(Account account, String selection, 26203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 26213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemPhotoIds = Lists.newArrayList(); 26223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 26233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 26243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = qb.query(mDb, new String[]{StreamItemPhotos._ID, StreamItems.RAW_CONTACT_ID}, 26253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 26263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 26283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemPhotoIds.add(c.getLong(0)); 26293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 26313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 26323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemPhotoIds; 26373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Queries the database for stream items under the given raw contact. If there are 26413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * more entries than {@link ContactsProvider2#MAX_STREAM_ITEMS_PER_RAW_CONTACT}, 26423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest entries (as determined by timestamp) will be deleted. 26433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to examine for stream items. 26443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param insertedStreamItemId The ID of the stream item that was just inserted, 26453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * prompting this cleanup. Callers may pass 0 if no insertion prompted the 26463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * cleanup. 26473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The ID of the inserted stream item if it still exists after cleanup; 26483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 0 otherwise. 26493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long cleanUpOldStreamItems(long rawContactId, long insertedStreamItemId) { 26513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long postCleanupInsertedStreamId = insertedStreamItemId; 26523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = mDb.query(Tables.STREAM_ITEMS, new String[]{StreamItems._ID}, 26533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 26543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, StreamItems.TIMESTAMP + " DESC, " + StreamItems._ID + " DESC"); 26553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int streamItemCount = c.getCount(); 26573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemCount <= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 26583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Still under the limit - nothing to clean up! 26593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return insertedStreamItemId; 26603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 26613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToLast(); 26623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.getPosition() >= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 26633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = c.getLong(0); 26643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (insertedStreamItemId == streamItemId) { 26653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // The stream item just inserted is being deleted. 26663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann postCleanupInsertedStreamId = 0; 26673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(c.getLong(0)); 26693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToPrevious(); 26703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return postCleanupInsertedStreamId; 26763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2678ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateRawContactDisplayName(SQLiteDatabase db, long rawContactId) { 26798ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(db, rawContactId); 2680d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov } 2681d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov 26829261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 268320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov * Delete data row by row so that fixing of primaries etc work correctly. 268420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov */ 2685f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) { 268620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 268720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2688de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 2689de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 2690f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, 2691f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov selection, selectionArgs, null); 2692de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov try { 2693de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov while(c.moveToNext()) { 2694f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 269524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 269624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for write profile permission if the data belongs to the profile. 2697afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 269824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2699f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 2700a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2701d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov count += rowHandler.delete(mDb, mTransactionContext, c); 2702f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2703d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 270488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov } 270520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 270620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 2707de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov c.close(); 270820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 270920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 271020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 271120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 271220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 271388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov /** 271488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov * Delete a data row provided that it is one of the allowed mime types. 271588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov */ 271620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov public int deleteData(long dataId, String[] allowedMimeTypes) { 2717f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 271888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 271988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 27204da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 2721f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, Data._ID + "=?", 27224da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1, null); 2723f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 272420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 272520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!c.moveToFirst()) { 272620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 272720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 272820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2729f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 273020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean valid = false; 273120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov for (int i = 0; i < allowedMimeTypes.length; i++) { 273220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.equals(mimeType, allowedMimeTypes[i])) { 273320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov valid = true; 273420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 273520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 273620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 273720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 273820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!valid) { 27397a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana throw new IllegalArgumentException("Data type mismatch: expected " 274020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov + Lists.newArrayList(allowedMimeTypes)); 274120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 274220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 274324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for write profile permission if the data belongs to the profile. 274424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 2745afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 274624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2747a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2748d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov return rowHandler.delete(mDb, mTransactionContext, c); 274920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 275020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 275120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 275220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 275320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 275420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov /** 2755ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 2756ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 2757f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2758f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2759f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2760f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2761e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final Account account = resolveAccount(uri, mValues); 2762ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2763ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 2764f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String packageName = mValues.getAsString(Groups.RES_PACKAGE); 276567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 2766f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 276767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 2768f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.remove(Groups.RES_PACKAGE); 2769ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2770dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final boolean isFavoritesGroup = mValues.getAsLong(Groups.FAVORITES) != null 2771dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ? mValues.getAsLong(Groups.FAVORITES) != 0 2772dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana : false; 2773dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2774f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2775f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(Groups.DIRTY, 1); 277673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 277773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 2778f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov long result = mDb.insert(Tables.GROUPS, Groups.TITLE, mValues); 2779ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2780dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && isFavoritesGroup) { 2781dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // add all starred raw contacts to this group 2782dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String selection; 2783dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs; 2784dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (account == null) { 2785dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + " IS NULL AND " 2786dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContacts.ACCOUNT_TYPE + " IS NULL"; 2787dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = null; 2788dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2789dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + "=? AND " 2790dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContacts.ACCOUNT_TYPE + "=?"; 2791dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = new String[]{account.name, account.type}; 2792dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2793dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Cursor c = mDb.query(Tables.RAW_CONTACTS, 2794dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{RawContacts._ID, RawContacts.STARRED}, 2795dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, selectionArgs, null, null, null); 2796892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov try { 2797892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov while (c.moveToNext()) { 2798892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (c.getLong(1) != 0) { 2799892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov final long rawContactId = c.getLong(0); 2800892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov insertDataGroupMembership(rawContactId, result); 2801d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 2802892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } 2803dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2804892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } finally { 2805892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov c.close(); 2806dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2807dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2808dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2809f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mValues.containsKey(Groups.GROUP_VISIBLE)) { 28101a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2811ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey } 2812ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2813ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey return result; 2814ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2815ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 28165aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private long insertSettings(Uri uri, ContentValues values) { 2817e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final long id = mDb.insert(Tables.SETTINGS, null, values); 28185aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey 28191a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 28201a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2821e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 28221a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 2823e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return id; 2824e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 2825e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 2826ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 282782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov * Inserts a status update. 28281f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 282982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov public long insertStatusUpdate(ContentValues values) { 283082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov final String handle = values.getAsString(StatusUpdates.IM_HANDLE); 28310a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL); 28324dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov String customProtocol = null; 28334dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov 28340a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) { 283582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL); 28364dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov if (TextUtils.isEmpty(customProtocol)) { 28374dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov throw new IllegalArgumentException( 28384dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM"); 28394dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov } 28401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 28411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2842dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long rawContactId = -1; 2843dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long contactId = -1; 284482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov Long dataId = values.getAsLong(StatusUpdates.DATA_ID); 28456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountType = null; 28466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountName = null; 2847f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov mSb.setLength(0); 28482526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.clear(); 2849dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (dataId != null) { 2850dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the contact info for the given data row. 2851dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 28522526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(Tables.DATA + "." + Data._ID + "=?"); 28532526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(dataId)); 28541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 2855dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the data row to attach this presence update to 2856dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 28570a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(handle) || protocol == null) { 28580a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required"); 28590a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 28600a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 2861dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // TODO: generalize to allow other providers to match against email 2862dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol; 2863dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 28642a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov String mimeTypeIdIm = String.valueOf(mDbHelper.getMimeTypeIdForIm()); 2865dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (matchEmail) { 28662a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov String mimeTypeIdEmail = String.valueOf(mDbHelper.getMimeTypeIdForEmail()); 2867f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 2868f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise 2869f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the "OR" conjunction confuses it and it switches to a full scan of 2870f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the raw_contacts table. 2871f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 2872f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // This code relies on the fact that Im.DATA and Email.DATA are in fact the same 2873f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // column - Data.DATA1 28742526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + " IN (?,?)" + 28752526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Data.DATA1 + "=?" + 28762526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND ((" + DataColumns.MIMETYPE_ID + "=? AND " + Im.PROTOCOL + "=?"); 28772526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 28782526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 28792526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 28802526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 28812526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 2882dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 28832526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 28842526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 2885dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 28862526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=?))"); 28872526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 2888dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } else { 28892526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + "=?" + 28902526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.PROTOCOL + "=?" + 28912526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.DATA + "=?"); 28922526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 28932526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 28942526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 2895dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 28962526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 28972526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 2898dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 2899dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 29001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 290182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.DATA_ID)) { 29022526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + DataColumns.CONCRETE_ID + "=?"); 29032526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(values.getAsString(StatusUpdates.DATA_ID)); 2904dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 290570b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 290670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 29071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 29081f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 2909de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 29102526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null, 29114394086494fe7909aaca70f56fb4bb08beebf303Dmitri Plotnikov Clauses.CONTACT_VISIBLE + " DESC, " + Data.RAW_CONTACT_ID); 29121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 291367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataId = cursor.getLong(DataContactsQuery.DATA_ID); 29145ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID); 29156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountType = cursor.getString(DataContactsQuery.ACCOUNT_TYPE); 29166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountName = cursor.getString(DataContactsQuery.ACCOUNT_NAME); 2917e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 29181f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 29191f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 29201f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 29211f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 29221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 292331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 292431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 292531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 29261f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 29271f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 292882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.PRESENCE)) { 2929a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (customProtocol == null) { 2930a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 2931a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // properly enforce uniqueness of null values 2932a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov customProtocol = ""; 2933a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 2934a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 2935a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.clear(); 293682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.DATA_ID, dataId); 2937a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId); 2938a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.CONTACT_ID, contactId); 293982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PROTOCOL, protocol); 294082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 294182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_HANDLE, handle); 294282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.IM_ACCOUNT)) { 294382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT)); 2944a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 294582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PRESENCE, 294682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov values.getAsString(StatusUpdates.PRESENCE)); 2947aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori mValues.put(StatusUpdates.CHAT_CAPABILITY, 2948aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori values.getAsString(StatusUpdates.CHAT_CAPABILITY)); 29491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2950a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // Insert the presence update 2951a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mDb.replace(Tables.PRESENCE, null, mValues); 2952a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 2953e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 29540a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 295582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.STATUS)) { 295682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String status = values.getAsString(StatusUpdates.STATUS); 29570a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE); 29580a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov Integer labelResource = values.getAsInteger(StatusUpdates.STATUS_LABEL); 29590a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 29600a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(resPackage) 29610a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov && (labelResource == null || labelResource == 0) 29620a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov && protocol != null) { 29630a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov labelResource = Im.getProtocolLabelResource(protocol); 29640a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 29650a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 29660a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov Long iconResource = values.getAsLong(StatusUpdates.STATUS_ICON); 29670a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov // TODO compute the default icon based on the protocol 29680a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 2969a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (TextUtils.isEmpty(status)) { 297078fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.deleteStatusUpdate(dataId); 2971a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } else { 29726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP); 29736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (timestamp != null) { 29746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mDbHelper.replaceStatusUpdate(dataId, timestamp, status, resPackage, 29756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro iconResource, labelResource); 29766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 29776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mDbHelper.insertStatusUpdate(dataId, status, resPackage, iconResource, 29786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro labelResource); 29796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 29806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 29816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For forward compatibility with the new stream item API, insert this status update 29826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // there as well. If we already have a stream item from this source, update that 29836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // one instead of inserting a new one (since the semantics of the old status update 29846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // API is to only have a single record). 29856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (rawContactId != -1 && !TextUtils.isEmpty(status)) { 29866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentValues streamItemValues = new ContentValues(); 29876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 29886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TEXT, status); 29896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.COMMENTS, ""); 29906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_PACKAGE, resPackage); 29916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_ICON, iconResource); 29926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_LABEL, labelResource); 29936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TIMESTAMP, 29946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro timestamp == null ? System.currentTimeMillis() : timestamp); 29956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 29966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Note: The following is basically a workaround for the fact that status 29976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates didn't do any sort of account enforcement, while social stream item 29986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates do. We can't expect callers of the old API to start passing account 29996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // information along, so we just populate the account params appropriately for 30006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // the raw contact. 30016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (accountName != null && accountType != null) { 30026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_NAME, accountName); 30036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_TYPE, accountType); 30046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Check for an existing stream item from this source, and insert or update. 30076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Uri streamUri = StreamItems.CONTENT_URI; 30086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = query(streamUri, new String[]{StreamItems._ID}, 30096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", 30106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{String.valueOf(rawContactId)}, null); 30116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 30126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (c.getCount() > 0) { 30136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.moveToFirst(); 30146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro update(ContentUris.withAppendedId(streamUri, c.getLong(0)), 30156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues, null, null); 30166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 30176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro insert(streamUri, streamItemValues); 30186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 30206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 30216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 3024e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3025e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3026bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov 3027a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (contactId != -1) { 3028f4015ab9ab7c26b766b5331fbf6655b8c54877eaDmitri Plotnikov mContactAggregator.updateLastStatusUpdateId(contactId); 3029a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3030a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3031a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov return dataId; 30321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 30331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 30344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3035de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 3036bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3037b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "deleteInTransaction: " + uri); 3038b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3039b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3040f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3041f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 3042508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 3043508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 304435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 3045b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().delete(mDb, selection, selectionArgs); 304635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3047b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: 3048b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3049b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3050b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3051b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().delete(mDb, selectionWithId, selectionArgs); 3052b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3053cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov case CONTACTS: { 3054cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov // TODO 3055cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return 0; 3056cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3057cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3058d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3059d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 3060dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 30616bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 30626bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 30639fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP: { 30642e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 30652e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 30662e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 3067fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 3068fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 30692e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 30702e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 30712e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final long contactId = lookupContactIdByLookupKey(mDb, lookupKey); 3072dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 30732e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 30742e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 30759fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP_ID: { 30769fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // lookup contact by id and lookup key to see if they still match the actual record 30779fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final List<String> pathSegments = uri.getPathSegments(); 30789fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final String lookupKey = pathSegments.get(2); 30799fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 30809fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann setTablesAndProjectionMapForContacts(lookupQb, uri, null); 3081a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 30829fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann String[] args; 30839fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (selectionArgs == null) { 30849fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[2]; 30859fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 30869fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[selectionArgs.length + 2]; 30879fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 30889fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 30899fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args[0] = String.valueOf(contactId); 309060de6f6c3c70e53b603a47b0efc80993353a8368Daniel Lehmann args[1] = Uri.encode(lookupKey); 30919fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?"); 30929fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 30939fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann Cursor c = query(db, lookupQb, null, selection, args, null, null, null); 30949fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann try { 30959fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (c.getCount() == 1) { 30969fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // contact was unmodified so go ahead and delete it 3097dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 30989fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 30999fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // row was changed (e.g. the merging might have changed), we got multiple 31009fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // rows or the supplied selection filtered the record out 31019fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann return 0; 31029fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31039fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } finally { 31049fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann c.close(); 31059fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31069fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31079fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann 31082971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case RAW_CONTACTS: { 31092971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 3110fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov Cursor c = mDb.query(Tables.RAW_CONTACTS, 3111fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov new String[]{RawContacts._ID, RawContacts.CONTACT_ID}, 3112e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 31132971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 31142971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 31152971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = c.getLong(0); 3116fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov long contactId = c.getLong(1); 3117fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov numDeletes += deleteRawContact(rawContactId, contactId, 3118fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 31192971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31202971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 31212971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 31222971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31232971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 31242971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31252971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 31265ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 31272971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = ContentUris.parseId(uri); 3128fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return deleteRawContact(rawContactId, mDbHelper.getContactId(rawContactId), 3129fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 3130508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3131508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 313220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3133f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 3134944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong return deleteData(appendAccountToSelection(uri, selection), selectionArgs, 3135f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana callerIsSyncAdapter); 313620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 313720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 313848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 313948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 314048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 314148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3142508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 3143f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 31444da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 31454da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter); 3146ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3147ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3148ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3149f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 31505aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter); 31512971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31522971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 31532971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case GROUPS: { 31542971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 31552971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups._ID}, 3156e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 31572971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 31582971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 31595aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter); 31602971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31612971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 31622971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 31632971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 316481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (numDeletes > 0) { 3165f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 316681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 31672971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 3168508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3169508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 3170eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 317143880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3172e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs); 3173eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3174eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 317582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 31760a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov return deleteStatusUpdates(selection, selectionArgs); 31771f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 31781f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 31793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 31803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), selection, selectionArgs); 31823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 31843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 31853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), 31873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemsColumns.CONCRETE_ID + "=?", 31883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 31893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 31913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 31923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), selection, selectionArgs); 31943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 31953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 31963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 31973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 31983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 31993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 32003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), 32013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " 32023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + StreamItemPhotos.STREAM_ITEM_ID + "=?", 32033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 32043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 320681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 320781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 32083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return mLegacyApiSupport.delete(uri, selection, selectionArgs); 320981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3210508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 32114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 32124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 32131c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) { 3214ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3215b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final long groupMembershipMimetypeId = mDbHelper 321694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 3217de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 321894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 321994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupId, null); 322094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 322194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana try { 3222f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 3223de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 322494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } else { 322594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.clear(); 322694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.put(Groups.DELETED, 1); 3227f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mValues.put(Groups.DIRTY, 1); 3228de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null); 322994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 323094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } finally { 32311a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 323294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 323394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 323494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 32355aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int deleteSettings(Uri uri, String selection, String[] selectionArgs) { 3236e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final int count = mDb.delete(Tables.SETTINGS, selection, selectionArgs); 32371a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3238e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3239e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3240e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3241dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int deleteContact(long contactId, boolean callerIsSyncAdapter) { 3242afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(mDb, contactId, true); 324396b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(contactId); 3244cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, 324596b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker RawContacts.CONTACT_ID + "=?", mSelectionArgs1, 324696b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker null, null, null); 3247cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov try { 3248cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov while (c.moveToNext()) { 3249cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov long rawContactId = c.getLong(0); 3250dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 3251cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3252cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } finally { 3253cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov c.close(); 3254cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3255cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 32563826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 32573826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3258cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return mDb.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 3259cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3260cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3261fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) { 3262afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 32633389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov mContactAggregator.invalidateAggregationExceptionCache(); 32643826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 32653826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3266f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 326714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null); 3268fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov int count = mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null); 3269fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov mContactAggregator.updateDisplayNameForContact(mDb, contactId); 3270fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return count; 327133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } else { 3272b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.removeContactIfSingleton(rawContactId); 3273dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 327433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 327533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 327633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 32770a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private int deleteStatusUpdates(String selection, String[] selectionArgs) { 32789705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // delete from both tables: presence and status_updates 32799705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 32809705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (VERBOSE_LOGGING) { 32819705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori Log.v(TAG, "deleting data from status_updates for " + selection); 32829705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 32839705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mDb.delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection), 32849705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 32859705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mDb.delete(Tables.PRESENCE, selection, selectionArgs); 32860a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 32870a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 32883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItems(Uri uri, ContentValues values, String selection, 32893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 32903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream items to be deleted, and check that they belong 32913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // to the account. 32923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 32933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = enforceModifyingAccountForStreamItems( 32943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann account, selection, selectionArgs); 32953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 32973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann for (long streamItemId : streamItemIds) { 32983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(streamItemId); 32993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mVisibleTouched = true; 33023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds.size(); 33033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItem(long streamItemId) { 33063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 33073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItemPhotos(streamItemId); 33083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEMS, StreamItems._ID + "=?", 33093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 33103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(Uri uri, ContentValues values, String selection, 33133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 33143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream item photos to be deleted, and check that they 33153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // belong to the account. 33163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 33173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 33183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 33203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEM_PHOTOS, selection, selectionArgs); 33213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(long streamItemId) { 33243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 33253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEM_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID + "=?", 33263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 33273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 3329dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int markRawContactAsDeleted(long rawContactId, boolean callerIsSyncAdapter) { 333081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 333181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 3332cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.clear(); 3333cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DELETED, 1); 3334cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 3335cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1); 3336cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 3337cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3338dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return updateRawContact(rawContactId, mValues, callerIsSyncAdapter); 3339cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3340cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 33414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3342de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int updateInTransaction(Uri uri, ContentValues values, String selection, 3343de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov String[] selectionArgs) { 3344bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3345b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "updateInTransaction: " + uri); 3346b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3347b5a4add17815167d20a90645779df34cdf45280dFred Quintana 334835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 334900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 335000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 3351b5a4add17815167d20a90645779df34cdf45280dFred Quintana if (match == SYNCSTATE_ID && selection == null) { 3352b5a4add17815167d20a90645779df34cdf45280dFred Quintana long rowId = ContentUris.parseId(uri); 33531129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Object data = values.get(ContactsContract.SyncState.DATA); 3354d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.syncStateUpdated(rowId, data); 3355b5a4add17815167d20a90645779df34cdf45280dFred Quintana return 1; 3356b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3357b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3358f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3359f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 336000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 336135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 3362b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().update(mDb, values, 3363b5a4add17815167d20a90645779df34cdf45280dFred Quintana appendAccountToSelection(uri, selection), selectionArgs); 3364b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3365b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: { 3366b5a4add17815167d20a90645779df34cdf45280dFred Quintana selection = appendAccountToSelection(uri, selection); 3367b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3368b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3369b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3370b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().update(mDb, values, 3371b5a4add17815167d20a90645779df34cdf45280dFred Quintana selectionWithId, selectionArgs); 3372b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 337335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3374d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 3375dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter); 337600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 337700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 337800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3379d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3380dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(ContentUris.parseId(uri), values, callerIsSyncAdapter); 3381c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 3382c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 3383c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 338424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 338524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Restrict update to the user's profile. 338624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro StringBuilder profileSelection = new StringBuilder(); 338724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileSelection.append(Contacts.IS_USER_PROFILE + "=1"); 338824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(selection)) { 338924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileSelection.append(" AND (").append(selection).append(")"); 339024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 339124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro count = updateContactOptions(values, profileSelection.toString(), selectionArgs, 339224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro callerIsSyncAdapter); 339324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 339424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 339524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 33962e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP: 33972e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP_ID: { 33982e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 33992e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 34002e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 3401fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 3402fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 34032e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 34042e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 34052e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final long contactId = lookupContactIdByLookupKey(mDb, lookupKey); 3406dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(contactId, values, callerIsSyncAdapter); 34072e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey break; 34082e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 34092e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 34107d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh case RAW_CONTACTS_DATA: { 34117d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh final String rawContactId = uri.getPathSegments().get(1); 34127d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ") 34137d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh + (selection == null ? "" : " AND " + selection); 34147d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 34157d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter); 34167d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 34177d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh break; 34187d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh } 34197d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 342020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3421944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong count = updateData(uri, values, appendAccountToSelection(uri, selection), 3422f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 342381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3424f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 342581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 342620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 342720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3428c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 342948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 343048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 343148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 343248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3433f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter); 343481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3435f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 343681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 343700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 343800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 34397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 34405ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 34415ac5c70d1165309302ebcc931f51723e37d31e0bJeff Sharkey selection = appendAccountToSelection(uri, selection); 3442dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, selection, selectionArgs, callerIsSyncAdapter); 34437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 34447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 34457e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 34465ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 344733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 34484529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (selection != null) { 34494da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 34504da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov count = updateRawContacts(values, RawContacts._ID + "=?" 3451dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND(" + selection + ")", selectionArgs, 3452dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 34534529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } else { 34544da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 3455dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1, 3456dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 34574529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 34587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 34597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 34607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 3461ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 34625aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, appendAccountToSelection(uri, selection), 3463f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 346481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3465f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 346681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3467ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3468ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3469ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3470ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3471ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 34724da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId)); 34734da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String selectionWithId = Groups._ID + "=? " 347473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov + (selection == null ? "" : " AND " + selection); 34755aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, selectionWithId, selectionArgs, 34765aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey callerIsSyncAdapter); 347781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3478f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 347981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3480ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3481ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3482ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3483127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 3484de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov count = updateAggregationException(mDb, values); 3485b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 3486b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3487b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 3488eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 3489e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey count = updateSettings(uri, values, appendAccountToSelection(uri, selection), 3490e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey selectionArgs); 349143880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3492eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 3493eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3494eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 34959705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori case STATUS_UPDATES: { 34969705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori count = updateStatusUpdate(uri, values, selection, selectionArgs); 34979705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori break; 34989705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 34999705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 35003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 35013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, selection, selectionArgs); 35023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 35063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, StreamItemsColumns.CONCRETE_ID + "=?", 35073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 35083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 35123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, selection, selectionArgs); 35133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 35173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 35183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 35193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{streamItemId}); 35203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 35243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 35253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 35263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 35273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " + 35283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?", 35293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 35303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 353372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov case DIRECTORIES: { 3534bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanPackagesByUid(Binder.getCallingUid()); 353572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov count = 1; 3536d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 3537d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 3538d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 353946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa case DATA_USAGE_FEEDBACK_ID: { 354046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (handleDataUsageFeedback(uri)) { 354146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 1; 354246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 354346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 0; 354446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 354546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa break; 354646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 354746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 354881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 354981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 3550f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 355181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 355200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 355300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 355400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 35554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 35564f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 35579705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private int updateStatusUpdate(Uri uri, ContentValues values, String selection, 35589705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori String[] selectionArgs) { 35599705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // update status_updates table, if status is provided 35609705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 35619705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori int updateCount = 0; 35629705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values); 35639705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 35649705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori updateCount = mDb.update(Tables.STATUS_UPDATES, 35659705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues, 35669705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori getWhereClauseForStatusUpdatesTable(selection), 35679705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 35689705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35699705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 35709705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // now update the Presence table 35719705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues = getSettableColumnsForPresenceTable(values); 35729705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 35739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori updateCount = mDb.update(Tables.PRESENCE, settableValues, 35749705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selection, selectionArgs); 35759705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35769705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO updateCount is not entirely a valid count of updated rows because 2 tables could 35779705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // potentially get updated in this method. 35789705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return updateCount; 35799705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35809705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 35813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItems(Uri uri, ContentValues values, String selection, 35823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 35833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream items can't be moved to a new raw contact. 35843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItems.RAW_CONTACT_ID); 35853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream items being updated belong to the account. 35873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 35883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItems(account, selection, selectionArgs); 35893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream items table. 35916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 35926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 35936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 35943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If there's been no exception, the update should be fine. 35953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.update(Tables.STREAM_ITEMS, values, selection, selectionArgs); 35963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItemPhotos(Uri uri, ContentValues values, String selection, 35993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 36003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream item photos can't be moved to a new stream item. 36013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItemPhotos.STREAM_ITEM_ID); 36023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream item photos being updated belong to the account. 36043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 36053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 36063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream item 36086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 36096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 36106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 36116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 36126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo (since we're updating, it's valid for the photo to not be present). 36136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(values, true)) { 36146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // If there's been no exception, the update should be fine. 36156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return mDb.update(Tables.STREAM_ITEM_PHOTOS, values, selection, selectionArgs); 36166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 36176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 36183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36209705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori /** 36219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori * Build a where clause to select the rows to be updated in status_updates table. 36229705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori */ 36239705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private String getWhereClauseForStatusUpdatesTable(String selection) { 36249705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.setLength(0); 36259705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE); 36269705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(selection); 36279705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(")"); 36289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mSb.toString(); 36299705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) { 36329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 36339705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values, 36349705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS); 36359705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values, 36369705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_TIMESTAMP); 36379705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values, 36389705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_RES_PACKAGE); 36399705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values, 36409705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_LABEL); 36419705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values, 36429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_ICON); 36439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 36449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForPresenceTable(ContentValues values) { 36479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 36489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values, 36499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.PRESENCE); 3650aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.CHAT_CAPABILITY, values, 3651aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori StatusUpdates.CHAT_CAPABILITY); 36529705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 36539705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36549705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36555aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int updateGroups(Uri uri, ContentValues values, String selectionWithId, 3656f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 365773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3658ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3659ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov 366073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov ContentValues updatedValues; 3661f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter && !values.containsKey(Groups.DIRTY)) { 366273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = mValues; 366373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.clear(); 366473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.putAll(values); 366573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.put(Groups.DIRTY, 1); 366673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } else { 366773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = values; 366873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 366973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3670ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey int count = mDb.update(Tables.GROUPS, updatedValues, selectionWithId, selectionArgs); 36711a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) { 36721a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 367394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 36746ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi if (updatedValues.containsKey(Groups.SHOULD_SYNC) 36751129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) { 36766ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups.ACCOUNT_NAME, 3677e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey Groups.ACCOUNT_TYPE}, selectionWithId, selectionArgs, null, 36786ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi null, null); 36796ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountName; 36806ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountType; 36816ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi try { 36826ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi while (c.moveToNext()) { 36836ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountName = c.getString(0); 36846ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountType = c.getString(1); 368524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 36866ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Account account = new Account(accountName, accountType); 3687ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov ContentResolver.requestSync(account, ContactsContract.AUTHORITY, 36886ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi new Bundle()); 36896ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi break; 36906ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 36916ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 36926ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } finally { 36936ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi c.close(); 36946ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 36956ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 369694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana return count; 369794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 369894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 3699b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private int updateSettings(Uri uri, ContentValues values, String selection, 3700b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov String[] selectionArgs) { 3701e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final int count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs); 37021a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 37031a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3704e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3705e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3706e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3707e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3708dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs, 3709dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 37104529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (values.containsKey(RawContacts.CONTACT_ID)) { 37114529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " + 37124529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov "in content values. Contact IDs are assigned automatically"); 37134529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 371473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 371597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 371697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 371797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0"); 371897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 371997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 37204529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov int count = 0; 3721ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.RAW_CONTACTS, 372251bf5ea9531b9da72caff607dbdf35fd6f61cbe2Jeff Sharkey new String[] { RawContacts._ID }, selection, 37234529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov selectionArgs, null, null, null); 37244529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov try { 37254529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov while (cursor.moveToNext()) { 37264529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov long rawContactId = cursor.getLong(0); 3727dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateRawContact(rawContactId, values, callerIsSyncAdapter); 37284529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov count++; 37294529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37304529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } finally { 37314529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov cursor.close(); 37324529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37334529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 37344529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov return count; 37354529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37364529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 3737dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContact(long rawContactId, ContentValues values, 3738dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 373924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 374024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Enforce profile permissions if the raw contact is in the user's profile. 3741afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 374224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 374396b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker final String selection = RawContacts._ID + " = ?"; 374496b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(rawContactId); 374519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED) 374619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka && values.getAsInteger(RawContacts.DELETED) == 0); 374719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int previousDeleted = 0; 3748ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType = null; 3749ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName = null; 375019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete) { 375119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka Cursor cursor = mDb.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, selection, 375296b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1, null, null, null); 375319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka try { 375419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (cursor.moveToFirst()) { 375519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka previousDeleted = cursor.getInt(RawContactsQuery.DELETED); 3756ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE); 3757ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME); 375819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 375919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } finally { 376019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka cursor.close(); 376119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 376219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 376319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT); 376419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 3765f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 376696b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker int count = mDb.update(Tables.RAW_CONTACTS, values, selection, mSelectionArgs1); 37675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count != 0) { 3768f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (values.containsKey(RawContacts.AGGREGATION_MODE)) { 3769f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = values.getAsInteger(RawContacts.AGGREGATION_MODE); 3770f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov 3771f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // As per ContactsContract documentation, changing aggregation mode 3772f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // to DEFAULT should not trigger aggregation 3773f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) { 377469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, aggregationMode, false); 3775f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 3776f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 3777433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey if (values.containsKey(RawContacts.STARRED)) { 3778dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 3779dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 3780dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana values.getAsLong(RawContacts.STARRED) != 0); 3781dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 37824529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov mContactAggregator.updateStarred(rawContactId); 3783dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 3784dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then update the 3785dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // favorites group membership based on whether or not this contact is starred. 3786dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // If it is starred, add a group membership, if one doesn't already exist 3787dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // otherwise delete any matching group memberships. 3788dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 3789dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean starred = 0 != DatabaseUtils.longForQuery(mDb, 3790dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana SELECTION_STARRED_FROM_RAW_CONTACTS, 3791dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}); 3792dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred); 3793dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3794dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3795dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3796dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then add a 3797dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // group membership to the group marked as AutoAdd, if any. 3798dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 3799dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 3800433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey } 3801dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3802285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov if (values.containsKey(RawContacts.SOURCE_ID)) { 38032b7a632bba423357ae5641f94da6a2f71afc523bDmitri Plotnikov mContactAggregator.updateLookupKeyForRawContact(mDb, rawContactId); 3804285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 3805f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.containsKey(RawContacts.NAME_VERIFIED)) { 3806f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 3807f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // If setting NAME_VERIFIED for this raw contact, reset it for all 3808f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // other raw contacts in the same aggregate 3809f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) { 381078fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.resetNameVerifiedForOtherRawContacts(rawContactId); 3811f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 3812f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov mContactAggregator.updateDisplayNameForRawContact(mDb, rawContactId); 3813f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 381419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete && previousDeleted == 1) { 3815d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.rawContactInserted(rawContactId, 3816d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov new Account(accountName, accountType)); 381719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 38185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 38195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return count; 382033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 382133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 3822321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana private int updateData(Uri uri, ContentValues values, String selection, 3823f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 382420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 382520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 382620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data._ID); 38275ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov mValues.remove(Data.RAW_CONTACT_ID); 382820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 382920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 383020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String packageName = values.getAsString(Data.RES_PACKAGE); 383120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (packageName != null) { 383220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 3833b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 383420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 383520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 383697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 383797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 383897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov Data.IS_READ_ONLY + "=0"); 383997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 384097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 3841653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov int count = 0; 384220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3843653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 3844653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // so we don't need to worry about updating data we don't have permission to read. 3845f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // This query will be allowed to return profiles, and we'll do the permission check 3846f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // within the loop. 38476ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Cursor c = queryLocal(uri.buildUpon() 3848f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "1").build(), 3849f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro DataRowHandler.DataUpdateQuery.COLUMNS, 38506ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro selection, selectionArgs, null, -1 /* directory ID */, 38516ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro true /* suppress profile check */); 3852653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov try { 3853653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov while(c.moveToNext()) { 385424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check profile permission for the raw contact that owns each data record. 385524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = c.getLong(DataRowHandler.DataUpdateQuery.RAW_CONTACT_ID); 3856afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 385724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 3858f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count += updateData(mValues, c, callerIsSyncAdapter); 385920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3860653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov } finally { 3861653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov c.close(); 386220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 386320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3864653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return count; 386520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 386620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3867f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) { 3868653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov if (values.size() == 0) { 3869653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return 0; 3870321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 3871653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov 3872f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String mimeType = c.getString(DataRowHandler.DataUpdateQuery.MIMETYPE); 3873a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 3874f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean updated = 3875f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro rowHandler.update(mDb, mTransactionContext, values, c, callerIsSyncAdapter); 3876f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) { 3877f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 3878a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov } 3879f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return updated ? 1 : 0; 3880321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 3881321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana 38828c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov private int updateContactOptions(ContentValues values, String selection, 3883dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 38848c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov int count = 0; 3885ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.CONTACTS, 388624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[] { Contacts._ID, Contacts.IS_USER_PROFILE }, selection, 38878c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov selectionArgs, null, null, null); 38888c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov try { 38898c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov while (cursor.moveToNext()) { 38908c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov long contactId = cursor.getLong(0); 389124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 389224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for profile write permission before updating a user's profile contact. 389324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean isProfile = cursor.getInt(1) == 1; 389424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (isProfile) { 389524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(true); 389624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 389724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 3898dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateContactOptions(contactId, values, callerIsSyncAdapter); 38998c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov count++; 39008c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 39018c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } finally { 39028c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov cursor.close(); 39038c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 39048c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 39058c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov return count; 39068c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 39078c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 3908dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateContactOptions(long contactId, ContentValues values, 3909dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 3910d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 391124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check write permission if the contact is the user's profile. 3912afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(mDb, contactId, true); 391324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 39148c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 3915b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 3916d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 3917b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 3918d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 3919b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 3920d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 3921b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 3922d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 3923b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 3924d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.STARRED); 3925d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 3926d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 39278c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.size() == 0) { 3928d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 3929d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 3930d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 39318c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.containsKey(RawContacts.STARRED)) { 3932c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey // Mark dirty when changing starred to trigger sync 39338c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3934c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey } 3935c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey 39364da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(contactId); 393797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov mDb.update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?" 393897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov + " AND " + RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0", mSelectionArgs1); 39398c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 3940dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (mValues.containsKey(RawContacts.STARRED) && !callerIsSyncAdapter) { 3941ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.RAW_CONTACTS, 3942dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=?", 3943dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mSelectionArgs1, null, null, null); 3944dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 3945dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (cursor.moveToNext()) { 3946dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana long rawContactId = cursor.getLong(0); 3947dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 3948dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mValues.getAsLong(RawContacts.STARRED) != 0); 3949dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3950dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 3951dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana cursor.close(); 3952dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3953dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3954dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 39558c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // Copy changeable values to prevent automatically managed fields from 39568c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // being explicitly updated by clients. 39578c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 3958b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 39598c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 3960b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 39618c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 3962b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 39638c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 3964b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 39658c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 3966b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 39678c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.STARRED); 39688c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 39699b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori int rslt = mDb.update(Tables.CONTACTS, mValues, Contacts._ID + "=?", mSelectionArgs1); 39706e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori 39719b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori if (values.containsKey(Contacts.LAST_TIME_CONTACTED) && 39729b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori !values.containsKey(Contacts.TIMES_CONTACTED)) { 39739b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 39749b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 39759b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori } 39769b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori return rslt; 3977f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 3978d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 3979127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 3980127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 39810c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1); 39820c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2); 398380c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 3984ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId1; 3985ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId2; 39860c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (rcId1 < rcId2) { 39870c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId1; 39880c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId2; 39890c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 39900c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId1; 39910c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId2; 3992b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3993127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 39940c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 39954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[0] = String.valueOf(rawContactId1); 39964da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[1] = String.valueOf(rawContactId2); 39970c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, 39984da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov AggregationExceptions.RAW_CONTACT_ID1 + "=? AND " 39994da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2); 40000c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 40016bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 40026bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 40030c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 40040c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 40050c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 40060c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues); 4007127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 4008127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 40093389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov mContactAggregator.invalidateAggregationExceptionCache(); 401069cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId1, 401169cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 401269cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId2, 401369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 4014dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov 4015bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateContact(mTransactionContext, db, rawContactId1); 4016bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateContact(mTransactionContext, db, rawContactId2); 4017127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 4018127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 4019127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 4020127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 4021b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4022b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 402370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong public void onAccountsUpdated(Account[] accounts) { 4024bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 40253826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 40263826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4027bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected boolean updateAccountsInBackground(Account[] accounts) { 4028f8536aaa7a52b9a7a353bc54e158becdbe79ec87Bai Tao // TODO : Check the unit test. 4029e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov boolean accountsChanged = false; 4030627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov HashSet<Account> existingAccounts = new HashSet<Account>(); 403149d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov mDb = mDbHelper.getWritableDatabase(); 403270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.beginTransaction(); 403370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong try { 4034dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana findValidAccounts(existingAccounts); 4035743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov 4036743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov // Add a row to the ACCOUNTS table for each new account 4037743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov for (Account account : accounts) { 4038743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov if (!existingAccounts.contains(account)) { 4039e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 4040743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov mDb.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 4041743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov + ", " + RawContacts.ACCOUNT_TYPE + ") VALUES (?, ?)", 4042743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov new String[] {account.name, account.type}); 4043743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 4044743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 404548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 4046627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov // Remove all valid accounts from the existing account set. What is left 4047743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov // in the accountsToDelete set will be extra accounts whose data must be deleted. 4048627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov HashSet<Account> accountsToDelete = new HashSet<Account>(existingAccounts); 4049627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (Account account : accounts) { 4050627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov accountsToDelete.remove(account); 405170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 405270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong 405333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov if (!accountsToDelete.isEmpty()) { 4054e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 4055e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov for (Account account : accountsToDelete) { 4056e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov Log.d(TAG, "removing data for removed account " + account); 4057e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov String[] params = new String[] {account.name, account.type}; 4058e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4059e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.GROUPS + 4060e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Groups.ACCOUNT_NAME + " = ?" + 4061e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + Groups.ACCOUNT_TYPE + " = ?", params); 4062e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4063e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.PRESENCE + 4064e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" + 4065e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "SELECT " + RawContacts._ID + 4066e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 4067e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 4068e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + RawContacts.ACCOUNT_TYPE + " = ?)", params); 4069e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4070e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.RAW_CONTACTS + 4071e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 4072e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + RawContacts.ACCOUNT_TYPE + " = ?", params); 4073e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4074e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.SETTINGS + 4075e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Settings.ACCOUNT_NAME + " = ?" + 4076e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + Settings.ACCOUNT_TYPE + " = ?", params); 4077e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4078e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.ACCOUNTS + 4079e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + "=?" + 4080e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " AND " + RawContacts.ACCOUNT_TYPE + "=?", params); 4081d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov mDb.execSQL( 4082d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov "DELETE FROM " + Tables.DIRECTORIES + 4083d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov " WHERE " + Directory.ACCOUNT_NAME + "=?" + 4084d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov " AND " + Directory.ACCOUNT_TYPE + "=?", params); 40854458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov resetDirectoryCache(); 4086e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 4087e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov 408833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // Find all aggregated contacts that used to contain the raw contacts 408933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // we have just deleted and see if they are still referencing the deleted 4090e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov // names or photos. If so, fix up those contacts. 409133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov HashSet<Long> orphanContactIds = Sets.newHashSet(); 409233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Cursor cursor = mDb.rawQuery("SELECT " + Contacts._ID + 409333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " FROM " + Tables.CONTACTS + 409433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " WHERE (" + Contacts.NAME_RAW_CONTACT_ID + " NOT NULL AND " + 409569cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov Contacts.NAME_RAW_CONTACT_ID + " NOT IN " + 409669cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + RawContacts._ID + 409769cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + "))" + 409833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " OR (" + Contacts.PHOTO_ID + " NOT NULL AND " + 409933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Contacts.PHOTO_ID + " NOT IN " + 410069cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + Data._ID + 410169cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.DATA + "))", null); 410233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov try { 410333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov while (cursor.moveToNext()) { 410433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov orphanContactIds.add(cursor.getLong(0)); 410533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 410633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } finally { 410733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov cursor.close(); 410833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 410933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 411033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov for (Long contactId : orphanContactIds) { 4111bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.updateAggregateData(mTransactionContext, contactId); 411233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 4113e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDbHelper.updateAllVisible(); 4114bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 411533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 411633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 4117e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov if (accountsChanged) { 4118e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDbHelper.getSyncState().onAccountsChanged(mDb, accounts); 4119e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 412070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.setTransactionSuccessful(); 412170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } finally { 412270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.endTransaction(); 412370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 412473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.clear(); 41253826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 41263826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (accountsChanged) { 41273826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateContactsAccountCount(accounts); 41283826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 41293826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41303826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4131afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov return accountsChanged; 413270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 4133619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 41343826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateContactsAccountCount(Account[] accounts) { 41353826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov int count = 0; 41363826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov for (Account account : accounts) { 41373826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (isContactsAccount(account)) { 41383826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov count++; 41393826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41403826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41413826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mContactsAccountCount = count; 41423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 41443826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov protected boolean isContactsAccount(Account account) { 41453826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov final IContentService cs = ContentResolver.getContentService(); 41463826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov try { 41473826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0; 41483826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } catch (RemoteException e) { 41493826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov Log.e(TAG, "Cannot obtain sync flag for account: " + account, e); 41503826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return false; 41513826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 41533826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 415472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void onPackageChanged(String packageName) { 4155bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_DIRECTORIES, packageName); 4156d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4157d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4158619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 4159627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov * Finds all distinct accounts present in the specified table. 4160627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov */ 4161dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void findValidAccounts(Set<Account> validAccounts) { 4162743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov Cursor c = mDb.rawQuery( 4163743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov "SELECT " + RawContacts.ACCOUNT_NAME + "," + RawContacts.ACCOUNT_TYPE + 4164743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov " FROM " + Tables.ACCOUNTS, null); 4165627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 4166627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov while (c.moveToNext()) { 4167dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!c.isNull(0) || !c.isNull(1)) { 4168627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov validAccounts.add(new Account(c.getString(0), c.getString(1))); 4169627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4170627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4171627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } finally { 4172627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov c.close(); 4173627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4174627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4175627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov 41764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 41774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 41784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 417915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 418015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mReadAccessLatch); 418115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 4182d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY); 4183385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directory == null) { 41843716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 41856ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1, false)); 4186385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directory.equals("0")) { 41873716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 41883716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 41896ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Directory.DEFAULT, false)); 4190d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } else if (directory.equals("1")) { 41913716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 41923716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 41936ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Directory.LOCAL_INVISIBLE, false)); 4194d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4195d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4196d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov DirectoryInfo directoryInfo = getDirectoryAuthority(directory); 4197d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo == null) { 4198a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov Log.e(TAG, "Invalid directory ID: " + uri); 4199a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov return null; 4200d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4201d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4202d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Builder builder = new Uri.Builder(); 4203d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.scheme(ContentResolver.SCHEME_CONTENT); 4204d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.authority(directoryInfo.authority); 4205d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.encodedPath(uri.getEncodedPath()); 4206d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountName != null) { 4207d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName); 4208d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4209d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountType != null) { 4210d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType); 4211d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 42122e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 42132e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limit = getLimit(uri); 42142e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov if (limit != null) { 42152e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit); 42162e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov } 42172e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 4218d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Uri directoryUri = builder.build(); 421909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 422009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov if (projection == null) { 422109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov projection = getDefaultProjection(uri); 422209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 422309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 4224332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov Cursor cursor = getContext().getContentResolver().query(directoryUri, projection, selection, 4225d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov selectionArgs, sortOrder); 42266ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 42276ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (cursor == null) { 42286ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 42296ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42306ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 4231547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro CrossProcessCursor crossProcessCursor = getCrossProcessCursor(cursor); 4232547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (crossProcessCursor != null) { 4233547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return wrapCursor(uri, cursor); 4234547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } else { 4235547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return matrixCursorFromCursor(wrapCursor(uri, cursor)); 4236547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 42373716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 42383716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4239547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro private Cursor wrapCursor(Uri uri, Cursor cursor) { 4240547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 4241547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro // If the cursor doesn't contain a snippet column, don't bother wrapping it. 4242547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (cursor.getColumnIndex(SearchSnippetColumns.SNIPPET) < 0) { 4243547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return cursor; 4244547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 4245547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 42463716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Parse out snippet arguments for use when snippets are retrieved from the cursor. 42473716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String[] args = null; 42483716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String snippetArgs = 42493716f1447ceb21180d1301790eabd8b9453f486dDave Santoro getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 42503716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (snippetArgs != null) { 42513716f1447ceb21180d1301790eabd8b9453f486dDave Santoro args = snippetArgs.split(","); 42523716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 42533716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 42543716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String query = uri.getLastPathSegment(); 42553716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String startMatch = args != null && args.length > 0 ? args[0] 42563716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_START_MATCH; 42573716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String endMatch = args != null && args.length > 1 ? args[1] 42583716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_END_MATCH; 42593716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String ellipsis = args != null && args.length > 2 ? args[2] 42603716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_ELLIPSIS; 42613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 42623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 42633716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4264547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return new SnippetizingCursorWrapper(cursor, query, startMatch, endMatch, ellipsis, 4265547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro maxTokens); 42666ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42676ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 42686ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov private CrossProcessCursor getCrossProcessCursor(Cursor cursor) { 42696ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov Cursor c = cursor; 42706ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (c instanceof CrossProcessCursor) { 42716ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return (CrossProcessCursor) c; 42726ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else if (c instanceof CursorWindow) { 42736ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return getCrossProcessCursor(((CursorWrapper) c).getWrappedCursor()); 42746ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else { 42756ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 42766ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42776ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42786ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 42796ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov public MatrixCursor matrixCursorFromCursor(Cursor cursor) { 42806ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); 42816ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov int numColumns = cursor.getColumnCount(); 42826ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov String data[] = new String[numColumns]; 42836ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov cursor.moveToPosition(-1); 42846ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov while (cursor.moveToNext()) { 42856ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov for (int i = 0; i < numColumns; i++) { 42866ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov data[i] = cursor.getString(i); 42876ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 42886ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov newCursor.addRow(data); 4289332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov } 42906ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return newCursor; 4291d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4292d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4293d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final class DirectoryQuery { 4294d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final String[] COLUMNS = new String[] { 4295d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory._ID, 4296d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.DIRECTORY_AUTHORITY, 4297d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_NAME, 4298d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_TYPE 4299d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov }; 4300d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4301d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int DIRECTORY_ID = 0; 4302d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int AUTHORITY = 1; 4303d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_NAME = 2; 4304d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_TYPE = 3; 4305d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4306d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4307d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 4308d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Reads and caches directory information for the database. 4309d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 4310d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private DirectoryInfo getDirectoryAuthority(String directoryId) { 43114458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized (mDirectoryCache) { 43124458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov if (!mDirectoryCacheValid) { 43134458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.clear(); 431449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov SQLiteDatabase db = mDbHelper.getReadableDatabase(); 431549d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Cursor cursor = db.query(Tables.DIRECTORIES, 43164458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryQuery.COLUMNS, 43174458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov null, null, null, null, null); 43184458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov try { 43194458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov while (cursor.moveToNext()) { 43204458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryInfo info = new DirectoryInfo(); 43214458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov String id = cursor.getString(DirectoryQuery.DIRECTORY_ID); 43224458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.authority = cursor.getString(DirectoryQuery.AUTHORITY); 43234458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME); 43244458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE); 43254458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.put(id, info); 43264458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 43274458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } finally { 43284458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov cursor.close(); 4329d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 43304458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = true; 4331d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4332d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 43334458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov return mDirectoryCache.get(directoryId); 43344458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 4335d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4336d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 433772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void resetDirectoryCache() { 43384458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized(mDirectoryCache) { 43394458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = false; 43404458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 434172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 434272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 43436ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private Cursor queryLocal(Uri uri, String[] projection, String selection, 43446ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro String[] selectionArgs, String sortOrder, long directoryId, 43454b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki final boolean suppressProfileCheck) { 4346bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 4347bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov Log.v(TAG, "query: " + uri); 4348bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov } 43490b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov 4350b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 435135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4352d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 43531f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 4354c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov String limit = getLimit(uri); 4355c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 43564b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki // Column name for appendProfileRestriction(). We append the profile check to the original 43574b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki // selection if it's not null. 43584b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki String profileRestrictionColumnName = null; 43594b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki 4360a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 43614f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 436235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 4363b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().query(db, projection, selection, selectionArgs, 436435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana sortOrder); 436535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4366d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 4367763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 43684b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki appendLocalDirectorySelectionIfNeeded(qb, directoryId); 43694b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki profileRestrictionColumnName = Contacts.IS_USER_PROFILE; 43706ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro sortOrder = prependProfileSortIfNeeded(uri, sortOrder, suppressProfileCheck); 4371619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 4372619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 4373619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 4374d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 43754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 4376afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 4377763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 43784da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 43794da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 43806bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 43816bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 43826bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 43835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP: 43845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP_ID: { 43855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 43865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = pathSegments.size(); 43875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount < 3) { 4388fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 4389fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 43905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 4391a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 43925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String lookupKey = pathSegments.get(2); 43935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount == 4) { 43945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4395afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 43965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4397763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 4398a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4399a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4400a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4401a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 4402a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 44035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return c; 44045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 44055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 44065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 4407763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 44084da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 44094da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 44104da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 44115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 44125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 44135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 44142149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_DATA: 44152149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_ID_DATA: { 44162149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 44172149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov int segmentCount = pathSegments.size(); 44182149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount < 4) { 44192149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 44202149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov "Missing a lookup key", uri)); 44212149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44222149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov String lookupKey = pathSegments.get(2); 44232149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount == 5) { 44242149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4425afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44262149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 44272149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(lookupQb, uri, projection, false); 4428a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 4429a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4430a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4431a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Data.CONTACT_ID, contactId, Data.LOOKUP_KEY, lookupKey); 4432a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 44332149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov return c; 44342149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44352149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 44362149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov // TODO see if the contact exists but has no data rows (rare) 44372149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44382149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 44392149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 444024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 4441afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44422149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 444324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 44442149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov qb.appendWhere(" AND " + Data.CONTACT_ID + "=?"); 44452149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov break; 44462149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 44472149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 44483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_ID_STREAM_ITEMS: { 44493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4450afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 44523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 44533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContactsColumns.CONCRETE_CONTACT_ID + "=?"); 44543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 44553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 44573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_STREAM_ITEMS: 44583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_ID_STREAM_ITEMS: { 44593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<String> pathSegments = uri.getPathSegments(); 44603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int segmentCount = pathSegments.size(); 44613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount < 4) { 44623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new IllegalArgumentException(mDbHelper.exceptionMessage( 44633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann "Missing a lookup key", uri)); 44643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String lookupKey = pathSegments.get(2); 44663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount == 5) { 44673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(pathSegments.get(3)); 4468afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 44703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(lookupQb); 44713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 44723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann projection, selection, selectionArgs, sortOrder, groupBy, limit, 44733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RawContacts.CONTACT_ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 44743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c != null) { 44753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return c; 44763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 44793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 44803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = lookupContactIdByLookupKey(db, lookupKey); 4481afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 44823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 44833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContacts.CONTACT_ID + "=?"); 44843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 44853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 44863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4487f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: { 448842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKey = Uri.encode(uri.getPathSegments().get(2)); 448924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 4490afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 4491ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 4492f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey qb.setProjectionMap(sContactsVCardProjectionMap); 44934da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 449424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 44954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 4496f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey break; 4497f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey } 4498f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey 449942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 450042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); 450142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann String currentDateString = dateFormat.format(new Date()).toString(); 450242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann return db.rawQuery( 450342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann "SELECT" + 450442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " 'vcards_' || ? || '.vcf' AS " + OpenableColumns.DISPLAY_NAME + "," + 450542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " NULL AS " + OpenableColumns.SIZE, 450642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann new String[] { currentDateString }); 450742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 450842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 4509ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_FILTER: { 4510916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov String filterParam = ""; 4511ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 4512916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov filterParam = uri.getLastPathSegment(); 4513ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 45147ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov setTablesAndProjectionMapForContactsWithSnippet( 45157ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov qb, uri, projection, filterParam, directoryId); 45164b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki profileRestrictionColumnName = Contacts.IS_USER_PROFILE; 45176ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro sortOrder = prependProfileSortIfNeeded(uri, sortOrder, suppressProfileCheck); 4518ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4519ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4520ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 4521ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT_FILTER: 4522ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT: { 45232f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Basically the resultant SQL should look like this: 45242f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing starred items) 45252f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 45262f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing frequently contacted items) 45272f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // ORDER BY ... 45282f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 45292f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final boolean phoneOnly = readBooleanQueryParameter( 45302f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa uri, ContactsContract.STREQUENT_PHONE_ONLY, false); 45312f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (match == CONTACTS_STREQUENT_FILTER && uri.getPathSegments().size() > 3) { 45324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 45334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4534e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(Contacts._ID + " IN "); 45355e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov appendContactFilterAsNestedQuery(sb, filterParam); 45362f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection = DbQueryUtils.concatenateClauses(selection, sb.toString()); 45374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 45384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 45392f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] subProjection = null; 45405e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection != null) { 45412f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa subProjection = appendProjectionArg(projection, TIMES_USED_SORT_COLUMN); 45425e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 45435e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 45444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov // Build the first query for starred 45454928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 45464928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(phoneOnly ? 45474928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa sStrequentPhoneOnlyStarredProjectionMap 45484928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa : sStrequentStarredProjectionMap); 45492f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 45502f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection, Contacts.IS_USER_PROFILE + "=0")); 45512f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 45522f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String starredQuery = qb.buildQuery(subProjection, 455324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Contacts.STARRED + "=1", Contacts._ID, null, null, null); 4554d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 45552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Reset the builder. 4556d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 45572f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 45584928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 45594928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // Build the second query for frequent part. 45604928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final String frequentQuery; 45614928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (phoneOnly) { 45624928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final StringBuilder tableBuilder = new StringBuilder(); 45634928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // In phone only mode, we need to look at view_data instead of 45644928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // contacts/raw_contacts to obtain actual phone numbers. One problem is that 45654928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data is much larger than view_contacts, so our query might become much 45664928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // slower. 45674928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // 45684928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // To avoid the possible slow down, we start from data usage table and join 45694928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data to the table, assuming data usage table is quite smaller than 45704928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // data rows (almost always it should be), and we don't want any phone 45714928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // numbers not used by the user. This way sqlite is able to drop a number of 45724928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // rows in view_data in the early stage of data lookup. 45734928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa tableBuilder.append(Tables.DATA_USAGE_STAT 45744928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " INNER JOIN " + Views.DATA + " " + Tables.DATA 45754928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" 45764928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataColumns.CONCRETE_ID + " AND " 45774928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" 45784928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT_CALL + ")"); 45794928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactPresenceJoin(tableBuilder, projection, RawContacts.CONTACT_ID); 45804928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactStatusUpdateJoin(tableBuilder, projection, 45814928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa ContactsColumns.LAST_STATUS_UPDATE_ID); 45824928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 45834928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setTables(tableBuilder.toString()); 45844928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentPhoneOnlyFrequentProjectionMap); 45854928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 45864928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 45874928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.STARRED + "=0 OR " + Contacts.STARRED + " IS NULL", 45884928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa MimetypesColumns.MIMETYPE + " IN (" 45894928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + Phone.CONTENT_ITEM_TYPE + "', " 45904928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + SipAddress.CONTENT_ITEM_TYPE + "')")); 45914928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, null, null, null, null, null); 45924928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } else { 45934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 45944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 45954928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 45964928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 45974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa "(" + Contacts.STARRED + " =0 OR " + Contacts.STARRED + " IS NULL)", 45984928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.IS_USER_PROFILE + "=0")); 45994928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, 46004928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa null, Contacts._ID, null, null, null); 46014928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } 4602d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 4603d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 46042f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String unionQuery = 46052f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, 46062f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa STREQUENT_ORDER_BY, STREQUENT_LIMIT); 46072f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 46082f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Here, we need to use selection / selectionArgs (supplied from users) "twice", 46092f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // as we want them both for starred items and for frequently contacted items. 46102f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // 46112f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // e.g. if the user specify selection = "starred =?" and selectionArgs = "0", 46122f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // the resultant SQL should be like: 46132f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 46142f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 46152f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 46162f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] doubledSelectionArgs = null; 46172f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (selectionArgs != null) { 46182f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final int length = selectionArgs.length; 46192f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa doubledSelectionArgs = new String[length * 2]; 46207d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, 0, length); 46217d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, length, length); 46222f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 46232f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 46242f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa Cursor cursor = db.rawQuery(unionQuery, doubledSelectionArgs); 46252f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (cursor != null) { 46262f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa cursor.setNotificationUri(getContext().getContentResolver(), 4627d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 4628d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 46292f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa return cursor; 4630d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 4631d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 463245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa case CONTACTS_FREQUENT: { 463345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 463445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 4635363bdaba2994539e1a3a2342a9fcf223604d69eaDaisuke Miyakawa qb.appendWhere(Contacts.IS_USER_PROFILE + "=0"); 463645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa groupBy = Contacts._ID; 463745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa if (!TextUtils.isEmpty(sortOrder)) { 463845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY + ", " + sortOrder; 463945ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } else { 464045ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY; 464145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 464245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa break; 464345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 464445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 4645ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_GROUP: { 4646763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 4647b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 464871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 46494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 4650b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4651b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 4652b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4653b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 465424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 465524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 465624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 465724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(Contacts.IS_USER_PROFILE + "=1"); 465824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 465924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 466024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 466124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: { 466224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 466324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForEntities(qb, uri, projection); 466424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + Contacts.IS_USER_PROFILE + "=1"); 466524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 466624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 466724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 466824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: { 466924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 467024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 467124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 467224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 467324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 467424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 467524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA_ID: { 467624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 467724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 467824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 467924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + Data._ID + "=? AND " 468024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 468124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 468224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 468324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 468424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: { 468524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 4686ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 468724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.setProjectionMap(sContactsVCardProjectionMap); 468824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(Contacts.IS_USER_PROFILE + "=1"); 468924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 469024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 469124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 4692a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_DATA: { 46934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 469482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 46954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 46964da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 46976bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 46986bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 469900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 4700a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 47013653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4702afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 470382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 47044da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 47054da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 47063653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 47073653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov break; 47083653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov } 47093653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 4710a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_ENTITIES: { 4711a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4712a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 4713a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 4714a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 4715a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 4716a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4717a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4718a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ENTITIES: 4719a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ID_ENTITIES: { 4720a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 4721a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov int segmentCount = pathSegments.size(); 4722a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount < 4) { 4723a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 4724a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov "Missing a lookup key", uri)); 4725a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4726a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lookupKey = pathSegments.get(2); 4727a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount == 5) { 4728a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4729a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4730a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(lookupQb, uri, projection); 4731a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 4732a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4733a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4734a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4735a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.CONTACT_ID, contactId, 4736a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.LOOKUP_KEY, lookupKey); 4737a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 4738a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 4739a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4740a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4741a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4742a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 4743a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 4744a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 4745a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + Contacts.Entity.CONTACT_ID + "=?"); 4746a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 4747a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4748a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 47493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 47503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 47513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 47553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 47563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 47573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemsColumns.CONCRETE_ID + "=?"); 47583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_LIMIT: { 47626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro MatrixCursor cursor = new MatrixCursor(new String[]{StreamItems.MAX_ITEMS}, 1); 47636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro cursor.addRow(new Object[]{MAX_STREAM_ITEMS_PER_RAW_CONTACT}); 47643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return cursor; 47653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 47683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 47693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 47733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 47743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 47753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 47763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?"); 47773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 47813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 47823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 47833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 47843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemPhotoId); 47853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 47863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=? AND " + 47873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=?"); 47883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4791f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case PHOTO_DIMENSIONS: { 4792f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro MatrixCursor cursor = new MatrixCursor( 4793f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM}, 4794f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1); 4795f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cursor.addRow(new Object[]{mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim}); 4796f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return cursor; 4797f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 4798f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 47994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case PHONES: { 480082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 480189c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 48022815f58f72f109790585931f601a63ddc02536a5Evan Millar break; 48032815f58f72f109790585931f601a63ddc02536a5Evan Millar } 48042815f58f72f109790585931f601a63ddc02536a5Evan Millar 480548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: { 480682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 48074da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 480848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 48094da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 481048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 481148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 481248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 4813ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES_FILTER: { 481446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 481546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 481646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 481746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_CALL; 481846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 481946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 482089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 4821ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 48224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 48234a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4824a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(" AND ("); 48255e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 482645d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov boolean hasCondition = false; 48275e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov boolean orNeeded = false; 48285e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov String normalizedName = NameNormalizer.normalize(filterParam); 48295e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (normalizedName.length() > 0) { 4830155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(Data.RAW_CONTACT_ID + " IN " + 4831155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 4832155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 4833155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 4834155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 4835155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 4836155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 48372352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 4838155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 48395e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov orNeeded = true; 484045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 48415e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 48425e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 4843892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String number = PhoneNumberUtils.normalizeNumber(filterParam); 4844892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (!TextUtils.isEmpty(number)) { 48455e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (orNeeded) { 48465e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(" OR "); 48475e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 48485e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(Data._ID + 4849892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID 4850892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " FROM " + Tables.PHONE_LOOKUP 4851892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 4852892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append(number); 4853892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append("%')"); 485445d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 485545d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov } 485645d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov 485745d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov if (!hasCondition) { 485845d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // If it is neither a phone number nor a name, the query should return 485945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // an empty cursor. Let's ensure that. 486045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov sb.append("0"); 48615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 48625e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 4863a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 4864ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 48655e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = PhoneColumns.NORMALIZED_NUMBER + "," + RawContacts.CONTACT_ID; 4866a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 486746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 486846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 486946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + PHONE_FILTER_SORT_ORDER; 487046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 487146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = PHONE_FILTER_SORT_ORDER; 487246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 4873a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 4874ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4875ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4876ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 48774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case EMAILS: { 487882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 487989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 48804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov break; 48814a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 48824a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 488348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: { 488482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 48854da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 48864da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'" 48874da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + " AND " + Data._ID + "=?"); 488848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 488948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 489048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 48915e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_LOOKUP: { 489282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 489389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 48944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov if (uri.getPathSegments().size() > 2) { 489508768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String email = uri.getLastPathSegment(); 489608768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String address = mDbHelper.extractAddressFromEmailAddress(email); 489708768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, address); 489808768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)"); 48994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 4900ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4901ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4902ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 49035e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_FILTER: { 490446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 490546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 490646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 490746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT; 490846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 490946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 491007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov String filterParam = null; 49117d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa 491207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 491307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = uri.getLastPathSegment(); 491407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (TextUtils.isEmpty(filterParam)) { 491507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = null; 491607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 491707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 49185e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 491907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (filterParam == null) { 492007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov // If the filter is unspecified, return nothing 492107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov qb.appendWhere(" AND 0"); 492207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } else { 492307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov StringBuilder sb = new StringBuilder(); 492407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append(" AND " + Data._ID + " IN ("); 492507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append( 492607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov "SELECT " + Data._ID + 492707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov " FROM " + Tables.DATA + 49282a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov " WHERE " + DataColumns.MIMETYPE_ID + "="); 49292a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(mDbHelper.getMimeTypeIdForEmail()); 49302a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(" AND " + Data.DATA1 + " LIKE "); 493107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 493220938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov if (!filterParam.contains("@")) { 4933155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append( 4934155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " UNION SELECT " + Data._ID + 4935155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.DATA + 4936155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE +" + DataColumns.MIMETYPE_ID + "="); 4937155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(mDbHelper.getMimeTypeIdForEmail()); 4938155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(" AND " + Data.RAW_CONTACT_ID + " IN " + 4939155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 4940155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 4941155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 4942155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 4943155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 4944155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 49452352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 4946155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 49475e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49485e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 4949a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 49505e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49515e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = Email.DATA + "," + RawContacts.CONTACT_ID; 4952a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 495346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 495446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 495546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + EMAIL_FILTER_SORT_ORDER; 49567d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } else { 49577d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa sortOrder = EMAIL_FILTER_SORT_ORDER; 49587d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } 4959a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 49605e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov break; 49615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49625e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 4963ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 496482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 496589c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 496689c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 4967ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4968ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4969ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 497048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 497182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 49724da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 497348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 497448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 49754da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 497648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 497748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 497848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 49795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 4980763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 49814b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki profileRestrictionColumnName = RawContacts.RAW_CONTACT_IS_USER_PROFILE; 49824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 49834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 49844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 49855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 49865ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 4987afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 4988763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 49894da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 49904da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 49914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 49924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 49934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 49945ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 49955ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 499682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 49974da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 49984da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?"); 49994b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki profileRestrictionColumnName = RawContacts.RAW_CONTACT_IS_USER_PROFILE; 500024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 500124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 500224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 50033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 50043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5005afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 50063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 50073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 50083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=?"); 50093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 50103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 501124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 501224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 501324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 501424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 501524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 501624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 501724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 501824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 501924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: { 502024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 502124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = ContentUris.parseId(uri); 502224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 502324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 502424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 502524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts._ID + "=?"); 502624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 502724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 502824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 502924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 503024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 503124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 503224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 503324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 503424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 503524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + Data.RAW_CONTACT_ID + "=?"); 503624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 503724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 503824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 503924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_ENTITIES: { 504024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 504124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 504224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 504324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawEntities(qb, uri); 504424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 504524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts._ID + "=?"); 5046e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5047e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5048e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 5049e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey case DATA: { 505082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50514b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki profileRestrictionColumnName = RawContacts.RAW_CONTACT_IS_USER_PROFILE; 5052e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5053e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5054e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 50554f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case DATA_ID: { 505624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = ContentUris.parseId(uri); 5057afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForData(db, dataId, false); 505882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 50604da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 5061a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov break; 5062a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov } 5063a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov 5064a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 50654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 5066a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton if (TextUtils.isEmpty(sortOrder)) { 5067a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Default the sort order to something reasonable so we get consistent 5068a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // results when callers don't request an ordering 5069892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sortOrder = " length(lookup.normalized_number) DESC"; 5070a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5071a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5072e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : ""; 5073e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov String numberE164 = PhoneNumberUtils.formatNumberToE164(number, 5074e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov mDbHelper.getCurrentCountryIso()); 5075892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String normalizedNumber = 5076892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov PhoneNumberUtils.normalizeNumber(number); 5077892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov mDbHelper.buildPhoneLookupAndContactQuery(qb, normalizedNumber, numberE164); 5078e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov qb.setProjectionMap(sPhoneLookupProjectionMap); 5079e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov // Phone lookup cannot be combined with a selection 5080e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selection = null; 5081e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selectionArgs = null; 5082a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 5083a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5084a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5085ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 5086ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5087ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 508889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov appendAccountFromParameter(qb, uri); 5089ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5090ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5091ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5092ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 5093ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5094ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 50954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 50964da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Groups._ID + "=?"); 5097ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5098ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5099ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5100ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 5101f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa final boolean returnGroupCountPerAccount = 5102f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa readBooleanQueryParameter(uri, Groups.PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT, 5103f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa false); 5104f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa qb.setTables(Views.GROUPS + " AS " + Tables.GROUPS); 5105f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa qb.setProjectionMap(returnGroupCountPerAccount ? 5106f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa sGroupsSummaryProjectionMapWithGroupCountPerAccount 5107f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa : sGroupsSummaryProjectionMap); 510889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov appendAccountFromParameter(qb, uri); 5109f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa groupBy = GroupsColumns.CONCRETE_ID; 5110ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5111ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5112ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5113b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 51140c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS); 5115b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 5116b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 5117b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 5118b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 511931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 5120d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 51212d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov String filter = null; 51222d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 51232d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov filter = uri.getPathSegments().get(3); 51242d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov } 512531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 5126d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov if (limit != null) { 5127d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov maxSuggestions = Integer.parseInt(limit); 512831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 512931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 513031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 513131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 51325b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ArrayList<AggregationSuggestionParameter> parameters = null; 51335b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov List<String> query = uri.getQueryParameters("query"); 51345b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov if (query != null && !query.isEmpty()) { 51355b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters = new ArrayList<AggregationSuggestionParameter>(query.size()); 51365b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov for (String parameter : query) { 51375b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov int offset = parameter.indexOf(':'); 51385b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters.add(offset == -1 51395b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ? new AggregationSuggestionParameter( 514076dfa406e2cde19c824983c37fc92c1c5bf63eecDaniel Lehmann AggregationSuggestions.PARAMETER_MATCH_NAME, 51415b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter) 51425b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov : new AggregationSuggestionParameter( 51435b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(0, offset), 51445b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(offset + 1))); 51455b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 51465b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 51475b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 5148763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 51497581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov 51507581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov return mContactAggregator.queryAggregationSuggestions(qb, projection, contactId, 51515b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov maxSuggestions, filter, parameters); 515231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 515331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 5154eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 5155eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setTables(Tables.SETTINGS); 5156eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setProjectionMap(sSettingsProjectionMap); 515789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov appendAccountFromParameter(qb, uri); 5158e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5159e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // When requesting specific columns, this query requires 5160e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // late-binding of the GroupMembership MIME-type. 5161b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final String groupMembershipMimetypeId = Long.toString(mDbHelper 5162e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 516382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 5164b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.isInProjection(projection, Settings.UNGROUPED_COUNT)) { 5165e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5166e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 516782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 5168b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.isInProjection(projection, Settings.UNGROUPED_WITH_PHONES)) { 5169e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5170e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 5171e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5172eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 5173eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 5174eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 517582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 51760a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 51775ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 51785ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 51795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 518082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES_ID: { 51810a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 51824da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 51834da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(DataColumns.CONCRETE_ID + "=?"); 51845ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 51855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 51865ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 5187c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: { 5188174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchSuggestionsQuery( 5189174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, uri, projection, limit); 5190c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5191c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 5192c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: { 51932d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill String lookupKey = uri.getLastPathSegment(); 5194174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String filter = getQueryParameter( 5195174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov uri, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 5196174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchShortcutRefresh( 5197174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, projection, lookupKey, filter); 5198c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5199c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 52001b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS: 5201ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 52021b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 52031b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 52041b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 52051b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_WITH_PHONES: 5206ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 52071b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 52081b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1"); 52091b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 52101b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 52111b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_FAVORITES: 5212ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 52131b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 52141b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.STARRED + "=1"); 52151b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 52161b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 52171b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_GROUP_NAME: 5218ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 52191b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 522071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 52211b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 52221b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 52231b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 522446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITIES: { 5225a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 522646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 522746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 522846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 522946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITY_ID: { 523046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5231a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 52324da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 52334da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 523446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 523546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 523646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 523709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov case PROVIDER_STATUS: { 523809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return queryProviderStatus(uri, projection); 523909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 524009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5241d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES : { 5242d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5243d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5244d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5245d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5246d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 5247d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID : { 5248385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov long id = ContentUris.parseId(uri); 5249d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5250d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5251385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(id)); 5252d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.appendWhere(Directory._ID + "=?"); 5253d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5254d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5255d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 52567a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov case COMPLETE_NAME: { 52577a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return completeName(uri, projection); 52587a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 52597a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 52604f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 5261f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 5262c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov sortOrder, limit); 52634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 52644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 526509e69522745551522c55dff27424496f255def46Daniel Lehmann qb.setStrict(true); 52667f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov 52674b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki if (profileRestrictionColumnName != null) { 52684b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki // This check is very slow and most of the rows will pass though this check, so 52694b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki // it should be put after user's selection, so SQLite won't do this check first. 52704b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki selection = appendProfileRestriction(uri, profileRestrictionColumnName, 52714b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki suppressProfileCheck, selection); 52724b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki } 52734b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki 5274ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov Cursor cursor = 5275ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit); 5276ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) { 5277ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov cursor = bundleLetterCountExtras(cursor, db, qb, selection, selectionArgs, sortOrder); 5278ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5279ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov return cursor; 52805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 52815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 52825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection, 52835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String selection, String[] selectionArgs, String sortOrder, String groupBy, 52845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String limit) { 5285038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana if (projection != null && projection.length == 1 5286038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana && BaseColumns._COUNT.equals(projection[0])) { 5287038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana qb.setProjectionMap(sCountProjectionMap); 5288038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana } 52895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null, 52905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sortOrder, limit); 52914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 52924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 52934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 52944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 52954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 52964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 529709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov /** 529809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov * Creates a single-row cursor containing the current status of the provider. 529909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov */ 530009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private Cursor queryProviderStatus(Uri uri, String[] projection) { 530109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 530209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov RowBuilder row = cursor.newRow(); 530309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov for (int i = 0; i < projection.length; i++) { 530409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov if (ProviderStatus.STATUS.equals(projection[i])) { 530509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mProviderStatus); 530609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } else if (ProviderStatus.DATA1.equals(projection[i])) { 530709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mEstimatedStorageRequirement); 530809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 530909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 531009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return cursor; 531109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 531209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5313a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** 5314a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * Runs the query with the supplied contact ID and lookup ID. If the query succeeds, 5315a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * it returns the resulting cursor, otherwise it returns null and the calling 5316a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * method needs to resolve the lookup key and rerun the query. 5317a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov */ 5318a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private Cursor queryWithContactIdAndLookupKey(SQLiteQueryBuilder lookupQb, 5319a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteDatabase db, Uri uri, 5320a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection, String selection, String[] selectionArgs, 5321a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String sortOrder, String groupBy, String limit, 5322a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn, long contactId, String lookupKeyColumn, String lookupKey) { 5323a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] args; 5324a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (selectionArgs == null) { 5325a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[2]; 5326a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } else { 5327a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[selectionArgs.length + 2]; 5328a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 5329a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5330a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[0] = String.valueOf(contactId); 5331a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[1] = Uri.encode(lookupKey); 5332a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(contactIdColumn + "=? AND " + lookupKeyColumn + "=?"); 5333a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = query(db, lookupQb, projection, selection, args, sortOrder, 5334a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov groupBy, limit); 5335a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c.getCount() != 0) { 5336a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5337a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5338a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5339a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov c.close(); 5340a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return null; 5341a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 534209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5343bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov private static final class AddressBookIndexQuery { 5344bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String LETTER = "letter"; 5345bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String TITLE = "title"; 5346bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String COUNT = "count"; 5347ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5348bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String[] COLUMNS = new String[] { 5349bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov LETTER, TITLE, COUNT 5350ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov }; 5351ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5352bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_LETTER = 0; 5353bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_TITLE = 1; 5354bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_COUNT = 2; 5355bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 535624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The first letter of the sort key column is what is used for the index headings, except 535724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // in the case of the user's profile, in which case it is empty. 535824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro public static final String SECTION_HEADING_TEMPLATE = 535924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "(CASE WHEN %1$s=1 THEN '' ELSE SUBSTR(%2$s,1,1) END)"; 536024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5361de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa public static final String ORDER_BY = LETTER + " COLLATE " + PHONEBOOK_COLLATOR_NAME; 5362ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5363ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5364ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov /** 5365ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * Computes counts by the address book index titles and adds the resulting tally 5366ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * to the returned cursor as a bundle of extras. 5367ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov */ 5368ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov private Cursor bundleLetterCountExtras(Cursor cursor, final SQLiteDatabase db, 5369ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov SQLiteQueryBuilder qb, String selection, String[] selectionArgs, String sortOrder) { 5370ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortKey; 5371ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5372ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // The sort order suffix could be something like "DESC". 5373ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // We want to preserve it in the query even though we will change 5374ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // the sort column itself. 5375ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortOrderSuffix = ""; 5376ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (sortOrder != null) { 537724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 537824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // If the sort order contains one of the "is_profile" columns, we need to strip it out 537924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // first. 538024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (sortOrder.contains(Contacts.IS_USER_PROFILE) 538124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro || sortOrder.contains(RawContacts.RAW_CONTACT_IS_USER_PROFILE)) { 538224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String[] splitOrderClauses = sortOrder.split(","); 538324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro StringBuilder rejoinedClause = new StringBuilder(); 538424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro for (String orderClause : splitOrderClauses) { 538524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!orderClause.contains(Contacts.IS_USER_PROFILE) 538624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro && !orderClause.contains(RawContacts.RAW_CONTACT_IS_USER_PROFILE)) { 538724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (rejoinedClause.length() > 0) { 538824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro rejoinedClause.append(", "); 538924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 539024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro rejoinedClause.append(orderClause.trim()); 539124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 539224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 539324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sortOrder = rejoinedClause.toString(); 539424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 539524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5396ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int spaceIndex = sortOrder.indexOf(' '); 5397ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (spaceIndex != -1) { 5398ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder.substring(0, spaceIndex); 5399ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortOrderSuffix = sortOrder.substring(spaceIndex); 5400ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5401ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder; 5402ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5403ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5404ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = Contacts.SORT_KEY_PRIMARY; 5405ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5406ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5407bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String locale = getLocale().toString(); 5408ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov HashMap<String, String> projectionMap = Maps.newHashMap(); 540924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 541024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The user profile column varies depending on the view. 5411ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann String profileColumn = qb.getTables().contains(Views.CONTACTS) 541224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro ? Contacts.IS_USER_PROFILE 541324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro : RawContacts.RAW_CONTACT_IS_USER_PROFILE; 541424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String sectionHeading = String.format( 541524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro AddressBookIndexQuery.SECTION_HEADING_TEMPLATE, profileColumn, sortKey); 5416bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov projectionMap.put(AddressBookIndexQuery.LETTER, 541724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sectionHeading + " AS " + AddressBookIndexQuery.LETTER); 5418bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5419bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov /** 5420bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * Use the GET_PHONEBOOK_INDEX function, which is an android extension for SQLite3, 5421bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * to map the first letter of the sort key to a character that is traditionally 5422bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * used in phonebooks to represent that letter. For example, in Korean it will 5423bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * be the first consonant in the letter; for Japanese it will be Hiragana rather 5424bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * than Katakana. 5425bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov */ 5426ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.TITLE, 542724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "GET_PHONEBOOK_INDEX(" + sectionHeading + ",'" + locale + "')" 5428bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov + " AS " + AddressBookIndexQuery.TITLE); 5429ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.COUNT, 5430ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov "COUNT(" + Contacts._ID + ") AS " + AddressBookIndexQuery.COUNT); 5431ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov qb.setProjectionMap(projectionMap); 5432ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5433f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs, 5434ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY, null /* having */, 5435ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY + sortOrderSuffix); 5436ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5437ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov try { 5438f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov int groupCount = indexCursor.getCount(); 5439ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String titles[] = new String[groupCount]; 5440ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int counts[] = new int[groupCount]; 5441bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int indexCount = 0; 5442bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String currentTitle = null; 5443bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5444bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // Since GET_PHONEBOOK_INDEX is a many-to-1 function, we may end up 5445bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // with multiple entries for the same title. The following code 5446bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // collapses those duplicates. 5447ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov for (int i = 0; i < groupCount; i++) { 5448f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.moveToNext(); 5449bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String title = indexCursor.getString(AddressBookIndexQuery.COLUMN_TITLE); 5450bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int count = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT); 5451bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount == 0 || !TextUtils.equals(title, currentTitle)) { 5452bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles[indexCount] = currentTitle = title; 5453bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount] = count; 5454bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov indexCount++; 5455bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } else { 5456bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount - 1] += count; 5457bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5458bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5459bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5460bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount < groupCount) { 5461bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String[] newTitles = new String[indexCount]; 5462bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(titles, 0, newTitles, 0, indexCount); 5463bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles = newTitles; 5464bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5465bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int[] newCounts = new int[indexCount]; 5466bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(counts, 0, newCounts, 0, indexCount); 5467bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts = newCounts; 5468ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5469ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5470e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return new AddressBookCursor((CrossProcessCursor) cursor, titles, counts); 5471ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } finally { 5472f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.close(); 5473ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5474ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5475ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 54762d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill /** 547792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Returns the contact Id for the contact identified by the lookupKey. 547892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Robust against changes in the lookup key: if the key has changed, will 547992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * look up the contact by the raw contact IDs or name encoded in the lookup 548092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * key. 54812d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill */ 54822d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) { 54835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey key = new ContactLookupKey(); 54845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments = key.parse(lookupKey); 54855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 548692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov long contactId = -1; 548792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_SOURCE_ID)) { 548892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdBySourceIds(db, segments); 548992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 549092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 549192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 549292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 549392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 549492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov boolean hasRawContactIds = 549592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID); 549692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds) { 549792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdByRawContactIds(db, segments); 549892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 549992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 550092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 550192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 550292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 550392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds 550492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME)) { 55055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = lookupContactIdByDisplayNames(db, segments); 55065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 55095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private interface LookupBySourceIdQuery { 55125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String TABLE = Tables.RAW_CONTACTS; 55135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 55155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 55165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 55175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 55185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.SOURCE_ID 55195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 55205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 55225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_TYPE = 1; 55235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 55245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int SOURCE_ID = 3; 55255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long lookupContactIdBySourceIds(SQLiteDatabase db, 55285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments) { 55295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 55305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(RawContacts.SOURCE_ID + " IN ("); 55315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 55325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 553392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID) { 55345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 55355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 55365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 55395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 55405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS, 55425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 55435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 55445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 55455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountType = c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE); 55465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME); 55475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 55485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey.getAccountHashCode(accountType, accountName); 55495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID); 55505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 55515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 555292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID 555392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 55545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(sourceId)) { 55555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID); 55565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 55575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 55615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 55625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 55655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 556792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByRawContactIdQuery { 556892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.RAW_CONTACTS; 55695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 55715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 55725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 55735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 557492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts._ID, 55755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 55765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 55785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_TYPE = 1; 55795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 558092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ID = 3; 55815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 558392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByRawContactIds(SQLiteDatabase db, 558492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 558592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 558692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(RawContacts._ID + " IN ("); 55875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 55885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 558992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 559092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(segment.rawContactId); 559192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(","); 55925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 559492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 559592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 55965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 559792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov Cursor c = db.query(LookupByRawContactIdQuery.TABLE, LookupByRawContactIdQuery.COLUMNS, 559892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.toString(), null, null, null, null); 559992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov try { 560092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov while (c.moveToNext()) { 560192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountType = c.getString(LookupByRawContactIdQuery.ACCOUNT_TYPE); 560292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountName = c.getString(LookupByRawContactIdQuery.ACCOUNT_NAME); 560392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int accountHashCode = 560492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ContactLookupKey.getAccountHashCode(accountType, accountName); 560592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String rawContactId = c.getString(LookupByRawContactIdQuery.ID); 560692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 560792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 560892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID 560992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 561092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && segment.rawContactId.equals(rawContactId)) { 561192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov segment.contactId = c.getLong(LookupByRawContactIdQuery.CONTACT_ID); 561292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov break; 561392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 561492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 561592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 561692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } finally { 561792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov c.close(); 56185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 562092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return getMostReferencedContactId(segments); 562192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 562292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 562392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByDisplayNameQuery { 562492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS; 562592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 562692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String COLUMNS[] = { 562792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.CONTACT_ID, 562892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 562992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 563092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov NameLookupColumns.NORMALIZED_NAME 563192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov }; 563292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 563392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int CONTACT_ID = 0; 563492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_TYPE = 1; 563592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_NAME = 2; 563692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int NORMALIZED_NAME = 3; 563792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 563892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 563992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByDisplayNames(SQLiteDatabase db, 564092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 56415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 56425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(NameLookupColumns.NORMALIZED_NAME + " IN ("); 56435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 56445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 564592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 564692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 56475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 56485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 56495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 56525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY 56535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov + " AND " + RawContacts.CONTACT_ID + " NOT NULL"); 56545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS, 56565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 56575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 56585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 56595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountType = c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE); 56605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME); 56615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 56625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey.getAccountHashCode(accountType, accountName); 56635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME); 56645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 56655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 566692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if ((segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 566792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) 566892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 56695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(name)) { 56705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID); 56715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 56725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 56765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 56775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 56805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 568292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private boolean lookupKeyContainsType(ArrayList<LookupKeySegment> segments, int lookupType) { 568392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 568492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 568592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == lookupType) { 568692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return true; 568792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 568892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 568992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 569092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return false; 569192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 569292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 5693ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateLookupKeyForRawContact(SQLiteDatabase db, long rawContactId) { 5694ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov mContactAggregator.updateLookupKeyForRawContact(db, rawContactId); 5695ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov } 5696ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov 56975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov /** 56985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov * Returns the contact ID that is mentioned the highest number of times. 56995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov */ 57005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) { 57015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Collections.sort(segments); 57025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 57035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long bestContactId = -1; 57045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int bestRefCount = 0; 57055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 57065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = -1; 57075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int count = 0; 57085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 57095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = segments.size(); 57105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segmentCount; i++) { 57115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 57125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId != -1) { 57135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId == contactId) { 57145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count++; 57155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 57165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 57175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestContactId = contactId; 57185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestRefCount = count; 57195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = segment.contactId; 57215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count = 1; 57225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 57265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 57275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 57285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return bestContactId; 57295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 5732763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 5733763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar String[] projection) { 57344928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 57352f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 57362f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 57372f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 57384928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * @param includeDataUsageStat true when the table should include DataUsageStat table. 57394928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Note that this uses INNER JOIN instead of LEFT OUTER JOIN, so some of data in Contacts 57404928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * may be dropped. 57412f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 57422f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 57434928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa String[] projection, boolean includeDataUsageStat) { 574482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 5745ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 57462f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 57472f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Just for frequently contacted contacts in Strequent Uri handling. 57484928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (includeDataUsageStat) { 57492f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa sb.append(" INNER JOIN " + 5750ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA_USAGE_STAT + " AS " + Tables.DATA_USAGE_STAT + 57512f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa " ON (" + 57522f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DbQueryUtils.concatenateClauses( 57532f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DataUsageStatColumns.CONCRETE_TIMES_USED + " > 0", 57544928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) + 57552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa ")"); 57562f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 57572f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 57587ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 57597ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 5760916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setTables(sb.toString()); 5761916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionMap); 5762916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov } 5763916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 5764916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** 5765916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * Finds name lookup records matching the supplied filter, picks one arbitrary match per 5766916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * contact and joins that with other contacts tables. 5767916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov */ 5768916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private void setTablesAndProjectionMapForContactsWithSnippet(SQLiteQueryBuilder qb, Uri uri, 57697ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov String[] projection, String filter, long directoryId) { 57707ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov 57717ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5772ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 5773916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 577403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (filter != null) { 577503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov filter = filter.trim(); 577603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 577703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 577830cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov if (TextUtils.isEmpty(filter) || (directoryId != -1 && directoryId != Directory.DEFAULT)) { 577930cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov sb.append(" JOIN (SELECT NULL AS " + SearchSnippetColumns.SNIPPET + " WHERE 0)"); 57805e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } else { 57815e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov appendSearchIndexJoin(sb, uri, projection, filter); 57825e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 57837ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 57847ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 578503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setTables(sb.toString()); 578603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionWithSnippetMap); 578703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 5788916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 578903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private void appendSearchIndexJoin( 579003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov StringBuilder sb, Uri uri, String[] projection, String filter) { 5791916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 5792174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET)) { 579303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String[] args = null; 579403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String snippetArgs = 579503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 579603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (snippetArgs != null) { 579703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov args = snippetArgs.split(","); 579803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 579903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 58005e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String startMatch = args != null && args.length > 0 ? args[0] 58015e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_START_MATCH; 58025e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String endMatch = args != null && args.length > 1 ? args[1] 58035e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_END_MATCH; 58045e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String ellipsis = args != null && args.length > 2 ? args[2] 58055e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_ELLIPSIS; 58065e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 58075e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 58085e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 5809174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin( 5810174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb, filter, true, startMatch, endMatch, ellipsis, maxTokens); 5811174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 5812174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin(sb, filter, false, null, null, null, 0); 5813174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5814174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5815174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 5816174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public void appendSearchIndexJoin(StringBuilder sb, String filter, 5817174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean snippetNeeded, String startMatch, String endMatch, String ellipsis, 5818174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int maxTokens) { 5819174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isEmailAddress = false; 5820174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String emailAddress = null; 5821174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isPhoneNumber = false; 5822174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String phoneNumber = null; 5823174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String numberE164 = null; 5824174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 58253716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // If the query consists of a single word, we can do snippetizing after-the-fact for a 58263716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // performance boost. 58273716f1447ceb21180d1301790eabd8b9453f486dDave Santoro boolean singleTokenSearch = filter.split(QUERY_TOKENIZER_REGEX).length == 1; 58283716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 5829174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (filter.indexOf('@') != -1) { 5830174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov emailAddress = mDbHelper.extractAddressFromEmailAddress(filter); 5831174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isEmailAddress = !TextUtils.isEmpty(emailAddress); 5832174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 5833174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isPhoneNumber = isPhoneNumber(filter); 583404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (isPhoneNumber) { 583504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann phoneNumber = PhoneNumberUtils.normalizeNumber(filter); 583604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann numberE164 = PhoneNumberUtils.formatNumberToE164(phoneNumber, 583704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann mDbHelper.getCountryIso()); 583804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 5839174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5840174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 5841174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(" JOIN (SELECT " + SearchIndexColumns.CONTACT_ID + " AS snippet_contact_id"); 5842174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (snippetNeeded) { 58435e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(", "); 58445e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 58453d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 58465e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 584704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Email.ADDRESS + ")"); 584804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + Tables.DATA_JOIN_RAW_CONTACTS); 584904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 585004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID + " AND " + Email.ADDRESS + " LIKE "); 585104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann DatabaseUtils.appendEscapedSQLString(sb, filter + "%"); 585204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 58533d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 58543d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(","); 58553716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 58563716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 58573716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 58583716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 58593716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 58603716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 58613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 58623d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(")"); 58633d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 58643d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 58653d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 586604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Phone.NUMBER + ")"); 586704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + 586804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann Tables.DATA_JOIN_RAW_CONTACTS + " JOIN " + Tables.PHONE_LOOKUP); 586904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" ON " + DataColumns.CONCRETE_ID); 587004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID); 587104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 587204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID); 587304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" AND " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 587404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(phoneNumber); 587504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 587604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(numberE164)) { 587704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" OR " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 587804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(numberE164); 587904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 588004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 588104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 58825e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 58835e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 58843716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 58853716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 58863716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 58873716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 58883716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 58893716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 58903716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 58915e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 589203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 589304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann final String normalizedFilter = NameNormalizer.normalize(filter); 589404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(normalizedFilter)) { 58953716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 58963716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 58973716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 58983716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 58993716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("(CASE WHEN EXISTS (SELECT 1 FROM "); 59003716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.RAW_CONTACTS + " AS rc INNER JOIN "); 59013716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.NAME_LOOKUP + " AS nl ON (rc." + RawContacts._ID); 59023716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=nl." + NameLookupColumns.RAW_CONTACT_ID); 59033716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") WHERE nl." + NameLookupColumns.NORMALIZED_NAME); 59043716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" GLOB '" + normalizedFilter + "*' AND "); 59053716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("nl." + NameLookupColumns.NAME_TYPE + "="); 59063716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(NameLookupType.NAME_COLLATION_KEY + " AND "); 59073716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 59083716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=rc." + RawContacts.CONTACT_ID); 59093716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") THEN NULL ELSE "); 59103716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 59113716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" END)"); 59123716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 591304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } else { 591404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("NULL"); 591504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 591603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 59175e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" AS " + SearchSnippetColumns.SNIPPET); 59185e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 591903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 59205e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" FROM " + Tables.SEARCH_INDEX); 59215e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" WHERE "); 59225e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(Tables.SEARCH_INDEX + " MATCH "); 59235e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 59242352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, "\"" + sanitizeMatch(filter) + "*\""); 59253d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 59262352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, 592704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann "\"" + sanitizeMatch(filter) + "*\" OR \"" + phoneNumber + "*\"" 59282352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov + (numberE164 != null ? " OR \"" + numberE164 + "\"" : "")); 592903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 59302352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filter) + "*"); 59319c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov } 593203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov sb.append(") ON (" + Contacts._ID + "=snippet_contact_id)"); 5933a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov } 5934a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov 59352352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov private String sanitizeMatch(String filter) { 59362352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov // TODO more robust preprocessing of match expressions 59372352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov return filter.replace('-', ' ').replace('\"', ' '); 59382352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov } 59392352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov 59405e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov private void appendSnippetFunction( 59415e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov StringBuilder sb, String startMatch, String endMatch, String ellipsis, int maxTokens) { 59425e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append("snippet(" + Tables.SEARCH_INDEX + ","); 59435e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 59445e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 59455e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 59465e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 59475e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, ellipsis); 59485e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 59495e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov // The index of the column used for the snippet, "content" 59505e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(",1,"); 59515e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(maxTokens); 59525e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 59535e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 59545e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 5955763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) { 5956763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar StringBuilder sb = new StringBuilder(); 5957ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.RAW_CONTACTS); 5958763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setTables(sb.toString()); 5959763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setProjectionMap(sRawContactsProjectionMap); 5960763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar appendAccountFromParameter(qb, uri); 5961763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar } 5962763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar 5963a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForRawEntities(SQLiteQueryBuilder qb, Uri uri) { 5964ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.RAW_ENTITIES); 5965a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sRawEntityProjectionMap); 596646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana appendAccountFromParameter(qb, uri); 596746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 596846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 596982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 597082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String[] projection, boolean distinct) { 597146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, distinct, null); 597246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 597346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 597446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 597546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @param usageType when non-null {@link Tables#DATA_USAGE_STAT} is joined with the specified 597646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type. 597746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 597846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 597946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String[] projection, boolean distinct, Integer usageType) { 598082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 5981ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 598282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov sb.append(" data"); 598382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov 5984a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID); 5985a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 5986a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 5987a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 59883296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey 598946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (usageType != null) { 599046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa appendDataUsageStatJoin(sb, usageType, DataColumns.CONCRETE_ID); 599146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 599246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 599382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov qb.setTables(sb.toString()); 5994f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov 5995f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov boolean useDistinct = distinct 5996f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov || !mDbHelper.isInProjection(projection, DISTINCT_DATA_PROHIBITING_COLUMNS); 5997f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setDistinct(useDistinct); 5998f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setProjectionMap(useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap); 599982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov appendAccountFromParameter(qb, uri); 6000ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov } 6001ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov 60020a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb, 60030a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String[] projection) { 60040a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6005ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 60060a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" data"); 6007a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6008a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 60090a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6010a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6011a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sStatusUpdatesProjectionMap); 6012a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6013a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 60143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItems(SQLiteQueryBuilder qb) { 60151dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.STREAM_ITEMS 60161dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.RAW_CONTACTS + " ON (" 60171dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemsColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 60181dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.CONTACTS + " ON (" 60191dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + RawContactsColumns.CONCRETE_CONTACT_ID + "=" + ContactsColumns.CONCRETE_ID + ")"); 60203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemsProjectionMap); 60213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 60223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 60233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItemPhotos(SQLiteQueryBuilder qb) { 60241dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.PHOTO_FILES 60251dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.STREAM_ITEM_PHOTOS + " ON (" 60261dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_PHOTO_FILE_ID + "=" 60271dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + PhotoFilesColumns.CONCRETE_ID 60281dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.STREAM_ITEMS + " ON (" 60291dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=" 60301dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemsColumns.CONCRETE_ID + ")"); 60313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemPhotosProjectionMap); 60323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 60333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 6034a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForEntities(SQLiteQueryBuilder qb, Uri uri, 6035a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection) { 6036a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6037ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.ENTITIES); 6038a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" data"); 6039a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6040a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts.Entity.CONTACT_ID); 6041a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6042a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, Contacts.Entity.DATA_ID); 6043a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, Contacts.Entity.DATA_ID); 6044a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6045a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6046a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sEntityProjectionMap); 6047a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendAccountFromParameter(qb, uri); 6048a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6049a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6050a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactStatusUpdateJoin(StringBuilder sb, String[] projection, 6051a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lastStatusUpdateIdColumn) { 6052a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, 6053a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS, 6054a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_RES_PACKAGE, 6055a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_ICON, 6056a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_LABEL, 6057a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_TIMESTAMP)) { 6058a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " " 6059a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.ALIAS + 6060a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + lastStatusUpdateIdColumn + "=" 6061a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")"); 60620a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6063a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 60640a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6065a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataStatusUpdateJoin(StringBuilder sb, String[] projection, 6066a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 6067b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov if (mDbHelper.isInProjection(projection, 60680a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS, 60690a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_RES_PACKAGE, 60700a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_ICON, 60710a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_LABEL, 60720a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_TIMESTAMP)) { 60730a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + 6074a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "=" 6075a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + dataIdColumn + ")"); 60760a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6077a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6078a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 607946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void appendDataUsageStatJoin(StringBuilder sb, int usageType, String dataIdColumn) { 608046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" LEFT OUTER JOIN " + Tables.DATA_USAGE_STAT + 608146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" + dataIdColumn + 608246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " AND " + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" + usageType + ")"); 608346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 608446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 6085a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactPresenceJoin(StringBuilder sb, String[] projection, 6086a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn) { 6087a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, 6088a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_PRESENCE, Contacts.CONTACT_CHAT_CAPABILITY)) { 6089a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + 6090a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + contactIdColumn + " = " 6091a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + ")"); 6092a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6093a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6094a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6095a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataPresenceJoin(StringBuilder sb, String[] projection, 6096a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 6097a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, Data.PRESENCE, Data.CHAT_CAPABILITY)) { 6098a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE + 6099a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdates.DATA_ID + "=" + dataIdColumn + ")"); 6100a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6101a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6102a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 610324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private boolean appendLocalDirectorySelectionIfNeeded(SQLiteQueryBuilder qb, long directoryId) { 6104385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directoryId == Directory.DEFAULT) { 6105385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY); 610624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 6107385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directoryId == Directory.LOCAL_INVISIBLE){ 6108385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " NOT IN " + Tables.DEFAULT_DIRECTORY); 610924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 611024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 611124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return false; 611224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 611324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 61144b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki private String appendProfileRestriction(Uri uri, String profileColumn, 61154b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki boolean suppressProfileCheck, String originalSelection) { 61164b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki if (shouldIncludeProfile(uri, suppressProfileCheck)) { 61174b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki return originalSelection; 61184b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki } else { 61194b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki final String SELECTION = "(" + profileColumn + " IS NULL OR " + profileColumn + "=0)"; 61204b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki if (TextUtils.isEmpty(originalSelection)) { 61214b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki return SELECTION; 61224b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki } else { 61234b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki StringBuilder sb = new StringBuilder(); 61244b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki sb.append("("); 61254b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki sb.append(originalSelection); 61264b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki sb.append(") AND "); 61274b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki sb.append(SELECTION); 61284b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki return sb.toString(); 61294b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki } 6130385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } 6131385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } 6132385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov 61336ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private String prependProfileSortIfNeeded(Uri uri, String sortOrder, 61346ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean suppressProfileCheck) { 61356ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (shouldIncludeProfile(uri, suppressProfileCheck)) { 613624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (TextUtils.isEmpty(sortOrder)) { 613724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return Contacts.IS_USER_PROFILE + " DESC"; 613824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else { 613924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return Contacts.IS_USER_PROFILE + " DESC, " + sortOrder; 614024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 614124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 614224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return sortOrder; 614324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 614424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 61456ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private boolean shouldIncludeProfile(Uri uri, boolean suppressProfileCheck) { 614624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The user's profile may be returned alongside other contacts if it was requested and 614724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // the calling application has permission to read profile data. 6148377850d2dfd28eaf1b22273a50cfe066f6667ab9Dave Santoro boolean profileRequested = readBooleanQueryParameter(uri, ContactsContract.ALLOW_PROFILE, 614924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro false); 61506ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (profileRequested && !suppressProfileCheck) { 615124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 615224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 615324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return profileRequested; 615424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 615524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 61564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) { 6157f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6158f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 6159e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6160e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6161e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6162e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 6163fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6164fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6165e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6166e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6167e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6168e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6169e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6170e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 61714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere(RawContacts.ACCOUNT_NAME + "=" 61724a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + DatabaseUtils.sqlEscapeString(accountName) + " AND " 61734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + RawContacts.ACCOUNT_TYPE + "=" 61744a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + DatabaseUtils.sqlEscapeString(accountType)); 61754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } else { 61764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere("1"); 61774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 61784a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 61794a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 6180e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong private String appendAccountToSelection(Uri uri, String selection) { 6181f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6182f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 6183e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6184e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6185e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6186e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 6187fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6188fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6189e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6190e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6191e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6192e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6193e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6194e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 6195e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "=" 6196e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountName) + " AND " 6197e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + RawContacts.ACCOUNT_TYPE + "=" 6198e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountType)); 6199e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong if (!TextUtils.isEmpty(selection)) { 6200e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(" AND ("); 6201e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(selection); 6202e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(')'); 6203e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6204e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selectionSb.toString(); 6205e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } else { 6206e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selection; 6207e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6208e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6209e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong 62107e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 6211c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * Gets the value of the "limit" URI query parameter. 6212c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * 6213c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * @return A string containing a non-negative integer, or <code>null</code> if 6214c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * the parameter is not set, or is set to an invalid value. 6215c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov */ 6216f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private String getLimit(Uri uri) { 62172e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limitParam = getQueryParameter(uri, ContactsContract.LIMIT_PARAM_KEY); 6218c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (limitParam == null) { 6219c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6220c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6221c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov // make sure that the limit is a non-negative integer 6222c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov try { 6223c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov int l = Integer.parseInt(limitParam); 6224c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (l < 0) { 6225c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6226c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6227c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6228c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return String.valueOf(l); 6229c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } catch (NumberFormatException ex) { 6230c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6231c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6232c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6233c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6234c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 6235b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov @Override 6236f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 6237415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6238f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mode.equals("r")) { 6239f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mReadAccessLatch); 6240f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6241f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mWriteAccessLatch); 6242f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6243415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6244b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov int match = sUriMatcher.match(uri); 6245b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov switch (match) { 6246a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 6247afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 624824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6249afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 6250afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro return openPhotoAssetFile(db, uri, mode, 625124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Data._ID + "=" + Contacts.PHOTO_ID + " AND " + 625224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContacts.CONTACT_ID + "=?", 625324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(rawContactId)}); 6254e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6255b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6256f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: { 6257f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6258f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6259f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact ID can only be read."); 6260f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6261afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6262f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 6263afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6264afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = db.query(Tables.CONTACTS, 6265f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{Contacts.PHOTO_FILE_ID}, 6266f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID + "=?", new String[]{String.valueOf(contactId)}, 6267f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, null); 6268f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6269f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6270f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(0); 6271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6273f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6274f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6275f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6276f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6277f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6278f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: { 6279f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6280f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6281f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact lookup key can only be read."); 6282f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6283f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro List<String> pathSegments = uri.getPathSegments(); 6284f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int segmentCount = pathSegments.size(); 6285f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount < 4) { 6286f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6287f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Missing a lookup key", uri)); 6288f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6289afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6290f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String lookupKey = pathSegments.get(2); 6291f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Contacts.PHOTO_FILE_ID}; 6292f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount == 5) { 6293f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(pathSegments.get(3)); 6294afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6295f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 6296f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 6297afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 6298f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro projection, null, null, null, null, null, 6299f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 6300f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c != null) { 6301f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6302f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6303f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6304f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6305f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6306f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6307f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6308f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6309f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6310f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6311f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6312f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 6313afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 6314afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6315afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = qb.query(db, projection, Contacts._ID + "=?", 6316f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(contactId)}, null, null, null); 6317f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6318f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6319f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6320f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6321f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6322f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6323f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6324f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6325f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6326f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: { 6327f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6328f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean writeable = !mode.equals("r"); 6329afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6330afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, writeable); 6331f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6332f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Find the primary photo data record for this raw contact. 6333f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6334f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Data._ID, Photo.PHOTO_FILE_ID}; 6335f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 6336afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = qb.query(db, projection, 6337f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?", 6338f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(rawContactId), Photo.CONTENT_ITEM_TYPE}, 6339f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, Data.IS_PRIMARY + " DESC"); 6340f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long dataId = 0; 6341f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = 0; 6342f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6343f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c.getCount() >= 1) { 6344f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6345f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro dataId = c.getLong(0); 6346f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro photoFileId = c.getLong(1); 6347f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6348f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6349f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6350f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6351f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6352f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If writeable, open a writeable file descriptor that we can monitor. 6353f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // When the caller finishes writing content, we'll process the photo and 6354f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // update the data record. 6355f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (writeable) { 6356f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForWrite(rawContactId, dataId, uri, mode); 6357f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6358f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6359f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6360f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6361f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6362f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: { 6363f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = ContentUris.parseId(uri); 6364f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6365f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6366f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by key can only be read."); 6367f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6368f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6369f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6370f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6371e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov case DATA_ID: { 6372afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 637324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = Long.parseLong(uri.getPathSegments().get(1)); 6374afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForData(db, dataId, false); 6375afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro return openPhotoAssetFile(db, uri, mode, 6376e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov Data._ID + "=? AND " + Data.MIMETYPE + "='" + Photo.CONTENT_ITEM_TYPE + "'", 637724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(dataId)}); 6378d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6379d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6380fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case PROFILE_AS_VCARD: { 6381fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // When opening a contact as file, we pass back contents as a 6382fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // vCard-encoded stream. We build into a local buffer first, 6383fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // then pipe into MemoryFile once the exact size is known. 6384fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6385fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6386fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen return buildAssetFileDescriptor(localStream); 6387fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 638842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 6389fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case CONTACTS_AS_VCARD: { 639042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // When opening a contact as file, we pass back contents as a 639142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // vCard-encoded stream. We build into a local buffer first, 639242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // then pipe into MemoryFile once the exact size is known. 639342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6394fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6395f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 639642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 639742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 639842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 639949d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov SQLiteDatabase db = mDbHelper.getReadableDatabase(); 640042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKeys = uri.getPathSegments().get(2); 640142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String[] loopupKeyList = lookupKeys.split(":"); 640242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final StringBuilder inBuilder = new StringBuilder(); 6403fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Uri queryUri = Contacts.CONTENT_URI; 640442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann int index = 0; 6405fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen 6406d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // SQLite has limits on how many parameters can be used 6407d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // so the IDs are concatenated to a query string here instead 640842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann for (String lookupKey : loopupKeyList) { 640942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann if (index == 0) { 6410d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append("("); 641142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } else { 6412d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append(","); 641342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 641424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 6415afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 641624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro inBuilder.append(contactId); 6417fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (mProfileIdCache.profileContactId == contactId) { 6418fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen queryUri = queryUri.buildUpon().appendQueryParameter( 6419377850d2dfd28eaf1b22273a50cfe066f6667ab9Dave Santoro ContactsContract.ALLOW_PROFILE, "true").build(); 6420fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 642142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann index++; 642242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 642342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann inBuilder.append(')'); 642442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String selection = Contacts._ID + " IN " + inBuilder.toString(); 6425d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6426d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // When opening a contact as file, we pass back contents as a 6427d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // vCard-encoded stream. We build into a local buffer first, 6428d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // then pipe into MemoryFile once the exact size is known. 6429d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6430fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(queryUri, localStream, selection, null); 6431f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 6432d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6433b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6434b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov default: 6435fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new FileNotFoundException(mDbHelper.exceptionMessage("File does not exist", 6436fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov uri)); 6437b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6438b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6439b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6440afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private AssetFileDescriptor openPhotoAssetFile(SQLiteDatabase db, Uri uri, String mode, 6441afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro String selection, String[] selectionArgs) 6442e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throws FileNotFoundException { 6443e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov if (!"r".equals(mode)) { 6444e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throw new FileNotFoundException(mDbHelper.exceptionMessage("Mode " + mode 6445e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov + " not supported.", uri)); 6446e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6447e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6448e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov String sql = 6449ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann "SELECT " + Photo.PHOTO + " FROM " + Views.DATA + 6450e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov " WHERE " + selection; 645108ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood try { 6452f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6453f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert DatabaseUtils.blobFileDescriptorForQuery(db, sql, selectionArgs)); 645408ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } catch (SQLiteDoneException e) { 645508ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood // this will happen if the DB query returns no rows (i.e. contact does not exist) 645608ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood throw new FileNotFoundException(uri.toString()); 645708ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } 6458e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6459e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6460f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6461f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a display photo from the photo store for reading. 6462f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoFileId The display photo file ID 6463f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor that allows the file to be read. 6464f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @throws FileNotFoundException If no photo file for the given ID exists. 6465f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6466f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForRead(long photoFileId) 6467f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throws FileNotFoundException { 6468f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoStore.Entry entry = mPhotoStore.get(photoFileId); 6469f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 6470f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return makeAssetFileDescriptor( 6471f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(new File(entry.path), 6472f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.MODE_READ_ONLY), 6473f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro entry.size); 6474f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6475f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 6476f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new FileNotFoundException("No photo file found for ID " + photoFileId); 6477f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6478f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6479f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6480f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6481f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a file descriptor for a photo to be written. When the caller completes writing 6482f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to the file (closing the output stream), the image will be parsed out and processed. 6483f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If processing succeeds, the given raw contact ID's primary photo record will be 6484f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * populated with the inserted image (if no primary photo record exists, the data ID can 6485f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * be left as 0, and a new data record will be inserted). 6486f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rawContactId Raw contact ID this photo entry should be associated with. 6487f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param dataId Data ID for a photo mimetype that will be updated with the inserted 6488f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * image. May be set to 0, in which case the inserted image will trigger creation 6489f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * of a new primary photo image data row for the raw contact. 6490f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param uri The URI being used to access this file. 6491f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param mode Read/write mode string. 6492f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor the caller can use to write an image file for the 6493f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact. 6494f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6495f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForWrite(long rawContactId, long dataId, Uri uri, 6496f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String mode) { 6497f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6498f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return new AssetFileDescriptor(new MonitoredParcelFileDescriptor(rawContactId, dataId, 6499f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(File.createTempFile("img", null), 6500f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentResolver.modeToMode(uri, mode))), 6501f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 0, AssetFileDescriptor.UNKNOWN_LENGTH); 6502f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException ioe) { 6503f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Could not create temp image file in mode " + mode); 6504f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return null; 6505f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6506f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6507f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6508f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6509f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Parcel file descriptor wrapper that monitors when the file is closed. 6510f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If the file contains a valid image, the image is either inserted into the given 6511f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact or updated in the given data row. 6512f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6513f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private class MonitoredParcelFileDescriptor extends ParcelFileDescriptor { 6514f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mRawContactId; 6515f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mDataId; 6516f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private MonitoredParcelFileDescriptor(long rawContactId, long dataId, 6517f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor descriptor) { 6518f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro super(descriptor); 6519f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mRawContactId = rawContactId; 6520f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDataId = dataId; 6521f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6522f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6523f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro @Override 6524f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public void close() throws IOException { 6525f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6526f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check to see whether a valid image was written out. 6527f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Bitmap b = BitmapFactory.decodeFileDescriptor(getFileDescriptor()); 6528f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (b != null) { 6529f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoProcessor processor = new PhotoProcessor(b, mMaxDisplayPhotoDim, 6530f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim); 6531f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6532f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Store the compressed photo in the photo store. 6533f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = mPhotoStore.insert(processor); 6534f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6535f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Depending on whether we already had a data row to attach the photo to, 6536f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // do an update or insert. 6537f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mDataId != 0) { 6538f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Update the data record with the new photo. 6539f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 6540f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6541f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6542f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6543f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6544f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6545f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6546f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6547f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6548f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro update(ContentUris.withAppendedId(Data.CONTENT_URI, mDataId), updateValues, 6549f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null); 6550f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6551f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Insert a new primary data record with the photo. 6552f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues insertValues = new ContentValues(); 6553f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6554f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6555f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6556f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6557f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 6558f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.IS_PRIMARY, 1); 6559f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6560f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6561f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6562f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6563f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insert(RawContacts.CONTENT_URI.buildUpon() 6564f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(String.valueOf(mRawContactId)) 6565f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(RawContacts.Data.CONTENT_DIRECTORY).build(), 6566f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues); 6567f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6568f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6569f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6570f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro super.close(); 6571f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6572f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6573f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6574f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6575d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile"; 6576d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6577d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6578f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert * Returns an {@link AssetFileDescriptor} backed by the 6579d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * contents of the given {@link ByteArrayOutputStream}. 6580d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6581f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) { 6582d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey try { 6583d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey stream.flush(); 6584d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6585d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final byte[] byteData = stream.toByteArray(); 6586d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6587f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6588f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert ParcelFileDescriptor.fromData(byteData, CONTACT_MEMORY_FILE_NAME), 6589f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert byteData.length); 6590d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } catch (IOException e) { 6591ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert Log.w(TAG, "Problem writing stream into an ParcelFileDescriptor: " + e.toString()); 6592ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert return null; 6593d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6594d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6595d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6596f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd) { 6597f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor(fd, AssetFileDescriptor.UNKNOWN_LENGTH); 6598f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6599f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6600f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd, long length) { 6601f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return fd != null ? new AssetFileDescriptor(fd, 0, length) : null; 6602f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6603f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6604d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6605d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * Output {@link RawContacts} matching the requested selection in the vCard 6606d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * format to the given {@link OutputStream}. This method returns silently if 6607d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * any errors encountered. 6608d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6609fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen private void outputRawContactsAsVCard(Uri uri, OutputStream stream, 6610fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen String selection, String[] selectionArgs) { 6611d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final Context context = this.getContext(); 6612dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen int vcardconfig = VCardConfig.VCARD_TYPE_DEFAULT; 6613fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if(uri.getBooleanQueryParameter( 6614fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, false)) { 6615dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen vcardconfig |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT; 6616dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen } 66177a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa final VCardComposer composer = 6618dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen new VCardComposer(context, vcardconfig, false); 6619108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Writer writer = null; 6620108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6621108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer = new BufferedWriter(new OutputStreamWriter(stream)); 6622fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (!composer.init(uri, selection, selectionArgs, null)) { 6623108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "Failed to init VCardComposer"); 6624108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa return; 6625108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6626d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6627108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa while (!composer.isAfterLast()) { 6628108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.write(composer.createOneEntry()); 6629108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6630108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6631108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.e(TAG, "IOException: " + e); 6632108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } finally { 6633108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa composer.terminate(); 6634108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa if (writer != null) { 6635108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6636108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.close(); 6637108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6638108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "IOException during closing output stream: " + e); 6639108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6640d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6641d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6642d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6643b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 66444f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 66454f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 6646415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6647415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov waitForAccess(mReadAccessLatch); 6648415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6649a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 66504f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 6651b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS: 6652be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return Contacts.CONTENT_TYPE; 66532d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill case CONTACTS_LOOKUP: 6654b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_ID: 6655b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_LOOKUP_ID: 665624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 6657b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_ITEM_TYPE; 6658f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: 665942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: 666024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 6661f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey return Contacts.CONTENT_VCARD_TYPE; 6662f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov case CONTACTS_ID_PHOTO: 6663f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: 6664f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6665f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: 6666f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: 6667f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: 6668f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return "image/jpeg"; 6669b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS: 667024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 6671be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return RawContacts.CONTENT_TYPE; 6672b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS_ID: 667324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 6674b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return RawContacts.CONTENT_ITEM_TYPE; 6675f481f22a9323fe338672f99b88b26c5f0725cd42David Brown case DATA: 667624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 6677f481f22a9323fe338672f99b88b26c5f0725cd42David Brown return Data.CONTENT_TYPE; 6678508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 6679b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getDataMimeType(ContentUris.parseId(uri)); 668048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES: 668148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_TYPE; 668248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 668348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_ITEM_TYPE; 66849005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov case PHONE_LOOKUP: 66859005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov return PhoneLookup.CONTENT_TYPE; 668648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS: 668748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_TYPE; 668848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 668948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_ITEM_TYPE; 669048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS: 669148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_TYPE; 669248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: 669348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_ITEM_TYPE; 6694b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 6695b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_TYPE; 6696b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 6697b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_ITEM_TYPE; 6698b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case SETTINGS: 6699b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Settings.CONTENT_TYPE; 6700b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 6701b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_TYPE; 6702c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: 6703c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SUGGEST_MIME_TYPE; 6704c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: 6705c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SHORTCUT_MIME_TYPE; 6706d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES: 6707d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_TYPE; 6708d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID: 6709d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_ITEM_TYPE; 671061efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov default: 671161efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov return mLegacyApiSupport.getType(uri); 67124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 67134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 67147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 671509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov public String[] getDefaultProjection(Uri uri) { 671609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov final int match = sUriMatcher.match(uri); 671709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov switch (match) { 671809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS: 671909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP: 672009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_ID: 672109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP_ID: 672209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 672324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 672409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsProjectionMap.getColumnNames(); 672509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 67268727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov case CONTACTS_ID_ENTITIES: 672724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: 67288727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov return sEntityProjectionMap.getColumnNames(); 67298727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov 673009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_VCARD: 673109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_MULTI_VCARD: 673224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 673309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsVCardProjectionMap.getColumnNames(); 673409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 673509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS: 673609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS_ID: 673724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 673824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 673909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sRawContactsProjectionMap.getColumnNames(); 674009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 674109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DATA_ID: 674209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES: 674309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES_ID: 674409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS: 674509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS_ID: 674609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS: 674709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS_ID: 674824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 674909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDataProjectionMap.getColumnNames(); 675009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 675109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONE_LOOKUP: 675209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sPhoneLookupProjectionMap.getColumnNames(); 675309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 675409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 675509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 675609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sAggregationExceptionsProjectionMap.getColumnNames(); 675709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 675809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case SETTINGS: 675909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sSettingsProjectionMap.getColumnNames(); 676009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 676109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES: 676209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES_ID: 676309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDirectoryProjectionMap.getColumnNames(); 676409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 676509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov default: 676609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return null; 676709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 676809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 676909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 6770f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private class StructuredNameLookupBuilder extends NameLookupBuilder { 6771f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6772f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov public StructuredNameLookupBuilder(NameSplitter splitter) { 6773f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov super(splitter); 6774f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6775f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6776f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 6777f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected void insertNameLookup(long rawContactId, long dataId, int lookupType, 6778f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov String name) { 677978fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.insertNameLookup(rawContactId, dataId, lookupType, name); 6780f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6781f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6782f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 6783f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected String[] getCommonNicknameClusters(String normalizedName) { 6784d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); 6785f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6786f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6787f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 67882d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) { 6789d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov sb.append("(" + 6790d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov "SELECT DISTINCT " + RawContacts.CONTACT_ID + 6791d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 6792d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " JOIN " + Tables.NAME_LOOKUP + 6793d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " ON(" + RawContactsColumns.CONCRETE_ID + "=" 6794d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov + NameLookupColumns.RAW_CONTACT_ID + ")" + 6795d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " WHERE normalized_name GLOB '"); 6796e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(NameNormalizer.normalize(filterParam)); 6797916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov sb.append("*' AND " + NameLookupColumns.NAME_TYPE + 6798916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov " IN(" + CONTACT_LOOKUP_NAME_TYPES + "))"); 6799e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 6800e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 68019a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov public boolean isPhoneNumber(String filter) { 68029a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean atLeastOneDigit = false; 68039a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov int len = filter.length(); 68049a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov for (int i = 0; i < len; i++) { 68059a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov char c = filter.charAt(i); 68069a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (c >= '0' && c <= '9') { 68079a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov atLeastOneDigit = true; 68089a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } else if (c != '*' && c != '#' && c != '+' && c != 'N' && c != '.' && c != ';' 68099a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov && c != '-' && c != '(' && c != ')' && c != ' ') { 68109a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return false; 68119a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 68129a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 68139a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return atLeastOneDigit; 68149a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 68159a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 68164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** 68177a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * Takes components of a name from the query parameters and returns a cursor with those 68187a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * components as well as all missing components. There is no database activity involved 68197a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * in this so the call can be made on the UI thread. 68207a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov */ 68217a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private Cursor completeName(Uri uri, String[] projection) { 68227a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (projection == null) { 68237a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov projection = sDataProjectionMap.getColumnNames(); 68247a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68257a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68267a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ContentValues values = new ContentValues(); 6827f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataRowHandlerForStructuredName handler = (DataRowHandlerForStructuredName) 6828f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov getDataRowHandler(StructuredName.CONTENT_ITEM_TYPE); 68297a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68307a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov copyQueryParamsToContentValues(values, uri, 68317a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.DISPLAY_NAME, 68327a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PREFIX, 68337a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.GIVEN_NAME, 68347a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.MIDDLE_NAME, 68357a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.FAMILY_NAME, 68367a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.SUFFIX, 68377a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_NAME, 68387a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_FAMILY_NAME, 68397a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_MIDDLE_NAME, 68407a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_GIVEN_NAME 68417a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ); 68427a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68437a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov handler.fixStructuredNameComponents(values, values); 68447a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68457a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 68467a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov Object[] row = new Object[projection.length]; 68477a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 68487a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov row[i] = values.get(projection[i]); 68497a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68507a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov cursor.addRow(row); 68517a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return cursor; 68527a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68537a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68547a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private void copyQueryParamsToContentValues(ContentValues values, Uri uri, String... columns) { 68557a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (String column : columns) { 68567a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov String param = uri.getQueryParameter(column); 68577a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (param != null) { 68587a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov values.put(column, param); 68597a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68607a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68617a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 68627a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68637a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 68647a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov /** 68654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov * Inserts an argument at the beginning of the selection arg list. 68664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov */ 68674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private String[] insertSelectionArg(String[] selectionArgs, String arg) { 6868b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 6869b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 6870b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 6871b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 6872b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 68734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov newSelectionArgs[0] = arg; 68744a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length); 6875b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 6876b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 6877b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 6878caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 68795e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar private String[] appendProjectionArg(String[] projection, String arg) { 68805e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection == null) { 68815e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return null; 68825e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 68835e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar final int length = projection.length; 68845e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar String[] newProjection = new String[length + 1]; 68855e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar System.arraycopy(projection, 0, newProjection, 0, length); 68865e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar newProjection[length] = arg; 68875e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return newProjection; 68885e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 68895e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 6890caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov protected Account getDefaultAccount() { 6891caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov AccountManager accountManager = AccountManager.get(getContext()); 6892caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov try { 68935f1f4a062ac34d75d2dbf586702cbeb121cf09caDmitri Plotnikov Account[] accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE); 6894caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov if (accounts != null && accounts.length > 0) { 6895caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov return accounts[0]; 6896caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 6897caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } catch (Throwable e) { 68986f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov Log.e(TAG, "Cannot determine the default account for contacts compatibility", e); 6899caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 69006f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov return null; 6901caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 6902f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 690373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov /** 690473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov * Returns true if the specified account type is writable. 690573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov */ 690673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov protected boolean isWritableAccount(String accountType) { 6907bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov if (accountType == null) { 6908bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov return true; 6909bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov } 6910bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov 691173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov Boolean writable = mAccountWritability.get(accountType); 691273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable != null) { 691373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 691473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 691573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 6916627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov IContentService contentService = ContentResolver.getContentService(); 6917627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 6918627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) { 6919627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov if (ContactsContract.AUTHORITY.equals(sync.authority) && 692073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov accountType.equals(sync.accountType)) { 692173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = sync.supportsUploading(); 692273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov break; 6923627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 6924627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 6925627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } catch (RemoteException e) { 6926627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov Log.e(TAG, "Could not acquire sync adapter types"); 6927627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 692873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 692973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable == null) { 693073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = false; 693173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 693273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 693373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.put(accountType, writable); 693473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 6935627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 6936b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov 6937d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 6938f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter, 6939f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean defaultValue) { 6940f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6941f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov // Manually parse the query, which is much faster than calling uri.getQueryParameter 6942f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 6943f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 6944f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 6945f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6946f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6947f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = query.indexOf(parameter); 6948f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 6949f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 6950f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6951f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6952f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameter.length(); 6953f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6954f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return !matchQueryParameter(query, index, "=0", false) 6955f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && !matchQueryParameter(query, index, "=false", true); 6956f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6957f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6958f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private static boolean matchQueryParameter(String query, int index, String value, 6959f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean ignoreCase) { 6960f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int length = value.length(); 6961f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return query.regionMatches(ignoreCase, index, value, 0, length) 6962f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && (query.length() == index + length || query.charAt(index + length) == '&'); 6963f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6964f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6965f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /** 6966f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * A fast re-implementation of {@link Uri#getQueryParameter} 6967f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov */ 6968f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static String getQueryParameter(Uri uri, String parameter) { 6969f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 6970f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 6971f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 6972f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6973f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6974f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int queryLength = query.length(); 6975f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int parameterLength = parameter.length(); 6976f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6977f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String value; 6978f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = 0; 6979f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov while (true) { 6980f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index = query.indexOf(parameter, index); 6981f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 6982f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 69835fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 69845fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa 69855fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // Should match against the whole parameter instead of its suffix. 69865fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // e.g. The parameter "param" must not be found in "some_param=val". 69875fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (index > 0) { 69885fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa char prevChar = query.charAt(index - 1); 69895fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (prevChar != '?' && prevChar != '&') { 69905fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // With "some_param=val1¶m=val2", we should find second "param" occurrence. 69915fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa index += parameterLength; 69925fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa continue; 69935fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 6994f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 6995f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6996f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameterLength; 6997f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 6998f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (queryLength == index) { 6999f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7000f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7001f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7002f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query.charAt(index) == '=') { 7003f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index++; 7004f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov break; 7005f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7006f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7007f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7008f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int ampIndex = query.indexOf('&', index); 7009f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (ampIndex == -1) { 7010f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index); 7011f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } else { 7012f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index, ampIndex); 7013f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7014f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7015f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return Uri.decode(value); 7016f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 70175dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 70180dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov protected boolean isAggregationUpgradeNeeded() { 70190dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov if (!mContactAggregator.isEnabled()) { 70200dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return false; 70210dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 70220dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 70230dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_AGGREGATION_ALGORITHM, "1")); 70240dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return version < PROPERTY_AGGREGATION_ALGORITHM_VERSION; 70250dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 70260dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 7027bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void upgradeAggregationAlgorithmInBackground() { 70280dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // This upgrade will affect very few contacts, so it can be performed on the 70290dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // main thread during the initial boot after an OTA 70300dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 70310dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Upgrading aggregation algorithm"); 70320dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int count = 0; 70330dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long start = SystemClock.currentThreadTimeMillis(); 70340dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 703549d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov mDb = mDbHelper.getWritableDatabase(); 70360dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.beginTransaction(); 70370dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Cursor cursor = mDb.query(true, 70380dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Tables.RAW_CONTACTS + " r1 JOIN " + Tables.RAW_CONTACTS + " r2", 70390dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov new String[]{"r1." + RawContacts._ID}, 70400dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov "r1." + RawContacts._ID + "!=r2." + RawContacts._ID + 70410dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.CONTACT_ID + "=r2." + RawContacts.CONTACT_ID + 70420dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.ACCOUNT_NAME + "=r2." + RawContacts.ACCOUNT_NAME + 70430dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.ACCOUNT_TYPE + "=r2." + RawContacts.ACCOUNT_TYPE, 70440dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov null, null, null, null, null); 70450dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 70460dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov while (cursor.moveToNext()) { 70470dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long rawContactId = cursor.getLong(0); 70480dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, 70490dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 70500dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov count++; 70510dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 70520dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 70530dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov cursor.close(); 70540dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 7055bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateInTransaction(mTransactionContext, mDb); 7056bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 70570dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.setTransactionSuccessful(); 70580dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDbHelper.setProperty(PROPERTY_AGGREGATION_ALGORITHM, 70590dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov String.valueOf(PROPERTY_AGGREGATION_ALGORITHM_VERSION)); 70600dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 70610dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.endTransaction(); 70620dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long end = SystemClock.currentThreadTimeMillis(); 70630dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Aggregation algorithm upgraded for " + count 70640dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov + " contacts, in " + (end - start) + "ms"); 70650dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 70660dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 70679a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 70689a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov /* Visible for testing */ 70699a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean isPhone() { 70709a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (!sIsPhoneInitialized) { 70719a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhone = new TelephonyManager(getContext()).isVoiceCapable(); 70729a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhoneInitialized = true; 70739a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 70749a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return sIsPhone; 70759a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 707646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 707746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private boolean handleDataUsageFeedback(Uri uri) { 707846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final long currentTimeMillis = System.currentTimeMillis(); 707946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 708046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] ids = uri.getLastPathSegment().trim().split(","); 708146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ArrayList<Long> dataIds = new ArrayList<Long>(); 708246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 708346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (String id : ids) { 708446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa dataIds.add(Long.valueOf(id)); 708546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 708646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final boolean successful; 708746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (TextUtils.isEmpty(usageType)) { 708846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.w(TAG, "Method for data usage feedback isn't specified. Ignoring."); 708946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = false; 709046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 709146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = updateDataUsageStat(dataIds, usageType, currentTimeMillis) > 0; 709246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 709346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 709446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Handle old API. This doesn't affect the result of this entire method. 709546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] questionMarks = new String[ids.length]; 709646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Arrays.fill(questionMarks, "?"); 709746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = Data._ID + " IN (" + TextUtils.join(",", questionMarks) + ")"; 709846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final Cursor cursor = mDb.query( 7099ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA, 710046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { Data.CONTACT_ID }, 710146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa where, ids, null, null, null); 710246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 710346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa while (cursor.moveToNext()) { 710446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mSelectionArgs1[0] = cursor.getString(0); 710546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa ContentValues values2 = new ContentValues(); 710646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values2.put(Contacts.LAST_TIME_CONTACTED, currentTimeMillis); 710746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.update(Tables.CONTACTS, values2, Contacts._ID + "=?", mSelectionArgs1); 710846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 710946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 711046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 711146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 711246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 711346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 711446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 711546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return successful; 711646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 711746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 711846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 711946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Update {@link Tables#DATA_USAGE_STAT}. 712046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * 712146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @return the number of rows affected. 712246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 7123f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa @VisibleForTesting 7124f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa /* package */ int updateDataUsageStat( 7125f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa List<Long> dataIds, String type, long currentTimeMillis) { 712646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final int typeInt = sDataUsageTypeMap.get(type); 712746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = DataUsageStatColumns.DATA_ID + " =? AND " 712846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT + " =?"; 712946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] columns = 713046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { DataUsageStatColumns._ID, DataUsageStatColumns.TIMES_USED }; 713146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ContentValues values = new ContentValues(); 713246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (Long dataId : dataIds) { 713346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] args = new String[] { dataId.toString(), String.valueOf(typeInt) }; 713446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.beginTransaction(); 713546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 713646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final Cursor cursor = mDb.query(Tables.DATA_USAGE_STAT, columns, where, args, 713746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa null, null, null); 713846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 713946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (cursor.getCount() > 0) { 714046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!cursor.moveToFirst()) { 714146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.e(TAG, 714246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa "moveToFirst() failed while getAccount() returned non-zero."); 714346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 714446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 714546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, cursor.getInt(1) + 1); 714646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 714746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.update(Tables.DATA_USAGE_STAT, values, 714846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns._ID + " =?", 714946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { cursor.getString(0) }); 715046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 715146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 715246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 715346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.DATA_ID, dataId); 715446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.USAGE_TYPE_INT, typeInt); 715546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, 1); 715646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 715746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.insert(Tables.DATA_USAGE_STAT, null, values); 715846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 715946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.setTransactionSuccessful(); 716046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 716146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 716246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 716346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 716446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.endTransaction(); 716546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 716646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 716746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 716846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return dataIds.size(); 716946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 717046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 717146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 717246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Returns a sort order String for promoting data rows (email addresses, phone numbers, etc.) 717346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * associated with a primary account. The primary account should be supplied from applications 717446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * with {@link ContactsContract#PRIMARY_ACCOUNT_NAME} and 717546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * {@link ContactsContract#PRIMARY_ACCOUNT_TYPE}. Null will be returned when the primary 717646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * account isn't available. 717746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 717846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private String getAccountPromotionSortOrder(Uri uri) { 717946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountName = 718046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME); 718146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountType = 718246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE); 718346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 718446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Data rows associated with primary account should be promoted. 718546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountName)) { 718646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa StringBuilder sb = new StringBuilder(); 718746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append("(CASE WHEN " + RawContacts.ACCOUNT_NAME + "="); 718846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountName); 718946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountType)) { 719046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 719146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountType); 719246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 719346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" THEN 0 ELSE 1 END)"); 719446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return sb.toString(); 719546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 719646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return null; 719746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 719846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 71994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 7200