ContactsProvider2.java revision 43368a3f9e05a979e454e278d6a0e8475f08923d
14f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/* 24f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Copyright (C) 2009 The Android Open Source Project 34f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * 44f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License"); 54f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * you may not use this file except in compliance with the License. 64f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * You may obtain a copy of the License at 74f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * 84f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * http://www.apache.org/licenses/LICENSE-2.0 94f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * 104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Unless required by applicable law or agreed to in writing, software 114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS, 124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * See the License for the specific language governing permissions and 144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * limitations under the License 154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarpackage com.android.providers.contacts; 1828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar 19d9ec58265ae59a549880ef63cdfb5d0d977cdabaDmitri Plotnikovimport com.android.common.content.SQLiteContentProvider; 2053214b3ed12b0ff9cb589b6559311f2ac142f2e3Bjorn Bringertimport com.android.common.content.SyncStateContentProviderHelper; 215b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport com.android.providers.contacts.ContactAggregator.AggregationSuggestionParameter; 2297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactLookupKey.LookupKeySegment; 2324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns; 2497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns; 2597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; 2697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Clauses; 2797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns; 2897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsStatusUpdatesColumns; 2997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; 3071340347b4862d4b1368a5d69d1667e2245952e4Daisuke Miyakawaimport com.android.providers.contacts.ContactsDatabaseHelper.DataUsageStatColumns; 3197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns; 322f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawaimport com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns; 3397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns; 3497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType; 3597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneColumns; 3697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; 371dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.PhotoFilesColumns; 3897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 3997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 4003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SearchIndexColumns; 4197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SettingsColumns; 4297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns; 433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemPhotosColumns; 44f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemsColumns; 4597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables; 46ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmannimport com.android.providers.contacts.ContactsDatabaseHelper.Views; 472f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawaimport com.android.providers.contacts.util.DbQueryUtils; 4897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardComposer; 4997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardConfig; 5097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Lists; 5197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Maps; 5297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Sets; 53f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawaimport com.google.common.annotations.VisibleForTesting; 5497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 55b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account; 56caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager; 575b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanaimport android.accounts.OnAccountsUpdateListener; 58bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.Notification; 59bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.NotificationManager; 60bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.PendingIntent; 61c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager; 62568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation; 63568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult; 646ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.content.ContentResolver; 6535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris; 6667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues; 6767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context; 68627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.IContentService; 69bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.content.Intent; 70568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException; 713d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences; 72627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.SyncAdapterType; 7367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher; 74f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringertimport android.content.res.AssetFileDescriptor; 753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.content.res.Resources; 76e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikovimport android.database.CrossProcessCursor; 774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor; 78e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikovimport android.database.CursorWindow; 79ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.database.CursorWrapper; 80ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils; 8109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor; 8209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor.RowBuilder; 834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase; 8408ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwoodimport android.database.sqlite.SQLiteDoneException; 854f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder; 86f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.Bitmap; 87f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.BitmapFactory; 884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri; 89d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.net.Uri.Builder; 90bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Binder; 916ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.os.Bundle; 92bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Handler; 93bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.HandlerThread; 94bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Message; 95ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringertimport android.os.ParcelFileDescriptor; 96bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Process; 97b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException; 9815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikovimport android.os.StrictMode; 990dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikovimport android.os.SystemClock; 1000e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport android.os.SystemProperties; 1013d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager; 102508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns; 1033de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract; 104b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions; 10597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email; 10697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.GroupMembership; 10797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im; 10897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname; 1096d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Note; 11097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization; 11197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone; 11297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo; 1134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.SipAddress; 11497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 11597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 116ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.provider.ContactsContract.ContactCounts; 1173de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Contacts; 1185b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.AggregationSuggestions; 1193de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Data; 12071340347b4862d4b1368a5d69d1667e2245952e4Daisuke Miyakawaimport android.provider.ContactsContract.DataUsageFeedback; 121d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.provider.ContactsContract.Directory; 122f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.DisplayPhoto; 1233de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Groups; 124bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.provider.ContactsContract.Intents; 1253de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup; 1261dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoroimport android.provider.ContactsContract.PhotoFiles; 12709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.provider.ContactsContract.ProviderStatus; 1283de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.RawContacts; 129916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikovimport android.provider.ContactsContract.SearchSnippetColumns; 1303de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Settings; 13182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikovimport android.provider.ContactsContract.StatusUpdates; 1323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.provider.ContactsContract.StreamItemPhotos; 133f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.StreamItems; 13497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.LiveFolders; 13597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.OpenableColumns; 13697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.SyncStateContract; 137a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils; 1389a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikovimport android.telephony.TelephonyManager; 139a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils; 140c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log; 1414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 142108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.BufferedWriter; 143d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.ByteArrayOutputStream; 144f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.File; 145b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException; 146d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.IOException; 147d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.OutputStream; 148108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.OutputStreamWriter; 149108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.Writer; 15042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.text.SimpleDateFormat; 1517e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList; 15246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawaimport java.util.Arrays; 1535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections; 15442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.util.Date; 155b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap; 1560e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.HashSet; 1575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List; 158622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkeyimport java.util.Locale; 159b5a4add17815167d20a90645779df34cdf45280dFred Quintanaimport java.util.Map; 1600e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.Set; 161ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch; 1624f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/** 1644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications 1654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}. 1664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 1675b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanapublic class ContactsProvider2 extends SQLiteContentProvider implements OnAccountsUpdateListener { 168caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 169bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov private static final String TAG = "ContactsProvider"; 170bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov 171bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE); 1724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 17315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_INITIALIZE = 0; 17415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_OPEN_WRITE_ACCESS = 1; 17515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS = 2; 17615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_ACCOUNTS = 3; 17715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_LOCALE = 4; 17815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM = 5; 17905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_SEARCH_INDEX = 6; 18005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_PROVIDER_STATUS = 7; 18105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_DIRECTORIES = 8; 18205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_CHANGE_LOCALE = 9; 183f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int BACKGROUND_TASK_CLEANUP_PHOTOS = 10; 184619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** Default for the maximum number of returned aggregation suggestions. */ 1863cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DEFAULT_MAX_SUGGESTIONS = 5; 1873cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 1883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Limit for the maximum number of social stream items to store under a raw contact. */ 1893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int MAX_STREAM_ITEMS_PER_RAW_CONTACT = 5; 1903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 191f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Rate limit (in ms) for photo cleanup. Do it at most once per day. */ 192f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_CLEANUP_RATE_LIMIT = 24 * 60 * 60 * 1000; 193f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1943d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /** 195b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov * Property key for the legacy contact import version. The need for a version 1963d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov * as opposed to a boolean flag is that if we discover bugs in the contact import process, 1973d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov * we can trigger re-import by incrementing the import version. 1983d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov */ 199b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov private static final String PROPERTY_CONTACTS_IMPORTED = "contacts_imported_v1"; 200b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov private static final int PROPERTY_CONTACTS_IMPORT_VERSION = 1; 20151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov private static final String PREF_LOCALE = "locale"; 2023d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2030dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final String PROPERTY_AGGREGATION_ALGORITHM = "aggregation_v2"; 2040dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final int PROPERTY_AGGREGATION_ALGORITHM_VERSION = 2; 2050dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 2060e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate"; 2070e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff 208a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 2094f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2102f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 2112f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * Used to insert a column into strequent results, which enables SQL to sort the list using 2122f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * the total times contacted. See also {@link #sStrequentFrequentProjectionMap}. 2132f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 2142f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private static final String TIMES_USED_SORT_COLUMN = "times_used_sort"; 2155e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 216d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, " 2172f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa + TIMES_USED_SORT_COLUMN + " DESC, " 2189b43551f1ce33b79141772737a262ce609bd0cebMegha Joshi + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 219d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final String STREQUENT_LIMIT = 220d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE " 221d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov + Contacts.STARRED + "=1) + 25"; 222d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov 22345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final String FREQUENT_ORDER_BY = DataUsageStatColumns.TIMES_USED + " DESC," 22445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 22545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 2266e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE = 2279b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.CONTACTS + " SET " + Contacts.TIMES_CONTACTED + "=" + 2289b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " CASE WHEN " + Contacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " + 2299b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " (" + Contacts.TIMES_CONTACTED + " + 1) END WHERE " + Contacts._ID + "=?"; 2309b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 2316e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE = 2329b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.RAW_CONTACTS + " SET " + RawContacts.TIMES_CONTACTED + "=" + 2339b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " CASE WHEN " + RawContacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " + 2349b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " (" + RawContacts.TIMES_CONTACTED + " + 1) END WHERE " + RawContacts.CONTACT_ID + "=?"; 2359b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 236de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK"; 237de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa 2383716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Regex for splitting query strings - we split on any group of non-alphanumeric characters, 2393716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // excluding the @ symbol. 2403716f1447ceb21180d1301790eabd8b9453f486dDave Santoro /* package */ static final String QUERY_TOKENIZER_REGEX = "[^\\w@]+"; 2413716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 242d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS = 1000; 243d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS_ID = 1001; 2445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP = 1002; 2455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP_ID = 1003; 246a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_DATA = 1004; 2475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_FILTER = 1005; 2485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT = 1006; 2495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT_FILTER = 1007; 2505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_GROUP = 1008; 251a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_PHOTO = 1009; 252f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_DISPLAY_PHOTO = 1010; 253f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_DISPLAY_PHOTO = 1011; 254f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_DISPLAY_PHOTO = 1012; 255f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_AS_VCARD = 1013; 256f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_AS_MULTI_VCARD = 1014; 257f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_DATA = 1015; 258f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_DATA = 1016; 259f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_ENTITIES = 1017; 260f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ENTITIES = 1018; 261f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_ENTITIES = 1019; 262f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_STREAM_ITEMS = 1020; 263f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_STREAM_ITEMS = 1021; 264f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_STREAM_ITEMS = 1022; 26545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final int CONTACTS_FREQUENT = 1023; 2664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS = 2002; 2685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_ID = 2003; 2695ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_DATA = 2004; 27046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITY_ID = 2005; 271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_DISPLAY_PHOTO = 2006; 272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS = 2007; 2734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2746bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 2756bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 276ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 27748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_ID = 3003; 27848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_FILTER = 3004; 27948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS = 3005; 28048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_ID = 3006; 28148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_LOOKUP = 3007; 28248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_FILTER = 3008; 28348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS = 3009; 28448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS_ID = 3010; 285a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2866bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 2876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 288b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 289b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 290b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 29182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES = 7000; 29282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES_ID = 7001; 2931f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 29431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 29531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 296eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey private static final int SETTINGS = 9000; 297eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 298ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 299ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 300ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 301ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 30235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 303b5a4add17815167d20a90645779df34cdf45280dFred Quintana private static final int SYNCSTATE_ID = 11001; 30435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 305c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SUGGESTIONS = 12001; 306c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SHORTCUT = 12002; 307c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 3081b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS = 14000; 3091b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001; 3101b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002; 3111b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003; 3121b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 31346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITIES = 15001; 31446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 31509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private static final int PROVIDER_STATUS = 16001; 31609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 317d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES = 17001; 318d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES_ID = 17002; 319d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 3207a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private static final int COMPLETE_NAME = 18000; 3217a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 32224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE = 19000; 32324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_ENTITIES = 19001; 32424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA = 19002; 32524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA_ID = 19003; 32624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_AS_VCARD = 19004; 32724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS = 19005; 32824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID = 19006; 32924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_DATA = 19007; 33024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_ENTITIES = 19008; 33124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 33246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final int DATA_USAGE_FEEDBACK_ID = 20001; 33346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 3343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS = 21000; 3353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_PHOTOS = 21001; 3363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID = 21002; 3373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS = 21003; 3383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS_ID = 21004; 3393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_LIMIT = 21005; 3403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 341f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int DISPLAY_PHOTO = 22000; 342f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_DIMENSIONS = 22001; 343f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 344dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID = 345dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 346dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME 347dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "=" + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 348dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE 34943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + "=" + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND (" 35043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET 35143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + "=" + RawContactsColumns.CONCRETE_DATA_SET + " OR " 35243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 35343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " IS NULL)" 354dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND " + Groups.FAVORITES + " != 0"; 355dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 356dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID = 357dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 358dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 359dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 360dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 36143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND (" 36243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + "=" 36343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " OR " 36443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 36543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " IS NULL)" 36643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + " AND " + Groups.AUTO_ADD + " != 0"; 367dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 368dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String[] PROJECTION_GROUP_ID 369dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana = new String[]{Tables.GROUPS + "." + Groups._ID}; 370dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 371dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_GROUPMEMBERSHIP_DATA = DataColumns.MIMETYPE_ID + "=? " 372dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.GROUP_ROW_ID + "=? " 373dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.RAW_CONTACT_ID + "=?"; 374dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 375dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_STARRED_FROM_RAW_CONTACTS = 376dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana "SELECT " + RawContacts.STARRED 377dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " FROM " + Tables.RAW_CONTACTS + " WHERE " + RawContacts._ID + "=?"; 378dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 379e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public class AddressBookCursor extends CursorWrapper implements CrossProcessCursor { 380e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov private final CrossProcessCursor mCursor; 381e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov private final Bundle mBundle; 382e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 383e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public AddressBookCursor(CrossProcessCursor cursor, String[] titles, int[] counts) { 384e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov super(cursor); 385e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mCursor = cursor; 386e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle = new Bundle(); 387e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle.putStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES, titles); 388e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle.putIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, counts); 389e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 390e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 391e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 392e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public Bundle getExtras() { 393e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mBundle; 394e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 395e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 396e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 397e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public void fillWindow(int pos, CursorWindow window) { 398e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mCursor.fillWindow(pos, window); 399e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 400e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 401e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 402e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public CursorWindow getWindow() { 403e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mCursor.getWindow(); 404e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 405e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 406e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 407e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public boolean onMove(int oldPosition, int newPosition) { 408e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mCursor.onMove(oldPosition, newPosition); 409e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 410e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 411e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 412d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private interface DataContactsQuery { 413f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov public static final String TABLE = "data " 414f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) " 415f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)"; 41667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 41767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 4186cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov RawContactsColumns.CONCRETE_ID, 4196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_TYPE, 4206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_NAME, 42143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContactsColumns.CONCRETE_DATA_SET, 4223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 423f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov ContactsColumns.CONCRETE_ID 424ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 425ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 426d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov public static final int RAW_CONTACT_ID = 0; 4276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_TYPE = 1; 4286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_NAME = 2; 42943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_SET = 3; 43043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_ID = 4; 43143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int CONTACT_ID = 5; 432ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 4331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 434f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov interface RawContactsQuery { 43519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String TABLE = Tables.RAW_CONTACTS; 43619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 43719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String[] COLUMNS = new String[] { 438ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.DELETED, 439ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 440ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_NAME, 44143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.DATA_SET, 44243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 44319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka }; 44419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 44519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int DELETED = 0; 446ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_TYPE = 1; 447ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_NAME = 2; 44843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int DATA_SET = 3; 44943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 4; 45019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 45119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 452c76cdd0723b99f478c9ba5329d14a971cd8dfb3dCostin Manolache public static final String DEFAULT_ACCOUNT_TYPE = "com.google"; 453caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 45471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov /** Sql where statement for filtering on groups. */ 45571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov private static final String CONTACTS_IN_GROUP_SELECT = 45671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov Contacts._ID + " IN " 45771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + RawContacts.CONTACT_ID 45871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.RAW_CONTACTS 45971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN " 46071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 46171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.DATA_JOIN_MIMETYPES 46271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 46371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 46471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + Tables.GROUPS + "." + Groups._ID 46571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.GROUPS 46671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Groups.TITLE + "=?)))"; 46771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov 468a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating DIRTY flag on multiple raw contacts */ 469a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_DIRTY_SQL = 470a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 471a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.DIRTY + "=1" + 472a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 473a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 474a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating VERSION on multiple raw contacts */ 475a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL = 476a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 477a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.VERSION + " = " + RawContacts.VERSION + " + 1" + 478a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 479a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 480c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Current contacts - those contacted within the last 3 days (in seconds) 481c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_CURRENT = 3 * 24 * 60 * 60; 482c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 483c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Recent contacts - those contacted within the last 30 days (in seconds) 484c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_RECENT = 30 * 24 * 60 * 60; 485c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 486f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa private static final String TIME_SINCE_LAST_USED = 487f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa "(strftime('%s', 'now') - " + DataUsageStatColumns.LAST_TIME_USED + "/1000)"; 488f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa 489c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov /* 490c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * Sorting order for email address suggestions: first starred, then the rest. 4912262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * second in_visible_group, then the rest. 4922262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * Within the four (starred/unstarred, in_visible_group/not-in_visible_group) groups 4932262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * - three buckets: very recently contacted, then fairly 494c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * recently contacted, then the rest. Within each of the bucket - descending count 49546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * of times contacted (both for data row and for contact row). If all else fails, alphabetical. 49646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * (Super)primary email address is returned before other addresses for the same contact. 497c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov */ 498c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final String EMAIL_FILTER_SORT_ORDER = 4992262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa Contacts.STARRED + " DESC, " 5002262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa + Contacts.IN_VISIBLE_GROUP + " DESC, " 501f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + "(CASE WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_CURRENT 50246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 0 " 503f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + " WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_RECENT 50446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 1 " 50546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " ELSE 2 END), " 50646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.TIMES_USED + " DESC, " 50746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Contacts.DISPLAY_NAME + ", " 50846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Data.CONTACT_ID + ", " 509c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_SUPER_PRIMARY + " DESC, " 510c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_PRIMARY + " DESC"; 51146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 51246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** Currently same as {@link #EMAIL_FILTER_SORT_ORDER} */ 51346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final String PHONE_FILTER_SORT_ORDER = EMAIL_FILTER_SORT_ORDER; 514c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 515916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Name lookup types used for contact filtering */ 516916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private static final String CONTACT_LOOKUP_NAME_TYPES = 517916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.NAME_COLLATION_KEY + "," + 518916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.EMAIL_BASED_NICKNAME + "," + 51992ddc5cdc4d89ee2c6e861ae7b3a3a913ffa0100Dmitri Plotnikov NameLookupType.NICKNAME; 520916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 521f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov /** 522f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * If any of these columns are used in a Data projection, there is no point in 523f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * using the DISTINCT keyword, which can negatively affect performance. 524f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov */ 525f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov private static final String[] DISTINCT_DATA_PROHIBITING_COLUMNS = { 526f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data._ID, 527f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.RAW_CONTACT_ID, 528f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.NAME_RAW_CONTACT_ID, 529f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 530f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 53143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.DATA_SET, 53243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 533f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.DIRTY, 534f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.NAME_VERIFIED, 535f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.SOURCE_ID, 536f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.VERSION, 537f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov }; 538916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 539f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsColumns = ProjectionMap.builder() 540f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CUSTOM_RINGTONE) 541f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME) 542f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_ALTERNATIVE) 543f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_SOURCE) 544f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.IN_VISIBLE_GROUP) 545f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LAST_TIME_CONTACTED) 546f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LOOKUP_KEY) 547f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME) 548f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME_STYLE) 549f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHOTO_ID) 550f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .add(Contacts.PHOTO_FILE_ID) 5513d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_URI) 5523d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_THUMBNAIL_URI) 553f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SEND_TO_VOICEMAIL) 554f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_ALTERNATIVE) 555f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_PRIMARY) 556f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.STARRED) 557f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.TIMES_CONTACTED) 558cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 559f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 560f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 561f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsPresenceColumns = ProjectionMap.builder() 562f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 563f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE) 564f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 565f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 566f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 567f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 568f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 569f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 570f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 571f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 572f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 573f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 574f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 575f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 576f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 577f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 578f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSnippetColumns = ProjectionMap.builder() 57903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov .add(SearchSnippetColumns.SNIPPET) 580f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 581f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 582f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactColumns = ProjectionMap.builder() 583f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_NAME) 584f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_TYPE) 58543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.DATA_SET) 58643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.ACCOUNT_TYPE_AND_DATA_SET) 587f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DIRTY) 588f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.NAME_VERIFIED) 589f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SOURCE_ID) 590f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.VERSION) 591f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 592f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 593f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactSyncColumns = ProjectionMap.builder() 594f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC1) 595f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC2) 596f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC3) 597f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC4) 598f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 599f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 600f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataColumns = ProjectionMap.builder() 601f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA1) 602f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA2) 603f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA3) 604f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA4) 605f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA5) 606f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA6) 607f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA7) 608f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA8) 609f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA9) 610f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA10) 611f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA11) 612f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA12) 613f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA13) 614f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA14) 615f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA15) 616f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA_VERSION) 617f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_PRIMARY) 618f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_SUPER_PRIMARY) 619f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.MIMETYPE) 620f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RES_PACKAGE) 621f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC1) 622f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC2) 623f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC3) 624f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC4) 625f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(GroupMembership.GROUP_SOURCE_ID) 626f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 627f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 628f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactPresenceColumns = ProjectionMap.builder() 629f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 630f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.PRESENCE) 631f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 632f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.CHAT_CAPABILITY) 633f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 634f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 635f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 636f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 637f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 638f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 639f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 640f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 641f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 642f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 643f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 644f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 645f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataPresenceColumns = ProjectionMap.builder() 646f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.PRESENCE, Tables.PRESENCE + "." + StatusUpdates.PRESENCE) 647f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CHAT_CAPABILITY, Tables.PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 648f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS, StatusUpdatesColumns.CONCRETE_STATUS) 649f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_TIMESTAMP, StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 650f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_RES_PACKAGE, StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 651f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_LABEL, StatusUpdatesColumns.CONCRETE_STATUS_LABEL) 652f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_ICON, StatusUpdatesColumns.CONCRETE_STATUS_ICON) 653f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 654f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 655038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana /** Contains just BaseColumns._COUNT */ 656f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sCountProjectionMap = ProjectionMap.builder() 657f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(BaseColumns._COUNT, "COUNT(*)") 658f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 659f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 660e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov /** Contains just the contacts columns */ 661f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionMap = ProjectionMap.builder() 662f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts._ID) 663f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 664f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.NAME_RAW_CONTACT_ID) 66524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 666f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 667f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsPresenceColumns) 668f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 669f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 670916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Contains just the contacts columns */ 671f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionWithSnippetMap = ProjectionMap.builder() 672f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 673f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sSnippetColumns) 674f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 675916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6765e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar /** Used for pushing starred contacts to the top of a times contacted list **/ 677f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentStarredProjectionMap = ProjectionMap.builder() 678f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 6792f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 680f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 681f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 682f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder() 683f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 6842f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, "SUM(" + DataUsageStatColumns.CONCRETE_TIMES_USED + ")") 685f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 686f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 6874928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 6884928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 6894928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. Right now Starred part just returns NULL for 6904928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * those data columns (frequent part should return real ones in data table). 6914928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 6924928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyStarredProjectionMap 6934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 6944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 6954928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 6964928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER, "NULL") 6974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE, "NULL") 6984928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL, "NULL") 6994928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7004928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 7014928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 7024928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 7034928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. We hard-code {@link Contacts#IS_USER_PROFILE} to NULL, 7044928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * because sContactsProjectionMap specifies a field that doesn't exist in the view behind the 7054928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * query that uses this projection map. 7064928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 7074928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyFrequentProjectionMap 7084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 7094928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 7104928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, DataUsageStatColumns.CONCRETE_TIMES_USED) 7114928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER) 7124928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE) 7134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL) 7144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Contacts.IS_USER_PROFILE, "NULL") 7154928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7164928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 717f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey /** Contains just the contacts vCard columns */ 718f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsVCardProjectionMap = ProjectionMap.builder() 719fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen .add(Contacts._ID) 720f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME + " || '.vcf'") 721f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.SIZE, "NULL") 722f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 723f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 724ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov /** Contains just the raw contacts columns */ 725f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactsProjectionMap = ProjectionMap.builder() 726f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 727f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 728f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 729f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_PRIMARY) 730f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_ALTERNATIVE) 731f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_SOURCE) 732f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME) 733f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME_STYLE) 734f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_PRIMARY) 735f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_ALTERNATIVE) 736f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.TIMES_CONTACTED) 737f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.LAST_TIME_CONTACTED) 738f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CUSTOM_RINGTONE) 739f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SEND_TO_VOICEMAIL) 740f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 741f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.AGGREGATION_MODE) 74224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 743f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 744f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 745f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 746f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 747a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the raw entity view*/ 748f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawEntityProjectionMap = ProjectionMap.builder() 749f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 750f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 751f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.Entity.DATA_ID) 752f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 753f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 75424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 755f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 756f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 757f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 758f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 759f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 760a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the contact entity view*/ 761f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sEntityProjectionMap = ProjectionMap.builder() 762f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity._ID) 763f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.CONTACT_ID) 764f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.RAW_CONTACT_ID) 765f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DATA_ID) 766f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.NAME_RAW_CONTACT_ID) 767f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DELETED) 76824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 769f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 770f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 771f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 772f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 773f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 774f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 775f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 776f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** Contains columns from the data view */ 778f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataProjectionMap = ProjectionMap.builder() 779f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID) 780f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RAW_CONTACT_ID) 781f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CONTACT_ID) 782f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.NAME_RAW_CONTACT_ID) 78324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 784f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 785f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 786f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 787f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 788f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 789f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 790f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7915e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov /** Contains columns from the data view */ 792f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDistinctDataProjectionMap = ProjectionMap.builder() 793f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID, "MIN(" + Data._ID + ")") 794f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 79524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 796f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 797f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 798f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 799f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 800f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 801f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 8029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data and contacts columns, for joined tables */ 803f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sPhoneLookupProjectionMap = ProjectionMap.builder() 804f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup._ID, "contacts_view." + Contacts._ID) 805f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LOOKUP_KEY, "contacts_view." + Contacts.LOOKUP_KEY) 806f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.DISPLAY_NAME, "contacts_view." + Contacts.DISPLAY_NAME) 807f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LAST_TIME_CONTACTED, "contacts_view." + Contacts.LAST_TIME_CONTACTED) 808f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TIMES_CONTACTED, "contacts_view." + Contacts.TIMES_CONTACTED) 809f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.STARRED, "contacts_view." + Contacts.STARRED) 810f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.IN_VISIBLE_GROUP, "contacts_view." + Contacts.IN_VISIBLE_GROUP) 811f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.PHOTO_ID, "contacts_view." + Contacts.PHOTO_ID) 8123d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_URI, "contacts_view." + Contacts.PHOTO_URI) 8133d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_THUMBNAIL_URI, "contacts_view." + Contacts.PHOTO_THUMBNAIL_URI) 814f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.CUSTOM_RINGTONE, "contacts_view." + Contacts.CUSTOM_RINGTONE) 815f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.HAS_PHONE_NUMBER, "contacts_view." + Contacts.HAS_PHONE_NUMBER) 816f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.SEND_TO_VOICEMAIL, "contacts_view." + Contacts.SEND_TO_VOICEMAIL) 817f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.NUMBER, Phone.NUMBER) 818f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TYPE, Phone.TYPE) 819f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LABEL, Phone.LABEL) 8202530512f639c4979fd7371c7dd25dd67e8118124Bai Tao .add(PhoneLookup.NORMALIZED_NUMBER, Phone.NORMALIZED_NUMBER) 821f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 822f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 823ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 824f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsProjectionMap = ProjectionMap.builder() 825f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups._ID) 826f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_NAME) 827f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_TYPE) 82843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.DATA_SET) 82943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.ACCOUNT_TYPE_AND_DATA_SET) 830f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SOURCE_ID) 831f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DIRTY) 832f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.VERSION) 833f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.RES_PACKAGE) 834f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE) 835f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE_RES) 836f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.GROUP_VISIBLE) 837f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYSTEM_ID) 838f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DELETED) 839f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.NOTES) 8401cdfc9dacc136e99d3c0bc5b4212bc3c973be337Daniel Lehmann .add(Groups.ACTION) 8411cdfc9dacc136e99d3c0bc5b4212bc3c973be337Daniel Lehmann .add(Groups.ACTION_URI) 842f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SHOULD_SYNC) 843f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.FAVORITES) 844f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.AUTO_ADD) 845c039cfb78c40730483fd71178df63ada5826a315Dmitri Plotnikov .add(Groups.GROUP_IS_READ_ONLY) 846f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC1) 847f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC2) 848f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC3) 849f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC4) 850f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 851f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 852ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains {@link Groups} columns along with summary details */ 853f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsSummaryProjectionMap = ProjectionMap.builder() 854f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sGroupsProjectionMap) 855f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_COUNT, 856f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 857f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 858f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")") 859f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_WITH_PHONES, 860f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 861f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 862f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " WHERE " + Contacts.HAS_PHONE_NUMBER + ")") 863f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .build(); 864f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa 865f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa // This is only exposed as hidden API for the contacts app, so we can be very specific in 866f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa // the filtering 867f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa private static final ProjectionMap sGroupsSummaryProjectionMapWithGroupCountPerAccount = 868f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa ProjectionMap.builder() 869f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .addAll(sGroupsSummaryProjectionMap) 870f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .add(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 871f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(*) FROM " + Views.GROUPS + " WHERE " 872f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + "(" + Groups.ACCOUNT_NAME + "=" 873f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + GroupsColumns.CONCRETE_ACCOUNT_NAME 874f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " AND " 875f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.ACCOUNT_TYPE + "=" + GroupsColumns.CONCRETE_ACCOUNT_TYPE 876f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " AND " 877f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.DELETED + "=0 AND " 878f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.FAVORITES + "=0 AND " 879f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.AUTO_ADD + "=0" 880f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")" 881f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " GROUP BY " 882f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.ACCOUNT_NAME + ", " + Groups.ACCOUNT_TYPE 883f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")") 884f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 885f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 886373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov /** Contains the agg_exceptions columns */ 887f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sAggregationExceptionsProjectionMap = ProjectionMap.builder() 888f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id") 889f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.TYPE) 890f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID1) 891f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID2) 892f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 893f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 894eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey /** Contains the agg_exceptions columns */ 895f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSettingsProjectionMap = ProjectionMap.builder() 896f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_NAME) 897f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_TYPE) 898f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_VISIBLE) 899f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.SHOULD_SYNC) 900f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ANY_UNSYNCED, 901f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN MIN(" + Settings.SHOULD_SYNC 902f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ",(SELECT " 903f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "(CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL" 904f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 905f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE MIN(" + Groups.SHOULD_SYNC + ")" 906f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)" 907f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.GROUPS 908f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 909f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_NAME 910f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 911f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_TYPE + "))=0" 912f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 913f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE 0" 914f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)") 915f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_COUNT, 916f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 917f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 918f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 919f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 920f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 921f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 922f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_WITH_PHONES, 923f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 924f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 925f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 926f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Contacts.HAS_PHONE_NUMBER 927f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 928f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 929f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 930f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 931f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 93282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov /** Contains StatusUpdates columns */ 933f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStatusUpdatesProjectionMap = ProjectionMap.builder() 934f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PresenceColumns.RAW_CONTACT_ID) 935f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.DATA_ID, DataColumns.CONCRETE_ID) 936f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_ACCOUNT) 937f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_HANDLE) 938f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PROTOCOL) 939f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 940f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // properly enforce uniqueness of null values 941f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CUSTOM_PROTOCOL, 942f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL + "=''" 943f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN NULL" 944f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END)") 945f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PRESENCE) 946f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CHAT_CAPABILITY) 947f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS) 948f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_TIMESTAMP) 949f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_RES_PACKAGE) 950f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_ICON) 951f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_LABEL) 952f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 953f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 9543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Contains StreamItems columns */ 9553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemsProjectionMap = ProjectionMap.builder() 9563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems._ID, StreamItemsColumns.CONCRETE_ID) 9573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(RawContacts.CONTACT_ID) 9583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_PACKAGE) 9603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_ICON) 9613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_LABEL) 9623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TEXT) 9633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TIMESTAMP) 9643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.COMMENTS) 9653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.ACTION) 9663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.ACTION_URI) 9673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemPhotosProjectionMap = ProjectionMap.builder() 9703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos._ID, StreamItemPhotosColumns.CONCRETE_ID) 9713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.STREAM_ITEM_ID) 9733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.SORT_INDEX) 9746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_FILE_ID) 9756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_URI, 9766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro "'" + DisplayPhoto.CONTENT_URI + "'||'/'||" + StreamItemPhotos.PHOTO_FILE_ID) 9773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.ACTION, StreamItemPhotosColumns.CONCRETE_ACTION) 9783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.ACTION_URI, StreamItemPhotosColumns.CONCRETE_ACTION_URI) 9791dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.HEIGHT) 9801dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.WIDTH) 9811dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.FILESIZE) 9823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9841b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov /** Contains Live Folders columns */ 985f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sLiveFoldersProjectionMap = ProjectionMap.builder() 986f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders._ID, Contacts._ID) 987f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders.NAME, Contacts.DISPLAY_NAME) 988f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // TODO: Put contact photo back when we have a way to display a default icon 989f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // for contacts without a photo 990f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // .add(LiveFolders.ICON_BITMAP, Photos.DATA) 991f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 992f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 993d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** Contains {@link Directory} columns */ 994f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDirectoryProjectionMap = ProjectionMap.builder() 995f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory._ID) 996f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.PACKAGE_NAME) 997f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.TYPE_RESOURCE_ID) 998f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DISPLAY_NAME) 999f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DIRECTORY_AUTHORITY) 1000f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_TYPE) 1001f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_NAME) 1002f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.EXPORT_SUPPORT) 1003778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.SHORTCUT_SUPPORT) 1004778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.PHOTO_SUPPORT) 1005f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 10067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // where clause to update the status_updates table 10089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE = 10099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID + 10109705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE + 10119705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE "; 10129705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 10132526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private static final String[] EMPTY_STRING_ARRAY = new String[0]; 10142526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1015bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1016bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Notification ID for failure to import contacts. 1017bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1018bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private static final int LEGACY_IMPORT_FAILED_NOTIFICATION = 1; 101951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 102003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_START_MATCH = "["; 102103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_END_MATCH = "]"; 102203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_ELLIPSIS = "..."; 102303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final int DEFAULT_SNIPPET_ARG_MAX_TOKENS = -10; 102403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 10259a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhoneInitialized; 10269a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhone; 10279a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 1028f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov private StringBuilder mSb = new StringBuilder(); 10291129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs1 = new String[1]; 10301129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs2 = new String[2]; 10312526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private ArrayList<String> mSelectionArgs = Lists.newArrayList(); 10322526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1033f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private Account mAccount; 1034f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 103546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 103646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Stores mapping from type Strings exposed via {@link DataUsageFeedback} to 103746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type integers in {@link DataUsageStatColumns}. 103846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 103946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final Map<String, Integer> sDataUsageTypeMap; 104046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 10414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 10424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 1043a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 1044d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 1045d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 1046a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA); 1047a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES); 10483653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", 10493653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 10502d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", 10512d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov AGGREGATION_SUGGESTIONS); 1052a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO); 1053f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", 1054f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_ID_DISPLAY_PHOTO); 10553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", 10563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_ID_STREAM_ITEMS); 1057c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER); 10585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER); 10595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP); 10602149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA); 10615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID); 10622149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", 10632149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov CONTACTS_LOOKUP_ID_DATA); 1064f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", 1065f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_DISPLAY_PHOTO); 1066f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo", 1067f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_ID_DISPLAY_PHOTO); 1068a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities", 1069a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ENTITIES); 1070a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities", 1071a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ID_ENTITIES); 10723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items", 10733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_STREAM_ITEMS); 10743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items", 10753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_ID_STREAM_ITEMS); 1076f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD); 107742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*", 107842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann CONTACTS_AS_MULTI_VCARD); 10795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT); 1080ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*", 1081ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov CONTACTS_STREQUENT_FILTER); 10825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP); 108345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "contacts/frequent", CONTACTS_FREQUENT); 10843653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 10855ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); 10865ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); 10875ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA); 1088f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/display_photo", 1089f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro RAW_CONTACTS_ID_DISPLAY_PHOTO); 109046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ENTITY_ID); 10913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items", 10923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RAW_CONTACTS_ID_STREAM_ITEMS); 109346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 109446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES); 1095b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 10964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 10974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 1098ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 109948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID); 11005e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER); 1101ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 11024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS); 110348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID); 11041dac83b8fa58944acfd00f44e717a7dddc659d2dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP); 11055e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP); 11065e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER); 11074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER); 1108ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 110948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID); 111046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** "*" is in CSV form with data ids ("123,456,789") */ 111146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/usagefeedback/*", DATA_USAGE_FEEDBACK_ID); 11121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1113ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 1114ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 1115ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 1116ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 111735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 1118b5a4add17815167d20a90645779df34cdf45280dFred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#", 1119b5a4add17815167d20a90645779df34cdf45280dFred Quintana SYNCSTATE_ID); 112035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1121a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 1122b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 1123b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 1124b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 1125b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 11264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1127eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS); 1128eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 112982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES); 113082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID); 11311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1132c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, 1133c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 1134c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 1135c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 11362d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 1137c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SHORTCUT); 1138c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 11391b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts", 11401b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS); 11411b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*", 11421b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_GROUP_NAME); 11431b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones", 11441b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_WITH_PHONES); 11451b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites", 11461b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_FAVORITES); 114709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 114809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS); 1149d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1150d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES); 1151d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID); 11527a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 11537a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME); 115424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 115524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile", PROFILE); 115624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/entities", PROFILE_ENTITIES); 115724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data", PROFILE_DATA); 115824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data/#", PROFILE_DATA_ID); 115924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/as_vcard", PROFILE_AS_VCARD); 116024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts", PROFILE_RAW_CONTACTS); 116124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#", 116224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID); 116324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/data", 116424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_DATA); 116524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/entity", 116624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_ENTITIES); 116746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 11683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items", STREAM_ITEMS); 11693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/photo", STREAM_ITEMS_PHOTOS); 11703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#", STREAM_ITEMS_ID); 11713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo", STREAM_ITEMS_ID_PHOTOS); 11723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo/#", 11733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann STREAM_ITEMS_ID_PHOTOS_ID); 11743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items_limit", STREAM_ITEMS_LIMIT); 11753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 1176f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "display_photo/*", DISPLAY_PHOTO); 1177f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS); 1178f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 117946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa HashMap<String, Integer> tmpTypeMap = new HashMap<String, Integer>(); 118046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_CALL, DataUsageStatColumns.USAGE_TYPE_INT_CALL); 118146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, 118246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT); 118346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, 118446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT); 118546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sDataUsageTypeMap = Collections.unmodifiableMap(tmpTypeMap); 118619a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov } 118719a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov 1188d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static class DirectoryInfo { 1189d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String authority; 1190d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountName; 1191d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountType; 1192d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 1193d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1194d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 1195d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Cached information about contact directories. 1196d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 11974458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private HashMap<String, DirectoryInfo> mDirectoryCache = new HashMap<String, DirectoryInfo>(); 11984458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private boolean mDirectoryCacheValid = false; 1199d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 12003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 120143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * An entry in group id cache. It maps the combination of (account type, account name, data set, 1202ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov * and source id) to group row id. 1203ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov */ 1204e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov public static class GroupIdCacheEntry { 1205ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType; 1206ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName; 120743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet; 1208ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String sourceId; 1209ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov long groupId; 1210ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov } 1211a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov 1212e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // We don't need a soft cache for groups - the assumption is that there will only 1213e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // be a small number of contact groups. The cache is keyed off source id. The value 1214e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // is a list of groups with this group id. 1215e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap(); 1216e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov 121724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 121824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Cached information about the contact ID and raw contact IDs that make up the user's 121924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile entry. 122024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 122124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static class ProfileIdCache { 122224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean inited; 122324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long profileContactId; 122424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Set<Long> profileRawContactIds = Sets.newHashSet(); 122524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Set<Long> profileDataIds = Sets.newHashSet(); 122624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 122724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 122824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Initializes the cache of profile contact and raw contact IDs. Does nothing if 122924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * the cache is already initialized (unless forceRefresh is set to true). 123024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param db The contacts database. 123124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forceRefresh Whether to force re-initialization of the cache. 123224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 123324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void init(SQLiteDatabase db, boolean forceRefresh) { 123424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!inited || forceRefresh) { 123524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileContactId = 0; 123624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactIds.clear(); 123724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileDataIds.clear(); 123824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Cursor c = db.rawQuery("SELECT " + 123924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_CONTACT_ID + "," + 124024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "," + 124124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro DataColumns.CONCRETE_ID + 124224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro " FROM " + Tables.RAW_CONTACTS + " JOIN " + Tables.ACCOUNTS + " ON " + 124324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "=" + 124424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro AccountsColumns.PROFILE_RAW_CONTACT_ID + 124524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro " JOIN " + Tables.DATA + " ON " + 124624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContactsColumns.CONCRETE_ID + "=" + DataColumns.CONCRETE_RAW_CONTACT_ID, 124724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro null); 124824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro try { 124924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro while (c.moveToNext()) { 125024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (profileContactId == 0) { 125124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileContactId = c.getLong(0); 125224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 125324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactIds.add(c.getLong(1)); 125424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileDataIds.add(c.getLong(2)); 125524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 125624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } finally { 125724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro c.close(); 125824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 125924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 126024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 126124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 126224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 126324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private ProfileIdCache mProfileIdCache; 126424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1265f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1266f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of display photos. Larger images will be scaled 1267f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to fit. 1268f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1269f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxDisplayPhotoDim; 1270f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of photo thumbnails. 1273f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1274f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxThumbnailPhotoDim; 1275f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private HashMap<String, DataRowHandler> mDataRowHandlers; 1277b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private ContactsDatabaseHelper mDbHelper; 127831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1279f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private PhotoStore mPhotoStore; 1280f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12814097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 1282f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private NameLookupBuilder mNameLookupBuilder; 1283315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov 1284622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private PostalSplitter mPostalSplitter; 1285622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey 128672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov private ContactDirectoryManager mContactDirectoryManager; 1287622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private ContactAggregator mContactAggregator; 1288f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 1289a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private GlobalSearchSupport mGlobalSearchSupport; 1290d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov private CommonNicknameCache mCommonNicknameCache; 1291f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov private SearchIndexManager mSearchIndexManager; 1292a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 129320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private ContentValues mValues = new ContentValues(); 129473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov private HashMap<String, Boolean> mAccountWritability = Maps.newHashMap(); 129520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 129609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private int mProviderStatus = ProviderStatus.STATUS_NORMAL; 12973826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private boolean mProviderStatusUpdateNeeded; 129809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private long mEstimatedStorageRequirement = 0; 129915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mReadAccessLatch; 130015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mWriteAccessLatch; 130115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private boolean mAccountUpdateListenerRegistered; 1302bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private boolean mOkToOpenAccess = true; 130373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 1304d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private TransactionContext mTransactionContext = new TransactionContext(); 1305de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov 13061a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey private boolean mVisibleTouched = false; 13071a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 130881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov private boolean mSyncToNetwork; 130981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 13104cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao private Locale mCurrentLocale; 13113826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private int mContactsAccountCount; 1312d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov 1313bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private HandlerThread mBackgroundThread; 1314bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private Handler mBackgroundHandler; 1315bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1316f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mLastPhotoCleanup = 0; 1317f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 13184f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 13194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 1320de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov super.onCreate(); 1321ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov try { 1322ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return initialize(); 1323ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } catch (RuntimeException e) { 1324ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov Log.e(TAG, "Cannot start provider", e); 1325ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return false; 1326ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 1327ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 132835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1329ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov private boolean initialize() { 133015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov StrictMode.setThreadPolicy( 133115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 133215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 13333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Resources resources = getContext().getResources(); 1334f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxDisplayPhotoDim = resources.getInteger( 1335f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_display_photo_dim); 1336f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim = resources.getInteger( 1337f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_thumbnail_photo_dim); 13383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 133924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mProfileIdCache = new ProfileIdCache(); 1340b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper = (ContactsDatabaseHelper)getDatabaseHelper(); 134172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov mContactDirectoryManager = new ContactDirectoryManager(this); 1342a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov mGlobalSearchSupport = new GlobalSearchSupport(this); 1343f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mPhotoStore = new PhotoStore(getContext().getFilesDir(), mDbHelper); 134465ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov 1345bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // The provider is closed for business until fully initialized 134615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = new CountDownLatch(1); 134715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = new CountDownLatch(1); 134872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1349bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread = new HandlerThread("ContactsProviderWorker", 1350bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov Process.THREAD_PRIORITY_BACKGROUND); 1351bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread.start(); 1352bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler = new Handler(mBackgroundThread.getLooper()) { 1353bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov @Override 1354bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov public void handleMessage(Message msg) { 1355bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov performBackgroundTask(msg.what, msg.obj); 1356bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1357bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov }; 13582a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov 135915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_INITIALIZE); 1360bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1361bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 1362bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_LOCALE); 1363bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM); 136405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_SEARCH_INDEX); 1365bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_PROVIDER_STATUS); 136615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_OPEN_WRITE_ACCESS); 1367f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 13683826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 136949d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov return true; 13704f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 13714f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1372767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov /** 137351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * (Re)allocates all locale-sensitive structures. 137451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 137504b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov private void initForDefaultLocale() { 137615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 137715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mLegacyApiSupport = new LegacyApiSupport(context, mDbHelper, this, mGlobalSearchSupport); 13784cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mCurrentLocale = getLocale(); 137904b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov mNameSplitter = mDbHelper.createNameSplitter(); 13804cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter); 13814cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mPostalSplitter = new PostalSplitter(mCurrentLocale); 138251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov mCommonNicknameCache = new CommonNicknameCache(mDbHelper.getReadableDatabase()); 1383cdd03b2ba03718a7fa85663a2438136284a1557cBai Tao ContactLocaleUtils.getIntance().setLocale(mCurrentLocale); 13845b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator = new ContactAggregator(this, mDbHelper, 138515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 13865b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 1387f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov mSearchIndexManager = new SearchIndexManager(this); 13885b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 1389bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers = new HashMap<String, DataRowHandler>(); 1390bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1391bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, 13926d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForEmail(context, mDbHelper, mContactAggregator)); 1393bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE, 13946d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForIm(context, mDbHelper, mContactAggregator)); 1395bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, 13966d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForOrganization(context, mDbHelper, mContactAggregator)); 1397bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, 13986d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForPhoneNumber(context, mDbHelper, mContactAggregator)); 1399bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, 14006d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForNickname(context, mDbHelper, mContactAggregator)); 1401bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE, 14026d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForStructuredName(context, mDbHelper, mContactAggregator, 1403bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mNameSplitter, mNameLookupBuilder)); 1404bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(StructuredPostal.CONTENT_ITEM_TYPE, 14056d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForStructuredPostal(context, mDbHelper, mContactAggregator, 1406bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mPostalSplitter)); 1407bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE, 14086d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForGroupMembership(context, mDbHelper, mContactAggregator, 1409bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mGroupIdCache)); 1410bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers.put(Photo.CONTENT_ITEM_TYPE, 1411f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new DataRowHandlerForPhoto(context, mDbHelper, mContactAggregator, mPhotoStore)); 14126d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov mDataRowHandlers.put(Note.CONTENT_ITEM_TYPE, 14136d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov new DataRowHandlerForNote(context, mDbHelper, mContactAggregator)); 1414bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1415bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1416bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /** 1417bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Visible for testing. 1418bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov */ 1419bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /* package */ PhotoPriorityResolver createPhotoPriorityResolver(Context context) { 1420bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov return new PhotoPriorityResolver(context); 1421bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1422bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1423bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task) { 1424bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendEmptyMessage(task); 1425bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1426bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1427bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task, Object arg) { 1428bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(task, arg)); 1429bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1430bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1431bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void performBackgroundTask(int task, Object arg) { 1432bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov switch (task) { 143315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_INITIALIZE: { 143415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov initForDefaultLocale(); 143515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch.countDown(); 143615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = null; 143715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov break; 143815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 143915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 144015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_OPEN_WRITE_ACCESS: { 1441bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (mOkToOpenAccess) { 144215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch.countDown(); 144315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = null; 1444bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1445bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1446bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1447bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1448bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS: { 1449bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isLegacyContactImportNeeded()) { 1450bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov importLegacyContactsInBackground(); 1451bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1452bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1453bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1454bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1455bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_ACCOUNTS: { 145615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 145715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (!mAccountUpdateListenerRegistered) { 145815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov AccountManager.get(context).addOnAccountsUpdatedListener(this, null, false); 145915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mAccountUpdateListenerRegistered = true; 146015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 146115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 146215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Account[] accounts = AccountManager.get(context).getAccounts(); 1463bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov boolean accountsChanged = updateAccountsInBackground(accounts); 1464bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateContactsAccountCount(accounts); 1465bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateDirectoriesInBackground(accountsChanged); 1466bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1467bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1468bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1469bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_LOCALE: { 1470bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateLocaleInBackground(); 1471bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1472bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1473bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1474fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov case BACKGROUND_TASK_CHANGE_LOCALE: { 1475fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov changeLocaleInBackground(); 1476fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov break; 1477fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1478fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1479bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM: { 1480bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isAggregationUpgradeNeeded()) { 1481bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov upgradeAggregationAlgorithmInBackground(); 1482bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1483bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1484bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1485bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 148605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_SEARCH_INDEX: { 148705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov updateSearchIndexInBackground(); 148805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov break; 148905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 149005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1491bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_PROVIDER_STATUS: { 1492bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateProviderStatus(); 1493bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1494bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1495bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1496bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_DIRECTORIES: { 1497bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (arg != null) { 1498bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.onPackageChanged((String) arg); 1499bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1500bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1501bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1502f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1503f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case BACKGROUND_TASK_CLEANUP_PHOTOS: { 1504f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check rate limit. 1505f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long now = System.currentTimeMillis(); 1506f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (now - mLastPhotoCleanup > PHOTO_CLEANUP_RATE_LIMIT) { 1507f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mLastPhotoCleanup = now; 1508f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupPhotoStore(); 1509f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro break; 1510f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1511f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1512bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 15134cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 15144cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao 151553fac8f99f3884c372c907a76766d27fa9e1d95fDmitri Plotnikov public void onLocaleChanged() { 15163826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 15173826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 15184f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov return; 15194f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov } 15204f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov 1521fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_CHANGE_LOCALE); 15224cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 152351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 152451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov /** 152551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * Verifies that the contacts database is properly configured for the current locale. 152651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * If not, changes the database locale to the current locale using an asynchronous task. 152751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * This needs to be done asynchronously because the process involves rebuilding 152851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * large data structures (name lookup, sort keys), which can take minutes on 152951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * a large set of contacts. 153051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 1531bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateLocaleInBackground() { 1532f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 1533f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov // The process is already running - postpone the change 1534f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov if (mProviderStatus == ProviderStatus.STATUS_CHANGING_LOCALE) { 1535f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov return; 1536f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov } 1537f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 153851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 153951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final String providerLocale = prefs.getString(PREF_LOCALE, null); 154051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final Locale currentLocale = mCurrentLocale; 154151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov if (currentLocale.toString().equals(providerLocale)) { 154251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov return; 154351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 154451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 154551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov int providerStatus = mProviderStatus; 154651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_CHANGING_LOCALE); 1547bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDbHelper.setLocale(this, currentLocale); 1548bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).apply(); 1549bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov setProviderStatus(providerStatus); 1550bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 155151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 1552fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov /** 1553fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov * Reinitializes the provider for a new locale. 1554fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov */ 1555fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov private void changeLocaleInBackground() { 1556fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Re-initializing the provider without stopping it. 1557fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Locking the database will prevent inserts/updates/deletes from 1558fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // running at the same time, but queries may still be running 1559fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // on other threads. Those queries may return inconsistent results. 1560fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov SQLiteDatabase db = mDbHelper.getWritableDatabase(); 1561fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.beginTransaction(); 1562fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov try { 1563fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov initForDefaultLocale(); 1564fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.setTransactionSuccessful(); 1565fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } finally { 1566fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.endTransaction(); 1567fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1568fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1569fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov updateLocaleInBackground(); 1570fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1571fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 157205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov protected void updateSearchIndexInBackground() { 157305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov mSearchIndexManager.updateIndex(); 157405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 157505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1576bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateDirectoriesInBackground(boolean rescan) { 1577bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanAllPackages(rescan); 157851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 157951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 15803826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateProviderStatus() { 15813826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 15823826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 15833826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return; 15843826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15853826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 15863826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mContactsAccountCount == 0 158749d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov && DatabaseUtils.queryNumEntries(mDbHelper.getReadableDatabase(), 158849d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Tables.CONTACTS, null) == 0) { 15893826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 15903826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } else { 15913826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 15923826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15933826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 15943826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 159531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* Visible for testing */ 1596f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro protected void cleanupPhotoStore() { 15976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro SQLiteDatabase db = mDbHelper.getWritableDatabase(); 15986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 15996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Assemble the set of photo store file IDs that are in use, and send those to the photo 1600f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // store. Any photos that aren't in that set will be deleted, and any photos that no 1601f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // longer exist in the photo store will be returned for us to clear out in the DB. 16026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = db.query(Views.DATA, new String[]{Data._ID, Photo.PHOTO_FILE_ID}, 1603f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.MIMETYPE + "=" + Photo.MIMETYPE + " AND " 1604f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro + Photo.PHOTO_FILE_ID + " IS NOT NULL", null, null, null, null); 16056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> usedPhotoFileIds = Sets.newHashSet(); 16066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToDataId = Maps.newHashMap(); 1607f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1608f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro while (c.moveToNext()) { 16096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = c.getLong(0); 16106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(1); 16116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 16126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToDataId.put(photoFileId, dataId); 16136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 16146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 16156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 16166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 16176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 16186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Also query for all social stream item photos. 16196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c = db.query(Tables.STREAM_ITEM_PHOTOS, 16206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{ 16216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos._ID, 16226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.STREAM_ITEM_ID, 16236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.PHOTO_FILE_ID 16246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro }, 16256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro null, null, null, null, null); 16266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToStreamItemPhotoId = Maps.newHashMap(); 16276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> streamItemPhotoIdToStreamItemId = Maps.newHashMap(); 16286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 16296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro while (c.moveToNext()) { 16306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = c.getLong(0); 16316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = c.getLong(1); 16326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(2); 16336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 16346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToStreamItemPhotoId.put(photoFileId, streamItemPhotoId); 16356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemPhotoIdToStreamItemId.put(streamItemPhotoId, streamItemId); 1636f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1637f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 1638f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 1639f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1640f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1641f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Run the photo store cleanup. 16426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> missingPhotoIds = mPhotoStore.cleanup(usedPhotoFileIds); 1643f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1644f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If any of the keys we're using no longer exist, clean them up. 16456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!missingPhotoIds.isEmpty()) { 1646f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 16476802030a777c0c3ba1dc029c534cca4784260632Dave Santoro for (long missingPhotoId : missingPhotoIds) { 16486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToDataId.containsKey(missingPhotoId)) { 16496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = photoFileIdToDataId.get(missingPhotoId); 1650f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 1651f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.putNull(Photo.PHOTO_FILE_ID); 1652f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ops.add(ContentProviderOperation.newUpdate( 16536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentUris.withAppendedId(Data.CONTENT_URI, dataId)) 1654f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .withValues(updateValues).build()); 1655f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 16566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToStreamItemPhotoId.containsKey(missingPhotoId)) { 16576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For missing photos that were in stream item photos, just delete the stream 16586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // item photo. 16596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = photoFileIdToStreamItemPhotoId.get(missingPhotoId); 16606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = streamItemPhotoIdToStreamItemId.get(streamItemPhotoId); 16616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ops.add(ContentProviderOperation.newDelete( 16626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.CONTENT_URI.buildUpon() 16636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemId)) 16646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY) 16656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemPhotoId)) 16666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .build()).build()); 16676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 1668f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1669f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1670f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro applyBatch(ops); 1671f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (OperationApplicationException oae) { 1672f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Not a fatal problem (and we'll try again on the next cleanup). 1673f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Failed to clean up outdated photo references", oae); 1674f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1675f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1676f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1677f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1678f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* Visible for testing */ 1679de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov @Override 1680b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 1681b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return ContactsDatabaseHelper.getInstance(context); 168231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 168331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 1684f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* package */ PhotoStore getPhotoStore() { 1685f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return mPhotoStore; 1686f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1687f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 168887614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxDisplayPhotoDim() { 168987614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxDisplayPhotoDim; 169087614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 169187614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 169287614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxThumbnailPhotoDim() { 169387614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxThumbnailPhotoDim; 169487614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 169587614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1696013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov /* package */ NameSplitter getNameSplitter() { 1697013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov return mNameSplitter; 1698013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov } 1699013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov 17005df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov /* package */ NameLookupBuilder getNameLookupBuilder() { 17015df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov return mNameLookupBuilder; 17025df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov } 17035df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov 17045dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov /* Visible for testing */ 1705ed78fd6df5e9f3a2d572162e5d374d1f4a625bddDmitri Plotnikov public ContactDirectoryManager getContactDirectoryManagerForTest() { 170672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov return mContactDirectoryManager; 170772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 170872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 170972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov /* Visible for testing */ 17105dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov protected Locale getLocale() { 17115dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov return Locale.getDefault(); 17125dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov } 17135dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 17143d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov protected boolean isLegacyContactImportNeeded() { 1715b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_CONTACTS_IMPORTED, "0")); 1716b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov return version < PROPERTY_CONTACTS_IMPORT_VERSION; 17173d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17183d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1719568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov protected LegacyContactImporter getLegacyContactImporter() { 1720568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return new LegacyContactImporter(getContext(), this); 1721568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1722568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1723568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 1724bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Imports legacy contacts as a background task. 1725568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 1726bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private void importLegacyContactsInBackground() { 1727bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Importing legacy contacts"); 1728bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADING); 1729568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1730bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 1731bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDbHelper.setLocale(this, mCurrentLocale); 1732bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, mCurrentLocale.toString()).commit(); 1733568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1734bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov LegacyContactImporter importer = getLegacyContactImporter(); 1735bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (importLegacyContacts(importer)) { 1736bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportSuccess(); 1737bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } else { 1738bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportFailure(); 1739bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1740568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1741568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1742bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1743bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Unlocks the provider and declares that the import process is complete. 1744bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1745bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportSuccess() { 1746bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1747bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)getContext().getSystemService(Context.NOTIFICATION_SERVICE); 1748bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.cancel(LEGACY_IMPORT_FAILED_NOTIFICATION); 1749bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1750b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov // Store a property in the database indicating that the conversion process succeeded 1751b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov mDbHelper.setProperty(PROPERTY_CONTACTS_IMPORTED, 1752b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov String.valueOf(PROPERTY_CONTACTS_IMPORT_VERSION)); 1753bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 1754bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Completed import of legacy contacts"); 1755bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1756bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1757bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1758bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Announces the provider status and keeps the provider locked. 1759bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1760bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportFailure() { 1761bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Context context = getContext(); 1762bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1763bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); 1764bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1765bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // Show a notification 1766bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Notification n = new Notification(android.R.drawable.stat_notify_error, 1767bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_ticker), 1768bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov System.currentTimeMillis()); 1769bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.setLatestEventInfo(context, 1770bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_title), 1771bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_text), 1772bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov PendingIntent.getActivity(context, 0, new Intent(Intents.UI.LIST_DEFAULT), 0)); 1773bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; 1774bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1775bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.notify(LEGACY_IMPORT_FAILED_NOTIFICATION, n); 1776bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1777bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADE_OUT_OF_MEMORY); 1778bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Failed to import legacy contacts"); 1779bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1780bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // Do not let any database changes until this issue is resolved. 1781bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mOkToOpenAccess = false; 17823d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 17833d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 17843d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /* Visible for testing */ 1785568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /* package */ boolean importLegacyContacts(LegacyContactImporter importer) { 17860e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff boolean aggregatorEnabled = mContactAggregator.isEnabled(); 17873d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov mContactAggregator.setEnabled(false); 17883d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov try { 1789bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (importer.importContacts()) { 1790bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1791bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // TODO aggregate all newly added raw contacts 1792bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mContactAggregator.setEnabled(aggregatorEnabled); 1793bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return true; 1794bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 17953d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } catch (Throwable e) { 17963d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov Log.e(TAG, "Legacy contact import failed", e); 17973d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 1798bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mEstimatedStorageRequirement = importer.getEstimatedStorageRequirement(); 1799bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return false; 18003d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 18013d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1802a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 1803a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 1804a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 1805a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /* package */ void wipeData() { 1806b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.wipeData(); 1807f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mPhotoStore.clear(); 18083826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS; 1809a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 1810a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1811568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 181215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov * During intialization, this content provider will 1813568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * block all attempts to change contacts data. In particular, it will hold 1814568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * up all contact syncs. As soon as the import process is complete, all 1815568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * processes waiting to write to the provider are unblocked and can proceed 1816568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * to compete for the database transaction monitor. 1817568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 181815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private void waitForAccess(CountDownLatch latch) { 181915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (latch == null) { 182015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 182115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 182215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 182315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov while (true) { 182415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov try { 182515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov latch.await(); 182615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 182715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } catch (InterruptedException e) { 182815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Thread.currentThread().interrupt(); 1829ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov } 1830568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1831568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1832568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1833568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1834568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public Uri insert(Uri uri, ContentValues values) { 183515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1836568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.insert(uri, values); 1837568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1838568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1839568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1840568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 184115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (mWriteAccessLatch != null) { 1842bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // We are stuck trying to upgrade contacts db. The only update request 1843bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // allowed in this case is an update of provider status, which will trigger 1844bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // an attempt to upgrade contacts again. 1845bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov int match = sUriMatcher.match(uri); 1846bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (match == PROVIDER_STATUS) { 1847bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Integer newStatus = values.getAsInteger(ProviderStatus.STATUS); 1848bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (newStatus != null && newStatus == ProviderStatus.STATUS_UPGRADING) { 1849bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1850bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 1; 1851bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } else { 1852bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 0; 1853bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1854bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1855bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 185615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1857568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.update(uri, values, selection, selectionArgs); 1858568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1859568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1860568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1861568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int delete(Uri uri, String selection, String[] selectionArgs) { 186215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1863568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.delete(uri, selection, selectionArgs); 1864568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1865568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1866568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1867568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 1868568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov throws OperationApplicationException { 186915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 1870568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return super.applyBatch(operations); 1871568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1872568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 18734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 18747b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov public int bulkInsert(Uri uri, ContentValues[] values) { 18757b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov waitForAccess(mWriteAccessLatch); 18767b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov return super.bulkInsert(uri, values); 18777b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov } 18787b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov 18797b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov @Override 1880285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void onBeginTransaction() { 1881bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1882b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "onBeginTransaction"); 1883b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1884285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.onBeginTransaction(); 18851ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana mContactAggregator.clearPendingAggregations(); 1886d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.clear(); 1887b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1888b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1889285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 1890285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 1891285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void beforeTransactionCommit() { 18921129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 1893bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1894b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "beforeTransactionCommit"); 1895b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1896285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.beforeTransactionCommit(); 1897b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 1898bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateInTransaction(mTransactionContext, mDb); 18991a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (mVisibleTouched) { 19001a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = false; 1901b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.updateAllVisible(); 19021a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey } 19033826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 1904bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 1905bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 19063826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatusUpdateNeeded) { 19073826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 19083826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = false; 19093826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 1910b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1911b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1912bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov private void updateSearchIndexInTransaction() { 1913bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov Set<Long> staleContacts = mTransactionContext.getStaleSearchIndexContactIds(); 1914bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov Set<Long> staleRawContacts = mTransactionContext.getStaleSearchIndexRawContactIds(); 1915bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov if (!staleContacts.isEmpty() || !staleRawContacts.isEmpty()) { 1916bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mSearchIndexManager.updateIndexForRawContacts(staleContacts, staleRawContacts); 1917bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mTransactionContext.clearSearchIndexUpdates(); 1918bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 1919bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 1920bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 1921b5a4add17815167d20a90645779df34cdf45280dFred Quintana private void flushTransactionalChanges() { 1922bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 1923b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "flushTransactionChanges"); 1924b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 19251129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 192624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Determine whether we need to refresh the profile ID cache. 192724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean profileCacheRefreshNeeded = false; 192824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1929d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov for (long rawContactId : mTransactionContext.getInsertedRawContactIds()) { 19308ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(mDb, rawContactId); 1931bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.onRawContactInsert(mTransactionContext, mDb, rawContactId); 1932285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 1933b5a4add17815167d20a90645779df34cdf45280dFred Quintana 193443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Map<Long, AccountWithDataSet> insertedProfileRawContactAccountMap = 193524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mTransactionContext.getInsertedProfileRawContactIds(); 193624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!insertedProfileRawContactAccountMap.isEmpty()) { 193724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro for (long profileRawContactId : insertedProfileRawContactAccountMap.keySet()) { 193824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mDbHelper.updateRawContactDisplayName(mDb, profileRawContactId); 193924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mContactAggregator.onProfileRawContactInsert(mTransactionContext, mDb, 194024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileRawContactId, 194124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro insertedProfileRawContactAccountMap.get(profileRawContactId)); 194224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 194324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = true; 194424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 194524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1946d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov Set<Long> dirtyRawContacts = mTransactionContext.getDirtyRawContactIds(); 1947d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!dirtyRawContacts.isEmpty()) { 1948a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 1949a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL); 1950d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, dirtyRawContacts); 1951a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 1952a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mDb.execSQL(mSb.toString()); 195324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 195424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = profileCacheRefreshNeeded || 195524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro !Collections.disjoint(mProfileIdCache.profileRawContactIds, dirtyRawContacts); 1956a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov } 1957a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 1958d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov Set<Long> updatedRawContacts = mTransactionContext.getUpdatedRawContactIds(); 1959d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!updatedRawContacts.isEmpty()) { 1960a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 1961a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL); 1962d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, updatedRawContacts); 1963a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 1964a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mDb.execSQL(mSb.toString()); 196524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 196624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileCacheRefreshNeeded = profileCacheRefreshNeeded || 196724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro !Collections.disjoint(mProfileIdCache.profileRawContactIds, updatedRawContacts); 1968b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1969b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1970d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov for (Map.Entry<Long, Object> entry : mTransactionContext.getUpdatedSyncStates()) { 1971b5a4add17815167d20a90645779df34cdf45280dFred Quintana long id = entry.getKey(); 19729d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana if (mDbHelper.getSyncState().update(mDb, id, entry.getValue()) <= 0) { 19739d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana throw new IllegalStateException( 19749d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana "unable to update sync state, does it still exist?"); 19759d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana } 1976b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1977b5a4add17815167d20a90645779df34cdf45280dFred Quintana 197824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (profileCacheRefreshNeeded) { 197924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Force the profile ID cache to refresh. 198024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mProfileIdCache.init(mDb, true); 198124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 198224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 1983d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.clear(); 1984b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1985b5a4add17815167d20a90645779df34cdf45280dFred Quintana 1986a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** 1987a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * Appends comma separated ids. 1988a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * @param ids Should not be empty 1989a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov */ 1990d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private void appendIds(StringBuilder sb, Set<Long> ids) { 1991b5a4add17815167d20a90645779df34cdf45280dFred Quintana for (long id : ids) { 1992a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(id).append(','); 1993b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 1994a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 1995a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.setLength(sb.length() - 1); // Yank the last comma 1996285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 1997285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 199824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 199924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given contact ID represents the user's personal profile - if it is, calls 200024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * a permission check (for writing the profile if forWrite is true, for reading the profile 200124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * otherwise). If the contact ID is not the user's profile, no check is executed. 2002afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 200324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param contactId The contact ID to be checked. 200424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 200524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 2006afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForContact(SQLiteDatabase db, long contactId, 2007afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro boolean forWrite) { 2008afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 200924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileContactId == contactId) { 201024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 201124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 201224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 201324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 201424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 201524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given raw contact ID is a member of the user's personal profile - if it 201624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * is, calls a permission check (for writing the profile if forWrite is true, for reading the 201724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile otherwise). If the raw contact ID is not in the user's profile, no check is 201824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * executed. 2019afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 202024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param rawContactId The raw contact ID to be checked. 202124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 202224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 2023afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForRawContact(SQLiteDatabase db, long rawContactId, 2024afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro boolean forWrite) { 2025afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 202624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileRawContactIds.contains(rawContactId)) { 202724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 202824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 202924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 203024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 203124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 203224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Checks whether the given data ID is a member of the user's personal profile - if it is, 203324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * calls a permission check (for writing the profile if forWrite is true, for reading the 203424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * profile otherwise). If the data ID is not in the user's profile, no check is executed. 2035afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro * @param db The database. 203624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param dataId The data ID to be checked. 203724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 203824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 2039afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private void enforceProfilePermissionForData(SQLiteDatabase db, long dataId, boolean forWrite) { 2040afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro mProfileIdCache.init(db, false); 204124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (mProfileIdCache.profileDataIds.contains(dataId)) { 204224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(forWrite); 204324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 204424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 204524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 204624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 204724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Performs a permission check for WRITE_PROFILE or READ_PROFILE (depending on the parameter). 204824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * If the permission check fails, this will throw a SecurityException. 204924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forWrite Whether the caller is attempting to do a write (vs. read) operation. 205024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro */ 205124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void enforceProfilePermission(boolean forWrite) { 205224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String profilePermission = forWrite 205324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro ? "android.permission.WRITE_PROFILE" 205424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro : "android.permission.READ_PROFILE"; 205524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro getContext().enforceCallingOrSelfPermission(profilePermission, null); 205624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 205724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2058285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2059cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov protected void notifyChange() { 206081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov notifyChange(mSyncToNetwork); 206181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = false; 206281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 206381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 206481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov protected void notifyChange(boolean syncToNetwork) { 206581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null, 206681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov syncToNetwork); 2067cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov } 2068568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 206951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov protected void setProviderStatus(int status) { 20703826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != status) { 20713826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = status; 20723826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov getContext().getContentResolver().notifyChange(ProviderStatus.CONTENT_URI, null, false); 20733826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 207451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 207551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 2076f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public DataRowHandler getDataRowHandler(final String mimeType) { 20773cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataRowHandler handler = mDataRowHandlers.get(mimeType); 20783cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (handler == null) { 20796d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov handler = new DataRowHandlerForCustomMimetype( 20806d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov getContext(), mDbHelper, mContactAggregator, mimeType); 20813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(mimeType, handler); 20823cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 20833cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return handler; 20843cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 20853cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 20864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 2087de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected Uri insertInTransaction(Uri uri, ContentValues values) { 2088bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 20891129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Log.v(TAG, "insertInTransaction: " + uri + " " + values); 2090b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2091f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2092f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 2093f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 2094f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2095a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 2096a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 209735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2098a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 209935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 2100b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov id = mDbHelper.getSyncState().insert(mDb, values); 210135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 210235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2103d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 2104d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov insertContact(values); 21056bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 21066bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 21076bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 210824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 210924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro throw new UnsupportedOperationException( 211024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "The profile contact is created automatically"); 211124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 211224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 21135ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 211424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter, false); 2115f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2116a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2117a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2118a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21195ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 21205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 2121f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2122f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2123a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2124a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2125a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 21273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItems.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 21283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 21293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 213324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 213424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(true); 213524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter, true); 213624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mSyncToNetwork |= !callerIsSyncAdapter; 213724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 213824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 213924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2140a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case DATA: { 2141f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2142f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2143a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2144a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2145a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2146ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 2147f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov id = insertGroup(uri, values, callerIsSyncAdapter); 2148f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2149ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2150ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2151ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2152eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 21535aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey id = insertSettings(uri, values); 215443880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 2155eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 2156eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 2157eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 215882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 215982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov id = insertStatusUpdate(values); 21601f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 21611f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 21621f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 21633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 21643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 21653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 21693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 21703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 21713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 21753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 21763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItemPhotos.STREAM_ITEM_ID, uri.getPathSegments().get(1)); 21773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 21783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 21793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 21803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 21813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2182a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 218381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 2184f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 2185a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2186a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 21877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 21887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 21897e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 21907e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2191de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return ContentUris.withAppendedId(uri, id); 2192a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2193a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2194a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2195e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * If account is non-null then store it in the values. If the account is 2196e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * already specified in the values then it must be consistent with the 2197e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * account, if it is non-null. 2198e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * 2199e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param uri Current {@link Uri} being operated on. 2200e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param values {@link ContentValues} to read and possibly update. 2201e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when only one of 2202e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_NAME} or 2203e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the 2204e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * other undefined. 2205e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME} 2206e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between 2207e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * the given {@link Uri} and {@link ContentValues}. 22087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 2209e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException { 2210f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 2211f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 2212e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 2213f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2214f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME); 2215f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 2216e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialValues = TextUtils.isEmpty(valueAccountName) 2217e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey ^ TextUtils.isEmpty(valueAccountType); 2218e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2219e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri || partialValues) { 2220e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 2221fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 2222fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 2223e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2224e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2225e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 2226e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 2227e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validUri = !TextUtils.isEmpty(accountName); 2228e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validValues = !TextUtils.isEmpty(valueAccountName); 2229e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2230e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validValues && validUri) { 2231e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Check that accounts match when both present 2232e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean accountMatch = TextUtils.equals(accountName, valueAccountName) 2233e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey && TextUtils.equals(accountType, valueAccountType); 2234e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (!accountMatch) { 2235fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 2236fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "When both specified, ACCOUNT_NAME and ACCOUNT_TYPE must match", uri)); 2237e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2238e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validUri) { 2239e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Fill values from Uri when not present 2240f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_NAME, accountName); 2241f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_TYPE, accountType); 2242e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validValues) { 2243f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountName = valueAccountName; 2244f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountType = valueAccountType; 2245e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else { 2246e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return null; 2247f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 2248f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2249e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Use cached Account object when matches, otherwise create 2250f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mAccount == null 2251f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.name.equals(accountName) 2252f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.type.equals(accountType)) { 2253f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mAccount = new Account(accountName, accountType); 2254035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 2255f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2256e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return mAccount; 22577e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 22587e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 22597e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 226043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Resolves the account and builds an {@link AccountWithDataSet} based on the data set specified 226143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * in the URI or values (if any). 226243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param uri Current {@link Uri} being operated on. 226343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param values {@link ContentValues} to read and possibly update. 226443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro */ 226543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private AccountWithDataSet resolveAccountWithDataSet(Uri uri, ContentValues values) { 226643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final Account account = resolveAccount(uri, mValues); 226743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = null; 226843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (account != null) { 226943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 227043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (dataSet == null) { 227143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro dataSet = mValues.getAsString(RawContacts.DATA_SET); 227243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 227343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet = new AccountWithDataSet(account.name, account.type, dataSet); 227443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 227543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro return accountWithDataSet; 227643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 227743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 227843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro /** 2279d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov * Inserts an item in the contacts table 22806bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 22816bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 22826bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 22836bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 2284d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private long insertContact(ContentValues values) { 2285de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new UnsupportedOperationException("Aggregate contacts are created automatically"); 22866bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 22876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 22886bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 228924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Inserts an item in the raw contacts table 2290a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2291f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param uri the values for the new row 2292f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param values the account this contact should be associated with. may be null. 2293dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana * @param callerIsSyncAdapter 229424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * @param forProfile Whether this raw contact is being inserted into the user's profile. 2295a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2296a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 229724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private long insertRawContact(Uri uri, ContentValues values, boolean callerIsSyncAdapter, 229824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean forProfile) { 2299f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2300f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2301f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 2302f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 230343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = resolveAccountWithDataSet(uri, mValues); 23047e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 23053d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov if (values.containsKey(RawContacts.DELETED) 23063d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov && values.getAsInteger(RawContacts.DELETED) != 0) { 2307f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 23083d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 23093d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2310f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov long rawContactId = mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, mValues); 2311f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = RawContacts.AGGREGATION_MODE_DEFAULT; 231224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (forProfile) { 231324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Profile raw contacts should never be aggregated by the aggregator; they are always 231424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // aggregated under a single profile contact. 231524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro aggregationMode = RawContacts.AGGREGATION_MODE_DISABLED; 231624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else if (mValues.containsKey(RawContacts.AGGREGATION_MODE)) { 2317f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov aggregationMode = mValues.getAsInteger(RawContacts.AGGREGATION_MODE); 2318f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 2319f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov mContactAggregator.markNewForAggregation(rawContactId, aggregationMode); 2320285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 232124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (forProfile) { 232224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Trigger creation of the user profile Contact (or association with the existing one) 232324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // at the end of the transaction. 232443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mTransactionContext.profileRawContactInserted(rawContactId, accountWithDataSet); 232524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else { 232624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Trigger creation of a Contact based on this RawContact at the end of transaction 232743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mTransactionContext.rawContactInserted(rawContactId, accountWithDataSet); 232824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 2329f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2330dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 2331dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 2332dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long starred = values.getAsLong(RawContacts.STARRED); 2333dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (starred != null && starred != 0) { 2334dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred != 0); 2335dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2336dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2337dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 23383826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 2339023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov return rawContactId; 2340a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2341a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2342dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void addAutoAddMembership(long rawContactId) { 2343dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID, 2344dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2345dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2346dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2347dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2348dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2349dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2350dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private Long findGroupByRawContactId(String selection, long rawContactId) { 2351dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Cursor c = mDb.query(Tables.GROUPS + "," + Tables.RAW_CONTACTS, PROJECTION_GROUP_ID, 2352dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, 2353dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}, 2354dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana null /* groupBy */, null /* having */, null /* orderBy */); 2355dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 2356dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (c.moveToNext()) { 2357dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return c.getLong(0); 2358dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2359dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return null; 2360dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 2361dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana c.close(); 2362dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2363dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2364dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2365dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void updateFavoritesMembership(long rawContactId, boolean isStarred) { 2366dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID, 2367dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2368dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2369dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (isStarred) { 2370dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2371dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2372dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana deleteDataGroupMembership(rawContactId, groupId); 2373dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2374dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2375dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2376dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2377dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void insertDataGroupMembership(long rawContactId, long groupId) { 2378dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ContentValues groupMembershipValues = new ContentValues(); 2379dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.GROUP_ROW_ID, groupId); 2380dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 2381dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(DataColumns.MIMETYPE_ID, 2382dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 2383dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDb.insert(Tables.DATA, null, groupMembershipValues); 2384dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2385dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2386dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void deleteDataGroupMembership(long rawContactId, long groupId) { 2387dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final String[] selectionArgs = { 2388dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)), 2389dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(groupId), 2390dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(rawContactId)}; 2391dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mDb.delete(Tables.DATA, SELECTION_GROUPMEMBERSHIP_DATA, selectionArgs); 2392dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2393dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2394a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2395a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 2396a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2397a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 2398a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2399a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 2400f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private long insertData(ContentValues values, boolean callerIsSyncAdapter) { 2401a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 2402de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.clear(); 2403de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.putAll(values); 240467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 2405de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID); 240620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 240724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // If the data being inserted belongs to the user's profile entry, check for the 240824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // WRITE_PROFILE permission before proceeding. 2409afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 241024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2411de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace package with internal mapping 2412de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String packageName = mValues.getAsString(Data.RES_PACKAGE); 2413de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (packageName != null) { 2414b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 2415de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 2416de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 2417508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 2418de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace mimetype with internal mapping 2419de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String mimeType = mValues.getAsString(Data.MIMETYPE); 2420de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (TextUtils.isEmpty(mimeType)) { 2421de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new IllegalArgumentException(Data.MIMETYPE + " is required"); 2422de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 24234097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 2424b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.getMimeTypeId(mimeType)); 2425de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 2426a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2427a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2428d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov id = rowHandler.insert(mDb, mTransactionContext, rawContactId, mValues); 2429f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2430d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 2431a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2432d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.rawContactUpdated(rawContactId); 2433a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 24344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 24354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 24363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_items table. The account is checked against the 24383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account in the raw contact for which the stream item is being inserted. If the 24393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * new stream item results in more stream items under this raw contact than the limit, 24403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest one will be deleted (note that if the stream item inserted was the 24413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * oldest, it will be immediately deleted, and this will return 0). 24423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 24433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 24443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 24453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return the stream item _ID of the newly created row, or 0 if it was not created 24463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 24473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItem(Uri uri, ContentValues values) { 24483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 24493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 24503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 24513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = mValues.getAsLong(StreamItems.RAW_CONTACT_ID); 24533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If the data being inserted belongs to the user's profile entry, check for the 24553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // WRITE_PROFILE permission before proceeding. 2456afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 24573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 24593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 24603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 24613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream items table. 24636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 24646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 24656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 24663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Insert the new stream item. 24676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro id = mDb.insert(Tables.STREAM_ITEMS, null, mValues); 24686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (id == -1) { 24696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insertion failed. 24706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 24716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 24723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check to see if we're over the limit for stream items under this raw contact. 24743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // It's possible that the inserted stream item is older than the the existing 24753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // ones, in which case it may be deleted immediately (resetting the ID to 0). 24763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = cleanUpOldStreamItems(rawContactId, id); 24773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 24793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 24823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_item_photos table. The account is checked against 24833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the account in the raw contact that owns the stream item being modified. 24843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 24853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 24863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 24876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return the stream item photo _ID of the newly created row, or 0 if there was an issue 24886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * with processing the photo or creating the row 24893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 24903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItemPhoto(Uri uri, ContentValues values) { 24913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 24923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 24933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 24943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = mValues.getAsLong(StreamItemPhotos.STREAM_ITEM_ID); 24963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemId != 0) { 24973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = lookupRawContactIdForStreamId(streamItemId); 24983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If the data being inserted belongs to the user's profile entry, check for the 25003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // WRITE_PROFILE permission before proceeding. 2501afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 25023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 25043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 25053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 25063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream item 25086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 25096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 25106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 25113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 25136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(mValues, false)) { 25146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insert the stream item photo. 25156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro id = mDb.insert(Tables.STREAM_ITEM_PHOTOS, null, mValues); 25166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 25193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Processes the photo contained in the {@link ContactsContract.StreamItemPhotos#PHOTO} 25236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * field of the given values, attempting to store it in the photo store. If successful, 25246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * the resulting photo file ID will be added to the values for insert/update in the table. 25256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * <p> 25266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * If updating, it is valid for the picture to be empty or unspecified (the function will 25276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * still return true). If inserting, a valid picture must be specified. 25286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param values The content values provided by the caller. 25296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param forUpdate Whether this photo is being processed for update (vs. insert). 25306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return Whether the insert or update should proceed. 25316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 25326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro private boolean processStreamItemPhoto(ContentValues values, boolean forUpdate) { 25336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!values.containsKey(StreamItemPhotos.PHOTO)) { 25346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 25356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro byte[] photoBytes = values.getAsByteArray(StreamItemPhotos.PHOTO); 25376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoBytes == null) { 25386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 25396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 25416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 25426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 25436802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = mPhotoStore.insert(new PhotoProcessor(photoBytes, 25441dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim, true), true); 25456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileId != 0) { 25466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.put(StreamItemPhotos.PHOTO_FILE_ID, photoFileId); 25476802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(StreamItemPhotos.PHOTO); 25486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return true; 25496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 25506802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Couldn't store the photo, return 0. 25516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert"); 25526802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 25536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } catch (IOException ioe) { 25556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert", ioe); 25566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 25576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 25596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 25606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 25613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Looks up the raw contact ID that owns the specified stream item. 25623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param streamItemId The ID of the stream item. 25633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The associated raw contact ID, or -1 if no such stream item exists. 25643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long lookupRawContactIdForStreamId(long streamItemId) { 25663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = -1; 25673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = mDb.query(Tables.STREAM_ITEMS, new String[]{StreamItems.RAW_CONTACT_ID}, 25683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems._ID + "=?", new String[]{String.valueOf(streamItemId)}, 25693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 25703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 25713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c.moveToFirst()) { 25723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann rawContactId = c.getLong(0); 25733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 25753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 25763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return rawContactId; 25783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 25793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 25803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 25813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given raw contact ID is owned by the given account. 25823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account is null, this will return true iff the raw contact 25833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * is also associated with the "null" account. 25843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 25853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account does not match, this will throw a security exception. 25863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 25873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to check for. 25883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 25893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void enforceModifyingAccount(Account account, long rawContactId) { 25903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String accountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 25913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + "=? AND " 25923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + "=?"; 25933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String noAccountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 25943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " IS NULL AND " 25953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " IS NULL"; 25963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c; 25973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (account != null) { 25983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContactsColumns.CONCRETE_ID}, 25993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann accountSelection, 26003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(rawContactId), mAccount.name, mAccount.type}, 26013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 26023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 26033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContactsColumns.CONCRETE_ID}, 26043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann noAccountSelection, new String[]{String.valueOf(rawContactId)}, 26053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 26063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if(c.getCount() == 0) { 26093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new SecurityException("Caller account does not match raw contact ID " 26103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + rawContactId); 26113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream items matches up with the given 26193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 26203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 26213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 26223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 26233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 26243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item IDs that would be included in this selection. 26253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItems(Account account, String selection, 26273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 26283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = Lists.newArrayList(); 26293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 26303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 26313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = qb.query(mDb, 26323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{StreamItems._ID, StreamItems.RAW_CONTACT_ID}, 26333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 26343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 26363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemIds.add(c.getLong(0)); 26373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 26393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 26403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds; 26453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream item photos matches up with the given 26493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 26503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 26513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 26523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 26533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 26543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item photo IDs that would be included in this selection. 26553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItemPhotos(Account account, String selection, 26573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 26583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemPhotoIds = Lists.newArrayList(); 26593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 26603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 26613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = qb.query(mDb, new String[]{StreamItemPhotos._ID, StreamItems.RAW_CONTACT_ID}, 26623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 26633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 26653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemPhotoIds.add(c.getLong(0)); 26663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 26683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 26693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 26713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 26723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemPhotoIds; 26743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Queries the database for stream items under the given raw contact. If there are 26783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * more entries than {@link ContactsProvider2#MAX_STREAM_ITEMS_PER_RAW_CONTACT}, 26793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest entries (as determined by timestamp) will be deleted. 26803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to examine for stream items. 26813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param insertedStreamItemId The ID of the stream item that was just inserted, 26823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * prompting this cleanup. Callers may pass 0 if no insertion prompted the 26833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * cleanup. 26843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The ID of the inserted stream item if it still exists after cleanup; 26853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 0 otherwise. 26863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long cleanUpOldStreamItems(long rawContactId, long insertedStreamItemId) { 26883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long postCleanupInsertedStreamId = insertedStreamItemId; 26893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = mDb.query(Tables.STREAM_ITEMS, new String[]{StreamItems._ID}, 26903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 26913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, StreamItems.TIMESTAMP + " DESC, " + StreamItems._ID + " DESC"); 26923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 26933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int streamItemCount = c.getCount(); 26943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemCount <= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 26953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Still under the limit - nothing to clean up! 26963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return insertedStreamItemId; 26973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 26983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToLast(); 26993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.getPosition() >= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 27003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = c.getLong(0); 27013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (insertedStreamItemId == streamItemId) { 27023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // The stream item just inserted is being deleted. 27033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann postCleanupInsertedStreamId = 0; 27043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(c.getLong(0)); 27063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToPrevious(); 27073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 27103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 27113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return postCleanupInsertedStreamId; 27133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2715ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateRawContactDisplayName(SQLiteDatabase db, long rawContactId) { 27168ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(db, rawContactId); 2717d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov } 2718d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov 27199261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 272020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov * Delete data row by row so that fixing of primaries etc work correctly. 272120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov */ 2722f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) { 272320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 272420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2725de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 2726de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 2727f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, 2728f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov selection, selectionArgs, null); 2729de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov try { 2730de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov while(c.moveToNext()) { 2731f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 273224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 273324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for write profile permission if the data belongs to the profile. 2734afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 273524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2736f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 2737a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2738d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov count += rowHandler.delete(mDb, mTransactionContext, c); 2739f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2740d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 274188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov } 274220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 274320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 2744de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov c.close(); 274520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 274620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 274720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 274820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 274920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 275088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov /** 275188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov * Delete a data row provided that it is one of the allowed mime types. 275288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov */ 275320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov public int deleteData(long dataId, String[] allowedMimeTypes) { 2754f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 275588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 275688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 27574da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 2758f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, Data._ID + "=?", 27594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1, null); 2760f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 276120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 276220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!c.moveToFirst()) { 276320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 276420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 276520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2766f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 276720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean valid = false; 276820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov for (int i = 0; i < allowedMimeTypes.length; i++) { 276920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.equals(mimeType, allowedMimeTypes[i])) { 277020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov valid = true; 277120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 277220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 277320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 277420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 277520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!valid) { 27767a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana throw new IllegalArgumentException("Data type mismatch: expected " 277720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov + Lists.newArrayList(allowedMimeTypes)); 277820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 277920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 278024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for write profile permission if the data belongs to the profile. 278124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 2782afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 278324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2784a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2785d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov return rowHandler.delete(mDb, mTransactionContext, c); 278620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 278720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 278820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 278920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 279020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 279120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov /** 2792ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 2793ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 2794f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2795f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2796f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2797f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2798e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final Account account = resolveAccount(uri, mValues); 279943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = null; 280043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (account != null && mValues.containsKey(Groups.DATA_SET)) { 280143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro dataSet = mValues.getAsString(Groups.DATA_SET); 280243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 2803ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2804ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 2805f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String packageName = mValues.getAsString(Groups.RES_PACKAGE); 280667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 2807f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 280867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 2809f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.remove(Groups.RES_PACKAGE); 2810ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2811dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final boolean isFavoritesGroup = mValues.getAsLong(Groups.FAVORITES) != null 2812dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ? mValues.getAsLong(Groups.FAVORITES) != 0 2813dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana : false; 2814dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2815f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2816f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(Groups.DIRTY, 1); 281773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 281873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 2819f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov long result = mDb.insert(Tables.GROUPS, Groups.TITLE, mValues); 2820ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2821dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && isFavoritesGroup) { 2822dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // add all starred raw contacts to this group 2823dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String selection; 2824dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs; 2825dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (account == null) { 2826dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + " IS NULL AND " 282743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.ACCOUNT_TYPE + " IS NULL AND " 282843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.DATA_SET + " IS NULL"; 2829dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = null; 283043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } else if (dataSet == null) { 2831dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + "=? AND " 2832dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContacts.ACCOUNT_TYPE + "=?"; 2833dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = new String[]{account.name, account.type}; 283443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } else { 283543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selection = RawContacts.ACCOUNT_NAME + "=? AND " 283643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.ACCOUNT_TYPE + "=? AND " 283743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.DATA_SET + "=?"; 283843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selectionArgs = new String[]{account.name, account.type, dataSet}; 2839dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2840dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Cursor c = mDb.query(Tables.RAW_CONTACTS, 2841dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{RawContacts._ID, RawContacts.STARRED}, 2842dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, selectionArgs, null, null, null); 2843892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov try { 2844892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov while (c.moveToNext()) { 2845892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (c.getLong(1) != 0) { 2846892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov final long rawContactId = c.getLong(0); 2847892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov insertDataGroupMembership(rawContactId, result); 2848d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.markRawContactDirty(rawContactId); 2849892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } 2850dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2851892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } finally { 2852892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov c.close(); 2853dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2854dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2855dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2856f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mValues.containsKey(Groups.GROUP_VISIBLE)) { 28571a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2858ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey } 2859ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2860ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey return result; 2861ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2862ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 28635aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private long insertSettings(Uri uri, ContentValues values) { 2864e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final long id = mDb.insert(Tables.SETTINGS, null, values); 28655aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey 28661a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 28671a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2868e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 28691a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 2870e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return id; 2871e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 2872e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 2873ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 287482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov * Inserts a status update. 28751f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 287682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov public long insertStatusUpdate(ContentValues values) { 287782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov final String handle = values.getAsString(StatusUpdates.IM_HANDLE); 28780a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL); 28794dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov String customProtocol = null; 28804dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov 28810a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) { 288282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL); 28834dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov if (TextUtils.isEmpty(customProtocol)) { 28844dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov throw new IllegalArgumentException( 28854dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM"); 28864dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov } 28871f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 28881f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2889dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long rawContactId = -1; 2890dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long contactId = -1; 289182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov Long dataId = values.getAsLong(StatusUpdates.DATA_ID); 28926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountType = null; 28936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountName = null; 2894f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov mSb.setLength(0); 28952526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.clear(); 2896dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (dataId != null) { 2897dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the contact info for the given data row. 2898dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 28992526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(Tables.DATA + "." + Data._ID + "=?"); 29002526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(dataId)); 29011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 2902dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the data row to attach this presence update to 2903dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 29040a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(handle) || protocol == null) { 29050a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required"); 29060a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 29070a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 2908dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // TODO: generalize to allow other providers to match against email 2909dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol; 2910dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 29112a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov String mimeTypeIdIm = String.valueOf(mDbHelper.getMimeTypeIdForIm()); 2912dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (matchEmail) { 29132a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov String mimeTypeIdEmail = String.valueOf(mDbHelper.getMimeTypeIdForEmail()); 2914f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 2915f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise 2916f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the "OR" conjunction confuses it and it switches to a full scan of 2917f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the raw_contacts table. 2918f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 2919f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // This code relies on the fact that Im.DATA and Email.DATA are in fact the same 2920f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // column - Data.DATA1 29212526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + " IN (?,?)" + 29222526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Data.DATA1 + "=?" + 29232526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND ((" + DataColumns.MIMETYPE_ID + "=? AND " + Im.PROTOCOL + "=?"); 29242526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 29252526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 29262526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 29272526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 29282526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 2929dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 29302526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 29312526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 2932dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 29332526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=?))"); 29342526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 2935dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } else { 29362526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + "=?" + 29372526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.PROTOCOL + "=?" + 29382526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.DATA + "=?"); 29392526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 29402526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 29412526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 2942dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 29432526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 29442526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 2945dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 2946dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 29471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 294882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.DATA_ID)) { 29492526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + DataColumns.CONCRETE_ID + "=?"); 29502526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(values.getAsString(StatusUpdates.DATA_ID)); 2951dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 295270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 295370b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 29541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 29551f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 2956de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 29572526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null, 29584394086494fe7909aaca70f56fb4bb08beebf303Dmitri Plotnikov Clauses.CONTACT_VISIBLE + " DESC, " + Data.RAW_CONTACT_ID); 29591f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 296067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataId = cursor.getLong(DataContactsQuery.DATA_ID); 29615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID); 29626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountType = cursor.getString(DataContactsQuery.ACCOUNT_TYPE); 29636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountName = cursor.getString(DataContactsQuery.ACCOUNT_NAME); 2964e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 29651f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 29661f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 29671f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 29681f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 29691f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 297031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 297131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 297231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 29731f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 29741f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 297582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.PRESENCE)) { 2976a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (customProtocol == null) { 2977a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 2978a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // properly enforce uniqueness of null values 2979a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov customProtocol = ""; 2980a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 2981a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 2982a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.clear(); 298382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.DATA_ID, dataId); 2984a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId); 2985a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.CONTACT_ID, contactId); 298682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PROTOCOL, protocol); 298782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 298882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_HANDLE, handle); 298982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.IM_ACCOUNT)) { 299082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT)); 2991a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 299282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PRESENCE, 299382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov values.getAsString(StatusUpdates.PRESENCE)); 2994aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori mValues.put(StatusUpdates.CHAT_CAPABILITY, 2995aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori values.getAsString(StatusUpdates.CHAT_CAPABILITY)); 29961f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 2997a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // Insert the presence update 2998a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mDb.replace(Tables.PRESENCE, null, mValues); 2999a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3000e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 30010a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 300282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.STATUS)) { 300382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String status = values.getAsString(StatusUpdates.STATUS); 30040a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE); 30050a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov Integer labelResource = values.getAsInteger(StatusUpdates.STATUS_LABEL); 30060a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 30070a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(resPackage) 30080a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov && (labelResource == null || labelResource == 0) 30090a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov && protocol != null) { 30100a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov labelResource = Im.getProtocolLabelResource(protocol); 30110a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 30120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 30130a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov Long iconResource = values.getAsLong(StatusUpdates.STATUS_ICON); 30140a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov // TODO compute the default icon based on the protocol 30150a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 3016a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (TextUtils.isEmpty(status)) { 301778fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.deleteStatusUpdate(dataId); 3018a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } else { 30196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP); 30206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (timestamp != null) { 30216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mDbHelper.replaceStatusUpdate(dataId, timestamp, status, resPackage, 30226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro iconResource, labelResource); 30236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 30246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mDbHelper.insertStatusUpdate(dataId, status, resPackage, iconResource, 30256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro labelResource); 30266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For forward compatibility with the new stream item API, insert this status update 30296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // there as well. If we already have a stream item from this source, update that 30306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // one instead of inserting a new one (since the semantics of the old status update 30316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // API is to only have a single record). 30326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (rawContactId != -1 && !TextUtils.isEmpty(status)) { 30336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentValues streamItemValues = new ContentValues(); 30346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 30356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TEXT, status); 30366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.COMMENTS, ""); 30376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_PACKAGE, resPackage); 30386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_ICON, iconResource); 30396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_LABEL, labelResource); 30406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TIMESTAMP, 30416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro timestamp == null ? System.currentTimeMillis() : timestamp); 30426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30436802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Note: The following is basically a workaround for the fact that status 30446802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates didn't do any sort of account enforcement, while social stream item 30456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates do. We can't expect callers of the old API to start passing account 30466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // information along, so we just populate the account params appropriately for 304743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // the raw contact. Data set is not relevant here, as we only check account 304843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // name and type. 30496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (accountName != null && accountType != null) { 30506802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_NAME, accountName); 30516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_TYPE, accountType); 30526802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Check for an existing stream item from this source, and insert or update. 30556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Uri streamUri = StreamItems.CONTENT_URI; 30566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = query(streamUri, new String[]{StreamItems._ID}, 30576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", 30586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{String.valueOf(rawContactId)}, null); 30596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 30606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (c.getCount() > 0) { 30616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.moveToFirst(); 30626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro update(ContentUris.withAppendedId(streamUri, c.getLong(0)), 30636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues, null, null); 30646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 30656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro insert(streamUri, streamItemValues); 30666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 30686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 30696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 30706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 30716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 3072e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3073e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3074bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov 3075a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (contactId != -1) { 3076f4015ab9ab7c26b766b5331fbf6655b8c54877eaDmitri Plotnikov mContactAggregator.updateLastStatusUpdateId(contactId); 3077a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3078a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3079a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov return dataId; 30801f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 30811f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 30824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3083de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 3084bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3085b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "deleteInTransaction: " + uri); 3086b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3087b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3088f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3089f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 3090508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 3091508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 309235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 3093b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().delete(mDb, selection, selectionArgs); 309435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3095b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: 3096b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3097b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3098b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3099b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().delete(mDb, selectionWithId, selectionArgs); 3100b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3101cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov case CONTACTS: { 3102cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov // TODO 3103cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return 0; 3104cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3105cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3106d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3107d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 3108dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 31096bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 31106bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 31119fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP: { 31122e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 31132e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 31142e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 3115fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 3116fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 31172e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 31182e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 31192e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final long contactId = lookupContactIdByLookupKey(mDb, lookupKey); 3120dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 31212e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 31222e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 31239fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP_ID: { 31249fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // lookup contact by id and lookup key to see if they still match the actual record 31259fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final List<String> pathSegments = uri.getPathSegments(); 31269fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final String lookupKey = pathSegments.get(2); 31279fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 31289fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann setTablesAndProjectionMapForContacts(lookupQb, uri, null); 3129a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 31309fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann String[] args; 31319fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (selectionArgs == null) { 31329fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[2]; 31339fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 31349fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[selectionArgs.length + 2]; 31359fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 31369fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31379fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args[0] = String.valueOf(contactId); 313860de6f6c3c70e53b603a47b0efc80993353a8368Daniel Lehmann args[1] = Uri.encode(lookupKey); 31399fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?"); 31409fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 31419fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann Cursor c = query(db, lookupQb, null, selection, args, null, null, null); 31429fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann try { 31439fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (c.getCount() == 1) { 31449fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // contact was unmodified so go ahead and delete it 3145dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 31469fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 31479fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // row was changed (e.g. the merging might have changed), we got multiple 31489fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // rows or the supplied selection filtered the record out 31499fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann return 0; 31509fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31519fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } finally { 31529fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann c.close(); 31539fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31549fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 31559fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann 31562971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case RAW_CONTACTS: { 31572971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 3158fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov Cursor c = mDb.query(Tables.RAW_CONTACTS, 3159fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov new String[]{RawContacts._ID, RawContacts.CONTACT_ID}, 3160e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 31612971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 31622971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 31632971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = c.getLong(0); 3164fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov long contactId = c.getLong(1); 3165fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov numDeletes += deleteRawContact(rawContactId, contactId, 3166fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 31672971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31682971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 31692971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 31702971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31712971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 31722971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 31732971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 31745ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 31752971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = ContentUris.parseId(uri); 3176fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return deleteRawContact(rawContactId, mDbHelper.getContactId(rawContactId), 3177fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 3178508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3179508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 318020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3181f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 3182944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong return deleteData(appendAccountToSelection(uri, selection), selectionArgs, 3183f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana callerIsSyncAdapter); 318420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 318520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 318648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 318748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 318848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 318948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3190508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 3191f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 31924da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 31934da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter); 3194ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3195ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3196ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3197f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 31985aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter); 31992971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 32002971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 32012971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case GROUPS: { 32022971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 32032971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups._ID}, 3204e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 32052971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 32062971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 32075aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter); 32082971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 32092971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 32102971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 32112971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 321281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (numDeletes > 0) { 3213f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 321481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 32152971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 3216508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3217508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 3218eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 321943880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3220e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs); 3221eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3222eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 322382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 32240a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov return deleteStatusUpdates(selection, selectionArgs); 32251f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 32261f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 32273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 32283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 32293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), selection, selectionArgs); 32303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 32333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 32343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), 32353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemsColumns.CONCRETE_ID + "=?", 32363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 32373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 32403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 32413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), selection, selectionArgs); 32423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 32443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 32453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 32463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 32473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 32483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), 32493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " 32503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + StreamItemPhotos.STREAM_ITEM_ID + "=?", 32513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 32523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 32533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 325481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 325581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 32563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return mLegacyApiSupport.delete(uri, selection, selectionArgs); 325781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3258508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 32594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 32604f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 32611c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) { 3262ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3263b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final long groupMembershipMimetypeId = mDbHelper 326494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 3265de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 326694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 326794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupId, null); 326894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 326994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana try { 3270f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 3271de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 327294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } else { 327394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.clear(); 327494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.put(Groups.DELETED, 1); 3275f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mValues.put(Groups.DIRTY, 1); 3276de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null); 327794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 327894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } finally { 32791a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 328094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 328194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 328294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 32835aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int deleteSettings(Uri uri, String selection, String[] selectionArgs) { 3284e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final int count = mDb.delete(Tables.SETTINGS, selection, selectionArgs); 32851a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3286e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3287e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3288e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3289dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int deleteContact(long contactId, boolean callerIsSyncAdapter) { 3290afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(mDb, contactId, true); 329196b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(contactId); 3292cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, 329396b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker RawContacts.CONTACT_ID + "=?", mSelectionArgs1, 329496b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker null, null, null); 3295cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov try { 3296cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov while (c.moveToNext()) { 3297cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov long rawContactId = c.getLong(0); 3298dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 3299cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3300cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } finally { 3301cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov c.close(); 3302cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3303cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 33043826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 33053826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3306cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return mDb.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 3307cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3308cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3309fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) { 3310afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 33113389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov mContactAggregator.invalidateAggregationExceptionCache(); 33123826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 33133826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3314f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 331514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null); 3316fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov int count = mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null); 3317fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov mContactAggregator.updateDisplayNameForContact(mDb, contactId); 3318fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return count; 331933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } else { 3320b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.removeContactIfSingleton(rawContactId); 3321dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 332233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 332333b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 332433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 33250a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private int deleteStatusUpdates(String selection, String[] selectionArgs) { 33269705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // delete from both tables: presence and status_updates 33279705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 33289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (VERBOSE_LOGGING) { 33299705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori Log.v(TAG, "deleting data from status_updates for " + selection); 33309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 33319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mDb.delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection), 33329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 33339705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mDb.delete(Tables.PRESENCE, selection, selectionArgs); 33340a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 33350a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 33363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItems(Uri uri, ContentValues values, String selection, 33373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 33383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream items to be deleted, and check that they belong 33393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // to the account. 33403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 33413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = enforceModifyingAccountForStreamItems( 33423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann account, selection, selectionArgs); 33433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 33453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann for (long streamItemId : streamItemIds) { 33463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(streamItemId); 33473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mVisibleTouched = true; 33503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds.size(); 33513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItem(long streamItemId) { 33543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 33553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItemPhotos(streamItemId); 33563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEMS, StreamItems._ID + "=?", 33573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 33583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(Uri uri, ContentValues values, String selection, 33613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 33623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream item photos to be deleted, and check that they 33633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // belong to the account. 33643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 33653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 33663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 33683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEM_PHOTOS, selection, selectionArgs); 33693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 33713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(long streamItemId) { 33723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 33733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.delete(Tables.STREAM_ITEM_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID + "=?", 33743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 33753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 33763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 3377dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int markRawContactAsDeleted(long rawContactId, boolean callerIsSyncAdapter) { 337881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 337981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 3380cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.clear(); 3381cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DELETED, 1); 3382cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 3383cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1); 3384cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 3385cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3386dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return updateRawContact(rawContactId, mValues, callerIsSyncAdapter); 3387cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3388cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 33894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3390de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int updateInTransaction(Uri uri, ContentValues values, String selection, 3391de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov String[] selectionArgs) { 3392bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3393b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "updateInTransaction: " + uri); 3394b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3395b5a4add17815167d20a90645779df34cdf45280dFred Quintana 339635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 339700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 339800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 3399b5a4add17815167d20a90645779df34cdf45280dFred Quintana if (match == SYNCSTATE_ID && selection == null) { 3400b5a4add17815167d20a90645779df34cdf45280dFred Quintana long rowId = ContentUris.parseId(uri); 34011129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Object data = values.get(ContactsContract.SyncState.DATA); 3402d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.syncStateUpdated(rowId, data); 3403b5a4add17815167d20a90645779df34cdf45280dFred Quintana return 1; 3404b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3405b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3406f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3407f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 340800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 340935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 3410b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().update(mDb, values, 3411b5a4add17815167d20a90645779df34cdf45280dFred Quintana appendAccountToSelection(uri, selection), selectionArgs); 3412b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3413b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: { 3414b5a4add17815167d20a90645779df34cdf45280dFred Quintana selection = appendAccountToSelection(uri, selection); 3415b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3416b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3417b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3418b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().update(mDb, values, 3419b5a4add17815167d20a90645779df34cdf45280dFred Quintana selectionWithId, selectionArgs); 3420b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 342135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3422d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 3423dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter); 342400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 342500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 342600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3427d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3428dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(ContentUris.parseId(uri), values, callerIsSyncAdapter); 3429c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 3430c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 3431c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 343224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 343324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Restrict update to the user's profile. 343424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro StringBuilder profileSelection = new StringBuilder(); 343524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileSelection.append(Contacts.IS_USER_PROFILE + "=1"); 343624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(selection)) { 343724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro profileSelection.append(" AND (").append(selection).append(")"); 343824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 343924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro count = updateContactOptions(values, profileSelection.toString(), selectionArgs, 344024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro callerIsSyncAdapter); 344124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 344224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 344324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 34442e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP: 34452e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP_ID: { 34462e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 34472e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 34482e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 3449fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 3450fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 34512e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 34522e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 34532e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final long contactId = lookupContactIdByLookupKey(mDb, lookupKey); 3454dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(contactId, values, callerIsSyncAdapter); 34552e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey break; 34562e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 34572e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 34587d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh case RAW_CONTACTS_DATA: { 34597d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh final String rawContactId = uri.getPathSegments().get(1); 34607d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ") 34617d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh + (selection == null ? "" : " AND " + selection); 34627d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 34637d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter); 34647d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 34657d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh break; 34667d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh } 34677d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 346820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3469944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong count = updateData(uri, values, appendAccountToSelection(uri, selection), 3470f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 347181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3472f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 347381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 347420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 347520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3476c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 347748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 347848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 347948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 348048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3481f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter); 348281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3483f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 348481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 348500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 348600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 34877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 34885ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 34895ac5c70d1165309302ebcc931f51723e37d31e0bJeff Sharkey selection = appendAccountToSelection(uri, selection); 3490dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, selection, selectionArgs, callerIsSyncAdapter); 34917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 34927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 34937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 34945ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 349533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 34964529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (selection != null) { 34974da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 34984da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov count = updateRawContacts(values, RawContacts._ID + "=?" 3499dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND(" + selection + ")", selectionArgs, 3500dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 35014529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } else { 35024da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 3503dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1, 3504dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 35054529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 35067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 35077e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 35087e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 3509ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 35105aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, appendAccountToSelection(uri, selection), 3511f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 351281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3513f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 351481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3515ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3516ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3517ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3518ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3519ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 35204da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId)); 35214da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String selectionWithId = Groups._ID + "=? " 352273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov + (selection == null ? "" : " AND " + selection); 35235aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, selectionWithId, selectionArgs, 35245aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey callerIsSyncAdapter); 352581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3526f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 352781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3528ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3529ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3530ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3531127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 3532de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov count = updateAggregationException(mDb, values); 3533b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 3534b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3535b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 3536eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 3537e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey count = updateSettings(uri, values, appendAccountToSelection(uri, selection), 3538e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey selectionArgs); 353943880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3540eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 3541eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3542eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 35439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori case STATUS_UPDATES: { 35449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori count = updateStatusUpdate(uri, values, selection, selectionArgs); 35459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori break; 35469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 35483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 35493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, selection, selectionArgs); 35503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 35543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, StreamItemsColumns.CONCRETE_ID + "=?", 35553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 35563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 35603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, selection, selectionArgs); 35613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 35653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 35663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 35673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{streamItemId}); 35683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 35723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 35733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 35743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 35753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " + 35763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?", 35773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 35783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 35793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 358172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov case DIRECTORIES: { 3582bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanPackagesByUid(Binder.getCallingUid()); 358372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov count = 1; 3584d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 3585d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 3586d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 358746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa case DATA_USAGE_FEEDBACK_ID: { 358846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (handleDataUsageFeedback(uri)) { 358946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 1; 359046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 359146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 0; 359246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 359346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa break; 359446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 359546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 359681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 359781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 3598f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 359981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 360000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 360100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 360200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 36034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 36044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 36059705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private int updateStatusUpdate(Uri uri, ContentValues values, String selection, 36069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori String[] selectionArgs) { 36079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // update status_updates table, if status is provided 36089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 36099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori int updateCount = 0; 36109705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values); 36119705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 36129705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori updateCount = mDb.update(Tables.STATUS_UPDATES, 36139705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues, 36149705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori getWhereClauseForStatusUpdatesTable(selection), 36159705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 36169705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36179705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36189705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // now update the Presence table 36199705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues = getSettableColumnsForPresenceTable(values); 36209705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 36219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori updateCount = mDb.update(Tables.PRESENCE, settableValues, 36229705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selection, selectionArgs); 36239705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36249705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO updateCount is not entirely a valid count of updated rows because 2 tables could 36259705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // potentially get updated in this method. 36269705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return updateCount; 36279705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItems(Uri uri, ContentValues values, String selection, 36303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 36313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream items can't be moved to a new raw contact. 36323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItems.RAW_CONTACT_ID); 36333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream items being updated belong to the account. 36353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 36363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItems(account, selection, selectionArgs); 36373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream items table. 36396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 36406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 36416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 36423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If there's been no exception, the update should be fine. 36433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return mDb.update(Tables.STREAM_ITEMS, values, selection, selectionArgs); 36443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItemPhotos(Uri uri, ContentValues values, String selection, 36473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 36483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream item photos can't be moved to a new stream item. 36493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItemPhotos.STREAM_ITEM_ID); 36503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream item photos being updated belong to the account. 36523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 36533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 36543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream item 36566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 36576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 36586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 36596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 36606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo (since we're updating, it's valid for the photo to not be present). 36616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(values, true)) { 36626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // If there's been no exception, the update should be fine. 36636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return mDb.update(Tables.STREAM_ITEM_PHOTOS, values, selection, selectionArgs); 36646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 36656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 36663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36689705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori /** 36699705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori * Build a where clause to select the rows to be updated in status_updates table. 36709705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori */ 36719705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private String getWhereClauseForStatusUpdatesTable(String selection) { 36729705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.setLength(0); 36739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE); 36749705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(selection); 36759705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(")"); 36769705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mSb.toString(); 36779705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36789705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36799705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) { 36809705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 36819705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values, 36829705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS); 36839705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values, 36849705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_TIMESTAMP); 36859705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values, 36869705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_RES_PACKAGE); 36879705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values, 36889705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_LABEL); 36899705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values, 36909705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_ICON); 36919705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 36929705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 36939705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 36949705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForPresenceTable(ContentValues values) { 36959705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 36969705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values, 36979705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.PRESENCE); 3698aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.CHAT_CAPABILITY, values, 3699aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori StatusUpdates.CHAT_CAPABILITY); 37009705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 37019705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 37029705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 37035aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int updateGroups(Uri uri, ContentValues values, String selectionWithId, 3704f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 370573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3706ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3707ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov 370873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov ContentValues updatedValues; 3709f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter && !values.containsKey(Groups.DIRTY)) { 371073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = mValues; 371173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.clear(); 371273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.putAll(values); 371373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.put(Groups.DIRTY, 1); 371473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } else { 371573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = values; 371673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 371773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3718ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey int count = mDb.update(Tables.GROUPS, updatedValues, selectionWithId, selectionArgs); 37191a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) { 37201a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 372194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 372243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 372343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO: This will not work for groups that have a data set specified, since the content 372443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // resolver will not be able to request a sync for the right source (unless it is updated 372543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // to key off account with data set). 37266ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi if (updatedValues.containsKey(Groups.SHOULD_SYNC) 37271129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) { 37286ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups.ACCOUNT_NAME, 3729e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey Groups.ACCOUNT_TYPE}, selectionWithId, selectionArgs, null, 37306ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi null, null); 37316ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountName; 37326ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountType; 37336ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi try { 37346ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi while (c.moveToNext()) { 37356ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountName = c.getString(0); 37366ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountType = c.getString(1); 373724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 37386ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Account account = new Account(accountName, accountType); 3739ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov ContentResolver.requestSync(account, ContactsContract.AUTHORITY, 37406ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi new Bundle()); 37416ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi break; 37426ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 37436ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 37446ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } finally { 37456ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi c.close(); 37466ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 37476ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 374894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana return count; 374994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 375094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 3751b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private int updateSettings(Uri uri, ContentValues values, String selection, 3752b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov String[] selectionArgs) { 3753e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey final int count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs); 37541a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 37551a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3756e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3757e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3758e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3759e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3760dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs, 3761dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 37624529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (values.containsKey(RawContacts.CONTACT_ID)) { 37634529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " + 37644529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov "in content values. Contact IDs are assigned automatically"); 37654529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 376673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 376797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 376897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 376997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0"); 377097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 377197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 37724529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov int count = 0; 3773ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.RAW_CONTACTS, 377451bf5ea9531b9da72caff607dbdf35fd6f61cbe2Jeff Sharkey new String[] { RawContacts._ID }, selection, 37754529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov selectionArgs, null, null, null); 37764529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov try { 37774529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov while (cursor.moveToNext()) { 37784529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov long rawContactId = cursor.getLong(0); 3779dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateRawContact(rawContactId, values, callerIsSyncAdapter); 37804529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov count++; 37814529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37824529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } finally { 37834529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov cursor.close(); 37844529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37854529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 37864529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov return count; 37874529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37884529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 3789dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContact(long rawContactId, ContentValues values, 3790dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 379124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 379224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Enforce profile permissions if the raw contact is in the user's profile. 3793afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 379424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 379596b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker final String selection = RawContacts._ID + " = ?"; 379696b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(rawContactId); 379719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED) 379819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka && values.getAsInteger(RawContacts.DELETED) == 0); 379919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int previousDeleted = 0; 3800ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType = null; 3801ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName = null; 380243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = null; 380319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete) { 380419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka Cursor cursor = mDb.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, selection, 380596b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1, null, null, null); 380619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka try { 380719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (cursor.moveToFirst()) { 380819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka previousDeleted = cursor.getInt(RawContactsQuery.DELETED); 3809ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE); 3810ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME); 381143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro dataSet = cursor.getString(RawContactsQuery.DATA_SET); 381219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 381319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } finally { 381419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka cursor.close(); 381519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 381619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 381719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT); 381819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 3819f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 382096b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker int count = mDb.update(Tables.RAW_CONTACTS, values, selection, mSelectionArgs1); 38215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count != 0) { 3822f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (values.containsKey(RawContacts.AGGREGATION_MODE)) { 3823f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = values.getAsInteger(RawContacts.AGGREGATION_MODE); 3824f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov 3825f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // As per ContactsContract documentation, changing aggregation mode 3826f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // to DEFAULT should not trigger aggregation 3827f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) { 382869cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, aggregationMode, false); 3829f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 3830f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 3831433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey if (values.containsKey(RawContacts.STARRED)) { 3832dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 3833dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 3834dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana values.getAsLong(RawContacts.STARRED) != 0); 3835dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 38364529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov mContactAggregator.updateStarred(rawContactId); 3837dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 3838dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then update the 3839dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // favorites group membership based on whether or not this contact is starred. 3840dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // If it is starred, add a group membership, if one doesn't already exist 3841dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // otherwise delete any matching group memberships. 3842dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 3843dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean starred = 0 != DatabaseUtils.longForQuery(mDb, 3844dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana SELECTION_STARRED_FROM_RAW_CONTACTS, 3845dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}); 3846dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred); 3847dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3848dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3849dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3850dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then add a 3851dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // group membership to the group marked as AutoAdd, if any. 3852dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 3853dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 3854433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey } 3855dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3856285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov if (values.containsKey(RawContacts.SOURCE_ID)) { 38572b7a632bba423357ae5641f94da6a2f71afc523bDmitri Plotnikov mContactAggregator.updateLookupKeyForRawContact(mDb, rawContactId); 3858285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 3859f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.containsKey(RawContacts.NAME_VERIFIED)) { 3860f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 3861f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // If setting NAME_VERIFIED for this raw contact, reset it for all 3862f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // other raw contacts in the same aggregate 3863f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) { 386478fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.resetNameVerifiedForOtherRawContacts(rawContactId); 3865f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 3866f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov mContactAggregator.updateDisplayNameForRawContact(mDb, rawContactId); 3867f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 386819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete && previousDeleted == 1) { 3869d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov mTransactionContext.rawContactInserted(rawContactId, 387043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new AccountWithDataSet(accountName, accountType, dataSet)); 387119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 38725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 38735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return count; 387433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 387533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 3876321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana private int updateData(Uri uri, ContentValues values, String selection, 3877f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 387820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 387920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 388020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data._ID); 38815ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov mValues.remove(Data.RAW_CONTACT_ID); 388220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 388320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 388420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String packageName = values.getAsString(Data.RES_PACKAGE); 388520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (packageName != null) { 388620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 3887b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName)); 388820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 388920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 389097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 389197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 389297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov Data.IS_READ_ONLY + "=0"); 389397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 389497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 3895653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov int count = 0; 389620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3897653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 3898653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // so we don't need to worry about updating data we don't have permission to read. 3899f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // This query will be allowed to return profiles, and we'll do the permission check 3900f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // within the loop. 39016ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Cursor c = queryLocal(uri.buildUpon() 3902f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendQueryParameter(ContactsContract.ALLOW_PROFILE, "1").build(), 3903f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro DataRowHandler.DataUpdateQuery.COLUMNS, 39046ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro selection, selectionArgs, null, -1 /* directory ID */, 39056ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro true /* suppress profile check */); 3906653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov try { 3907653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov while(c.moveToNext()) { 390824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check profile permission for the raw contact that owns each data record. 390924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = c.getLong(DataRowHandler.DataUpdateQuery.RAW_CONTACT_ID); 3910afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(mDb, rawContactId, true); 391124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 3912f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count += updateData(mValues, c, callerIsSyncAdapter); 391320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3914653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov } finally { 3915653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov c.close(); 391620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 391720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3918653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return count; 391920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 392020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3921f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) { 3922653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov if (values.size() == 0) { 3923653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return 0; 3924321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 3925653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov 3926f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String mimeType = c.getString(DataRowHandler.DataUpdateQuery.MIMETYPE); 3927a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 3928f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean updated = 3929f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro rowHandler.update(mDb, mTransactionContext, values, c, callerIsSyncAdapter); 3930f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) { 3931f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 3932a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov } 3933f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return updated ? 1 : 0; 3934321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 3935321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana 39368c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov private int updateContactOptions(ContentValues values, String selection, 3937dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 39388c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov int count = 0; 3939ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.CONTACTS, 394024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[] { Contacts._ID, Contacts.IS_USER_PROFILE }, selection, 39418c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov selectionArgs, null, null, null); 39428c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov try { 39438c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov while (cursor.moveToNext()) { 39448c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov long contactId = cursor.getLong(0); 394524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 394624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check for profile write permission before updating a user's profile contact. 394724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean isProfile = cursor.getInt(1) == 1; 394824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (isProfile) { 394924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(true); 395024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 395124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 3952dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateContactOptions(contactId, values, callerIsSyncAdapter); 39538c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov count++; 39548c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 39558c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } finally { 39568c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov cursor.close(); 39578c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 39588c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 39598c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov return count; 39608c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 39618c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 3962dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateContactOptions(long contactId, ContentValues values, 3963dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 3964d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 396524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // Check write permission if the contact is the user's profile. 3966afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(mDb, contactId, true); 396724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 39688c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 3969b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 3970d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 3971b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 3972d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 3973b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 3974d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 3975b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 3976d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 3977b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 3978d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.STARRED); 3979d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 3980d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 39818c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.size() == 0) { 3982d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 3983d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 3984d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 39858c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.containsKey(RawContacts.STARRED)) { 3986c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey // Mark dirty when changing starred to trigger sync 39878c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3988c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey } 3989c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey 39904da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(contactId); 399197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov mDb.update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?" 399297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov + " AND " + RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0", mSelectionArgs1); 39938c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 3994dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (mValues.containsKey(RawContacts.STARRED) && !callerIsSyncAdapter) { 3995ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Cursor cursor = mDb.query(Views.RAW_CONTACTS, 3996dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=?", 3997dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mSelectionArgs1, null, null, null); 3998dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 3999dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (cursor.moveToNext()) { 4000dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana long rawContactId = cursor.getLong(0); 4001dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 4002dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mValues.getAsLong(RawContacts.STARRED) != 0); 4003dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4004dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 4005dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana cursor.close(); 4006dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4007dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4008dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 40098c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // Copy changeable values to prevent automatically managed fields from 40108c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // being explicitly updated by clients. 40118c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 4012b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 40138c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 4014b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 40158c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 4016b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 40178c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 4018b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 40198c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 4020b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 40218c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.STARRED); 40228c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 40239b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori int rslt = mDb.update(Tables.CONTACTS, mValues, Contacts._ID + "=?", mSelectionArgs1); 40246e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori 40259b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori if (values.containsKey(Contacts.LAST_TIME_CONTACTED) && 40269b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori !values.containsKey(Contacts.TIMES_CONTACTED)) { 40279b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 40289b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 40299b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori } 40309b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori return rslt; 4031f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 4032d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 4033127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 4034127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 40350c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1); 40360c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2); 403780c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 4038ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId1; 4039ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId2; 40400c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (rcId1 < rcId2) { 40410c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId1; 40420c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId2; 40430c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 40440c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId1; 40450c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId2; 4046b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4047127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 40480c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 40494da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[0] = String.valueOf(rawContactId1); 40504da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[1] = String.valueOf(rawContactId2); 40510c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, 40524da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov AggregationExceptions.RAW_CONTACT_ID1 + "=? AND " 40534da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2); 40540c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 40556bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 40566bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 40570c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 40580c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 40590c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 40600c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues); 4061127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 4062127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 40633389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov mContactAggregator.invalidateAggregationExceptionCache(); 406469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId1, 406569cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 406669cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId2, 406769cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 4068dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov 4069bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateContact(mTransactionContext, db, rawContactId1); 4070bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateContact(mTransactionContext, db, rawContactId2); 4071127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 4072127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 4073127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 4074127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 4075b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4076b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 407770d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong public void onAccountsUpdated(Account[] accounts) { 4078bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 40793826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 40803826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4081bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected boolean updateAccountsInBackground(Account[] accounts) { 4082f8536aaa7a52b9a7a353bc54e158becdbe79ec87Bai Tao // TODO : Check the unit test. 4083e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov boolean accountsChanged = false; 408449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov mDb = mDbHelper.getWritableDatabase(); 408570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.beginTransaction(); 408670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong try { 408743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> existingAccountsWithDataSets = 408843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro findValidAccountsWithDataSets(Tables.ACCOUNTS); 4089743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov 409043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add a row to the ACCOUNTS table (with no data set) for each new account. 4091743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov for (Account account : accounts) { 409243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = new AccountWithDataSet( 409343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro account.name, account.type, null); 409443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!existingAccountsWithDataSets.contains(accountWithDataSet)) { 4095e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 409643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 409743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add an account entry with an empty data set to match the account. 4098743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov mDb.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 409943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ", " + RawContacts.ACCOUNT_TYPE + ", " + RawContacts.DATA_SET 410043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ") VALUES (?, ?, ?)", 410143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new String[] { 410243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 410343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 410443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 410543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }); 4106743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 4107743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 410848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 410943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Check each of the existing sub-accounts against the account list. If the owning 411043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // account no longer exists, the sub-account and all its data should be deleted. 411143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro List<AccountWithDataSet> accountsWithDataSetsToDelete = 411243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new ArrayList<AccountWithDataSet>(); 411343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro List<Account> accountList = Arrays.asList(accounts); 411443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : existingAccountsWithDataSets) { 411543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Account owningAccount = new Account( 411643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), accountWithDataSet.getAccountType()); 411743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!accountList.contains(owningAccount)) { 411843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsWithDataSetsToDelete.add(accountWithDataSet); 411943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 412070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 412170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong 412243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!accountsWithDataSetsToDelete.isEmpty()) { 4123e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 412443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : accountsWithDataSetsToDelete) { 412543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Log.d(TAG, "removing data for removed account " + accountWithDataSet); 412643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String[] accountParams = new String[] { 412743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 412843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType() 412943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }; 413043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String[] accountWithDataSetParams = accountWithDataSet.getDataSet() == null 413143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ? accountParams 413243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro : new String[] { 413343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 413443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 413543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 413643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }; 413743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String groupsDataSetClause = " AND " + Groups.DATA_SET 413843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + (accountWithDataSet.getDataSet() == null ? " IS NULL" : " = ?"); 413943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String rawContactsDataSetClause = " AND " + RawContacts.DATA_SET 414043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + (accountWithDataSet.getDataSet() == null ? " IS NULL" : " = ?"); 414143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 4142e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4143e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.GROUPS + 4144e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Groups.ACCOUNT_NAME + " = ?" + 414543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Groups.ACCOUNT_TYPE + " = ?" + 414643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro groupsDataSetClause, accountWithDataSetParams); 4147e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4148e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.PRESENCE + 4149e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" + 4150e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "SELECT " + RawContacts._ID + 4151e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 4152e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 415343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + " = ?" + 415443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause + ")", accountWithDataSetParams); 4155e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4156e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.RAW_CONTACTS + 4157e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 415843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + " = ?" + 415943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause, accountWithDataSetParams); 4160e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4161e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.SETTINGS + 4162e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Settings.ACCOUNT_NAME + " = ?" + 416343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Settings.ACCOUNT_TYPE + " = ?", accountParams); 4164e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDb.execSQL( 4165e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.ACCOUNTS + 4166e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + "=?" + 416743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + "=?" + 416843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause, accountWithDataSetParams); 4169d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov mDb.execSQL( 4170d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov "DELETE FROM " + Tables.DIRECTORIES + 4171d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov " WHERE " + Directory.ACCOUNT_NAME + "=?" + 417243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Directory.ACCOUNT_TYPE + "=?", accountParams); 41734458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov resetDirectoryCache(); 4174e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 4175e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov 417633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // Find all aggregated contacts that used to contain the raw contacts 417733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // we have just deleted and see if they are still referencing the deleted 4178e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov // names or photos. If so, fix up those contacts. 417933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov HashSet<Long> orphanContactIds = Sets.newHashSet(); 418033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Cursor cursor = mDb.rawQuery("SELECT " + Contacts._ID + 418133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " FROM " + Tables.CONTACTS + 418233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " WHERE (" + Contacts.NAME_RAW_CONTACT_ID + " NOT NULL AND " + 418369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov Contacts.NAME_RAW_CONTACT_ID + " NOT IN " + 418469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + RawContacts._ID + 418569cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + "))" + 418633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " OR (" + Contacts.PHOTO_ID + " NOT NULL AND " + 418733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Contacts.PHOTO_ID + " NOT IN " + 418869cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + Data._ID + 418969cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.DATA + "))", null); 419033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov try { 419133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov while (cursor.moveToNext()) { 419233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov orphanContactIds.add(cursor.getLong(0)); 419333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 419433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } finally { 419533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov cursor.close(); 419633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 419733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 419833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov for (Long contactId : orphanContactIds) { 4199bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.updateAggregateData(mTransactionContext, contactId); 420033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 4201e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDbHelper.updateAllVisible(); 4202bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 420333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 420433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 420543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Now that we've done the account-based additions and subtractions from the Accounts 420643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // table, check for raw contacts that have been added with a data set and add Accounts 420743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // entries for those if necessary. 420843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro existingAccountsWithDataSets = findValidAccountsWithDataSets(Tables.ACCOUNTS); 420943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> rawContactAccountsWithDataSets = 421043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro findValidAccountsWithDataSets(Tables.RAW_CONTACTS); 421143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactAccountsWithDataSets.removeAll(existingAccountsWithDataSets); 421243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 421343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Any remaining raw contact sub-accounts need to be added to the Accounts table. 421443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : rawContactAccountsWithDataSets) { 421543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsChanged = true; 421643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 421743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add an account entry to match the raw contact. 421843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mDb.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 421943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ", " + RawContacts.ACCOUNT_TYPE + ", " + RawContacts.DATA_SET 422043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ") VALUES (?, ?, ?)", 422143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new String[] { 422243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 422343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 422443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 422543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }); 422643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 422743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 4228e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov if (accountsChanged) { 422943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO: Should sync state take data set into consideration? 4230e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov mDbHelper.getSyncState().onAccountsChanged(mDb, accounts); 4231e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 423270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.setTransactionSuccessful(); 423370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } finally { 423470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong mDb.endTransaction(); 423570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 423673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.clear(); 42373826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 42383826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (accountsChanged) { 42393826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateContactsAccountCount(accounts); 42403826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 42413826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4243afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov return accountsChanged; 424470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 4245619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 42463826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateContactsAccountCount(Account[] accounts) { 42473826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov int count = 0; 42483826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov for (Account account : accounts) { 42493826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (isContactsAccount(account)) { 42503826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov count++; 42513826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42533826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mContactsAccountCount = count; 42543826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42553826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 42563826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov protected boolean isContactsAccount(Account account) { 42573826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov final IContentService cs = ContentResolver.getContentService(); 42583826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov try { 42593826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0; 42603826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } catch (RemoteException e) { 42613826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov Log.e(TAG, "Cannot obtain sync flag for account: " + account, e); 42623826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return false; 42633826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42643826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42653826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 426672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void onPackageChanged(String packageName) { 4267bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_DIRECTORIES, packageName); 4268d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4269d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4270619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 427143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Finds all distinct account types and data sets present in the specified table. 4272627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov */ 427343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private Set<AccountWithDataSet> findValidAccountsWithDataSets(String table) { 427443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> accountsWithDataSets = new HashSet<AccountWithDataSet>(); 4275743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov Cursor c = mDb.rawQuery( 427643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro "SELECT DISTINCT " + RawContacts.ACCOUNT_NAME + "," + RawContacts.ACCOUNT_TYPE + 427743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro "," + RawContacts.DATA_SET + 427843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " FROM " + table, null); 4279627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 4280627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov while (c.moveToNext()) { 4281dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!c.isNull(0) || !c.isNull(1)) { 428243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsWithDataSets.add( 428343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new AccountWithDataSet(c.getString(0), c.getString(1), c.getString(2))); 4284627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4285627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4286627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } finally { 4287627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov c.close(); 4288627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 428943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro return accountsWithDataSets; 4290627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4291627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov 42924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 42934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 42944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 429515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 429615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mReadAccessLatch); 429715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 4298d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY); 4299385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directory == null) { 43003716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 43016ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1, false)); 4302385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directory.equals("0")) { 43033716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 43043716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 43056ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Directory.DEFAULT, false)); 4306d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } else if (directory.equals("1")) { 43073716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 43083716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 43096ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro Directory.LOCAL_INVISIBLE, false)); 4310d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4311d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4312d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov DirectoryInfo directoryInfo = getDirectoryAuthority(directory); 4313d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo == null) { 4314a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov Log.e(TAG, "Invalid directory ID: " + uri); 4315a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov return null; 4316d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4317d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4318d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Builder builder = new Uri.Builder(); 4319d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.scheme(ContentResolver.SCHEME_CONTENT); 4320d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.authority(directoryInfo.authority); 4321d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.encodedPath(uri.getEncodedPath()); 4322d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountName != null) { 4323d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName); 4324d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4325d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountType != null) { 4326d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType); 4327d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 43282e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 43292e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limit = getLimit(uri); 43302e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov if (limit != null) { 43312e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit); 43322e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov } 43332e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 4334d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Uri directoryUri = builder.build(); 433509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 433609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov if (projection == null) { 433709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov projection = getDefaultProjection(uri); 433809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 433909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 4340332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov Cursor cursor = getContext().getContentResolver().query(directoryUri, projection, selection, 4341d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov selectionArgs, sortOrder); 43426ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 43436ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (cursor == null) { 43446ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 43456ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 43466ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 4347547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro CrossProcessCursor crossProcessCursor = getCrossProcessCursor(cursor); 4348547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (crossProcessCursor != null) { 4349547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return wrapCursor(uri, cursor); 4350547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } else { 4351547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return matrixCursorFromCursor(wrapCursor(uri, cursor)); 4352547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 43533716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 43543716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4355547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro private Cursor wrapCursor(Uri uri, Cursor cursor) { 4356547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 4357547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro // If the cursor doesn't contain a snippet column, don't bother wrapping it. 4358547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (cursor.getColumnIndex(SearchSnippetColumns.SNIPPET) < 0) { 4359547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return cursor; 4360547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 4361547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 43623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Parse out snippet arguments for use when snippets are retrieved from the cursor. 43633716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String[] args = null; 43643716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String snippetArgs = 43653716f1447ceb21180d1301790eabd8b9453f486dDave Santoro getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 43663716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (snippetArgs != null) { 43673716f1447ceb21180d1301790eabd8b9453f486dDave Santoro args = snippetArgs.split(","); 43683716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 43693716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 43703716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String query = uri.getLastPathSegment(); 43713716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String startMatch = args != null && args.length > 0 ? args[0] 43723716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_START_MATCH; 43733716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String endMatch = args != null && args.length > 1 ? args[1] 43743716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_END_MATCH; 43753716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String ellipsis = args != null && args.length > 2 ? args[2] 43763716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_ELLIPSIS; 43773716f1447ceb21180d1301790eabd8b9453f486dDave Santoro int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 43783716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 43793716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4380547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return new SnippetizingCursorWrapper(cursor, query, startMatch, endMatch, ellipsis, 4381547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro maxTokens); 43826ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 43836ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 43846ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov private CrossProcessCursor getCrossProcessCursor(Cursor cursor) { 43856ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov Cursor c = cursor; 43866ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (c instanceof CrossProcessCursor) { 43876ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return (CrossProcessCursor) c; 43886ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else if (c instanceof CursorWindow) { 43896ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return getCrossProcessCursor(((CursorWrapper) c).getWrappedCursor()); 43906ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else { 43916ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 43926ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 43936ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 43946ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 43956ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov public MatrixCursor matrixCursorFromCursor(Cursor cursor) { 43966ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); 43976ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov int numColumns = cursor.getColumnCount(); 43986ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov String data[] = new String[numColumns]; 43996ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov cursor.moveToPosition(-1); 44006ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov while (cursor.moveToNext()) { 44016ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov for (int i = 0; i < numColumns; i++) { 44026ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov data[i] = cursor.getString(i); 44036ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 44046ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov newCursor.addRow(data); 4405332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov } 44066ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return newCursor; 4407d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4408d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4409d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final class DirectoryQuery { 4410d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final String[] COLUMNS = new String[] { 4411d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory._ID, 4412d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.DIRECTORY_AUTHORITY, 4413d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_NAME, 4414d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_TYPE 4415d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov }; 4416d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4417d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int DIRECTORY_ID = 0; 4418d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int AUTHORITY = 1; 4419d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_NAME = 2; 4420d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_TYPE = 3; 4421d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4422d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4423d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 4424d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Reads and caches directory information for the database. 4425d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 4426d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private DirectoryInfo getDirectoryAuthority(String directoryId) { 44274458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized (mDirectoryCache) { 44284458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov if (!mDirectoryCacheValid) { 44294458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.clear(); 443049d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov SQLiteDatabase db = mDbHelper.getReadableDatabase(); 443149d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Cursor cursor = db.query(Tables.DIRECTORIES, 44324458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryQuery.COLUMNS, 44334458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov null, null, null, null, null); 44344458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov try { 44354458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov while (cursor.moveToNext()) { 44364458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryInfo info = new DirectoryInfo(); 44374458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov String id = cursor.getString(DirectoryQuery.DIRECTORY_ID); 44384458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.authority = cursor.getString(DirectoryQuery.AUTHORITY); 44394458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME); 44404458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE); 44414458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.put(id, info); 44424458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 44434458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } finally { 44444458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov cursor.close(); 4445d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 44464458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = true; 4447d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4448d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 44494458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov return mDirectoryCache.get(directoryId); 44504458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 4451d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4452d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 445372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void resetDirectoryCache() { 44544458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized(mDirectoryCache) { 44554458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = false; 44564458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 445772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 445872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 44596ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private Cursor queryLocal(Uri uri, String[] projection, String selection, 44606ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro String[] selectionArgs, String sortOrder, long directoryId, 44616ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean suppressProfileCheck) { 4462bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 4463bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov Log.v(TAG, "query: " + uri); 4464bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov } 44650b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov 4466b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final SQLiteDatabase db = mDbHelper.getReadableDatabase(); 446735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4468d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 44691f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 4470c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov String limit = getLimit(uri); 4471c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 4472a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 44734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 447435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 4475b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getSyncState().query(db, projection, selection, selectionArgs, 447635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana sortOrder); 447735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4478d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 4479763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 448024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro boolean existingWhere = appendLocalDirectorySelectionIfNeeded(qb, directoryId); 44816ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, Contacts.IS_USER_PROFILE, existingWhere, 44826ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 44836ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro sortOrder = prependProfileSortIfNeeded(uri, sortOrder, suppressProfileCheck); 4484619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 4485619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 4486619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 4487d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 44884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 4489afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 4490763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 44914da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 44924da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 44936bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 44946bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 44956bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 44965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP: 44975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP_ID: { 44985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 44995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = pathSegments.size(); 45005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount < 3) { 4501fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 4502fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 45035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 4504a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 45055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String lookupKey = pathSegments.get(2); 45065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount == 4) { 45075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4508afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4510763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 4511a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4512a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4513a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4514a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 4515a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 45165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return c; 45175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 45185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 45195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 4520763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 45214da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 45224da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 45234da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 45245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 45255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 45265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 45272149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_DATA: 45282149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_ID_DATA: { 45292149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 45302149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov int segmentCount = pathSegments.size(); 45312149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount < 4) { 45322149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 45332149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov "Missing a lookup key", uri)); 45342149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 45352149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov String lookupKey = pathSegments.get(2); 45362149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount == 5) { 45372149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4538afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45392149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 45402149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(lookupQb, uri, projection, false); 4541a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 4542a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4543a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4544a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Data.CONTACT_ID, contactId, Data.LOOKUP_KEY, lookupKey); 4545a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 45462149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov return c; 45472149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 45482149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 45492149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov // TODO see if the contact exists but has no data rows (rare) 45502149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 45512149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 45522149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 455324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 4554afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45552149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 455624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 45572149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov qb.appendWhere(" AND " + Data.CONTACT_ID + "=?"); 45582149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov break; 45592149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 45602149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 45613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_ID_STREAM_ITEMS: { 45623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4563afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 45653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 45663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContactsColumns.CONCRETE_CONTACT_ID + "=?"); 45673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 45683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 45693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 45703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_STREAM_ITEMS: 45713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_ID_STREAM_ITEMS: { 45723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<String> pathSegments = uri.getPathSegments(); 45733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int segmentCount = pathSegments.size(); 45743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount < 4) { 45753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new IllegalArgumentException(mDbHelper.exceptionMessage( 45763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann "Missing a lookup key", uri)); 45773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 45783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String lookupKey = pathSegments.get(2); 45793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount == 5) { 45803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(pathSegments.get(3)); 4581afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 45833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(lookupQb); 45843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 45853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann projection, selection, selectionArgs, sortOrder, groupBy, limit, 45863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RawContacts.CONTACT_ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 45873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c != null) { 45883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return c; 45893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 45903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 45913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 45923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 45933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = lookupContactIdByLookupKey(db, lookupKey); 4594afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 45953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 45963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContacts.CONTACT_ID + "=?"); 45973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 45983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 45993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4600f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: { 460142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKey = Uri.encode(uri.getPathSegments().get(2)); 460224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 4603afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 4604ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 4605f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey qb.setProjectionMap(sContactsVCardProjectionMap); 46064da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 460724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 46084da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 4609f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey break; 4610f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey } 4611f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey 461242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 461342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); 461442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann String currentDateString = dateFormat.format(new Date()).toString(); 461542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann return db.rawQuery( 461642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann "SELECT" + 461742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " 'vcards_' || ? || '.vcf' AS " + OpenableColumns.DISPLAY_NAME + "," + 461842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " NULL AS " + OpenableColumns.SIZE, 461942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann new String[] { currentDateString }); 462042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 462142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 4622ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_FILTER: { 4623916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov String filterParam = ""; 4624ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 4625916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov filterParam = uri.getLastPathSegment(); 4626ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 46277ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov setTablesAndProjectionMapForContactsWithSnippet( 46287ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov qb, uri, projection, filterParam, directoryId); 46296ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, Contacts.IS_USER_PROFILE, false, 46306ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 46316ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro sortOrder = prependProfileSortIfNeeded(uri, sortOrder, suppressProfileCheck); 4632ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4633ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4634ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 4635ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT_FILTER: 4636ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT: { 46372f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Basically the resultant SQL should look like this: 46382f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing starred items) 46392f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 46402f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing frequently contacted items) 46412f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // ORDER BY ... 46422f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 46432f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final boolean phoneOnly = readBooleanQueryParameter( 46442f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa uri, ContactsContract.STREQUENT_PHONE_ONLY, false); 46452f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (match == CONTACTS_STREQUENT_FILTER && uri.getPathSegments().size() > 3) { 46464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 46474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4648e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(Contacts._ID + " IN "); 46495e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov appendContactFilterAsNestedQuery(sb, filterParam); 46502f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection = DbQueryUtils.concatenateClauses(selection, sb.toString()); 46514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 46524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 46532f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] subProjection = null; 46545e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection != null) { 46552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa subProjection = appendProjectionArg(projection, TIMES_USED_SORT_COLUMN); 46565e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 46575e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 46584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov // Build the first query for starred 46594928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 46604928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(phoneOnly ? 46614928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa sStrequentPhoneOnlyStarredProjectionMap 46624928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa : sStrequentStarredProjectionMap); 46632f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 46642f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection, Contacts.IS_USER_PROFILE + "=0")); 46652f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 46662f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String starredQuery = qb.buildQuery(subProjection, 466724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Contacts.STARRED + "=1", Contacts._ID, null, null, null); 4668d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 46692f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Reset the builder. 4670d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 46712f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 46724928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 46734928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // Build the second query for frequent part. 46744928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final String frequentQuery; 46754928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (phoneOnly) { 46764928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final StringBuilder tableBuilder = new StringBuilder(); 46774928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // In phone only mode, we need to look at view_data instead of 46784928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // contacts/raw_contacts to obtain actual phone numbers. One problem is that 46794928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data is much larger than view_contacts, so our query might become much 46804928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // slower. 46814928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // 46824928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // To avoid the possible slow down, we start from data usage table and join 46834928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data to the table, assuming data usage table is quite smaller than 46844928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // data rows (almost always it should be), and we don't want any phone 46854928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // numbers not used by the user. This way sqlite is able to drop a number of 46864928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // rows in view_data in the early stage of data lookup. 46874928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa tableBuilder.append(Tables.DATA_USAGE_STAT 46884928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " INNER JOIN " + Views.DATA + " " + Tables.DATA 46894928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" 46904928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataColumns.CONCRETE_ID + " AND " 46914928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" 46924928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT_CALL + ")"); 46934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactPresenceJoin(tableBuilder, projection, RawContacts.CONTACT_ID); 46944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactStatusUpdateJoin(tableBuilder, projection, 46954928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa ContactsColumns.LAST_STATUS_UPDATE_ID); 46964928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 46974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setTables(tableBuilder.toString()); 46984928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentPhoneOnlyFrequentProjectionMap); 46994928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 47004928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 47014928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.STARRED + "=0 OR " + Contacts.STARRED + " IS NULL", 47024928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa MimetypesColumns.MIMETYPE + " IN (" 47034928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + Phone.CONTENT_ITEM_TYPE + "', " 47044928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + SipAddress.CONTENT_ITEM_TYPE + "')")); 47054928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, null, null, null, null, null); 47064928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } else { 47074928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 47084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 47094928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 47104928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 47114928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa "(" + Contacts.STARRED + " =0 OR " + Contacts.STARRED + " IS NULL)", 47124928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.IS_USER_PROFILE + "=0")); 47134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, 47144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa null, Contacts._ID, null, null, null); 47154928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } 4716d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 4717d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 47182f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String unionQuery = 47192f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, 47202f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa STREQUENT_ORDER_BY, STREQUENT_LIMIT); 47212f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 47222f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Here, we need to use selection / selectionArgs (supplied from users) "twice", 47232f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // as we want them both for starred items and for frequently contacted items. 47242f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // 47252f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // e.g. if the user specify selection = "starred =?" and selectionArgs = "0", 47262f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // the resultant SQL should be like: 47272f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 47282f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 47292f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 47302f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] doubledSelectionArgs = null; 47312f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (selectionArgs != null) { 47322f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final int length = selectionArgs.length; 47332f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa doubledSelectionArgs = new String[length * 2]; 47347d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, 0, length); 47357d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, length, length); 47362f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 47372f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 47382f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa Cursor cursor = db.rawQuery(unionQuery, doubledSelectionArgs); 47392f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (cursor != null) { 47402f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa cursor.setNotificationUri(getContext().getContentResolver(), 4741d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 4742d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 47432f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa return cursor; 4744d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 4745d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 474645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa case CONTACTS_FREQUENT: { 474745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 474845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 4749363bdaba2994539e1a3a2342a9fcf223604d69eaDaisuke Miyakawa qb.appendWhere(Contacts.IS_USER_PROFILE + "=0"); 475045ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa groupBy = Contacts._ID; 475145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa if (!TextUtils.isEmpty(sortOrder)) { 475245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY + ", " + sortOrder; 475345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } else { 475445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY; 475545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 475645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa break; 475745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 475845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 4759ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_GROUP: { 4760763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 4761b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 476271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 47634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 4764b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4765b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 4766b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4767b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 476824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 476924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 477024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 477124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(Contacts.IS_USER_PROFILE + "=1"); 477224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 477324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 477424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 477524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: { 477624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 477724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForEntities(qb, uri, projection); 477824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + Contacts.IS_USER_PROFILE + "=1"); 477924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 478024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 478124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 478224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: { 478324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 478424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 478524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 478624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 478724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 478824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 478924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA_ID: { 479024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 479124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 479224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 479324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + Data._ID + "=? AND " 479424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 479524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 479624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 479724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 479824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: { 479924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 4800ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 480124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.setProjectionMap(sContactsVCardProjectionMap); 480224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(Contacts.IS_USER_PROFILE + "=1"); 480324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 480424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 480524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 4806a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_DATA: { 48074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 480882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 48094da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 48104da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 48116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 48126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 481300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 4814a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 48153653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4816afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 481782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 48184da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 48194da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 48203653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 48213653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov break; 48223653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov } 48233653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 4824a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_ENTITIES: { 4825a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 4826a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 4827a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 4828a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 4829a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 4830a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4831a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4832a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ENTITIES: 4833a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ID_ENTITIES: { 4834a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 4835a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov int segmentCount = pathSegments.size(); 4836a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount < 4) { 4837a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 4838a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov "Missing a lookup key", uri)); 4839a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4840a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lookupKey = pathSegments.get(2); 4841a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount == 5) { 4842a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 4843a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4844a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(lookupQb, uri, projection); 4845a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 4846a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4847a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 4848a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4849a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.CONTACT_ID, contactId, 4850a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.LOOKUP_KEY, lookupKey); 4851a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 4852a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 4853a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4854a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4855a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 4856a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 4857a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 4858a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 4859a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + Contacts.Entity.CONTACT_ID + "=?"); 4860a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 4861a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 4862a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 48633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 48643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 48653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 48663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 48683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 48693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 48703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 48713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemsColumns.CONCRETE_ID + "=?"); 48723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 48733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 48753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_LIMIT: { 48766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro MatrixCursor cursor = new MatrixCursor(new String[]{StreamItems.MAX_ITEMS}, 1); 48776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro cursor.addRow(new Object[]{MAX_STREAM_ITEMS_PER_RAW_CONTACT}); 48783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return cursor; 48793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 48813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 48823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 48833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 48843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 48863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 48873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 48883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 48893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 48903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?"); 48913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 48923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 48943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 48953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 48963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 48973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 48983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemPhotoId); 48993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 49003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=? AND " + 49013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=?"); 49023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 49033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 49043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4905f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case PHOTO_DIMENSIONS: { 4906f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro MatrixCursor cursor = new MatrixCursor( 4907f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM}, 4908f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1); 4909f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cursor.addRow(new Object[]{mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim}); 4910f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return cursor; 4911f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 4912f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 49134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case PHONES: { 491482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 491589c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 49162815f58f72f109790585931f601a63ddc02536a5Evan Millar break; 49172815f58f72f109790585931f601a63ddc02536a5Evan Millar } 49182815f58f72f109790585931f601a63ddc02536a5Evan Millar 491948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: { 492082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 49214da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 492248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 49234da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 492448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 492548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 492648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 4927ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES_FILTER: { 492846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 492946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 493046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 493146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_CALL; 493246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 493346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 493489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 4935ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 49364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 49374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4938a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(" AND ("); 49395e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 494045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov boolean hasCondition = false; 49415e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov boolean orNeeded = false; 49425e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov String normalizedName = NameNormalizer.normalize(filterParam); 49435e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (normalizedName.length() > 0) { 4944155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(Data.RAW_CONTACT_ID + " IN " + 4945155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 4946155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 4947155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 4948155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 4949155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 4950155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 49512352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 4952155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 49535e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov orNeeded = true; 495445d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 49555e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49565e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 4957892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String number = PhoneNumberUtils.normalizeNumber(filterParam); 4958892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (!TextUtils.isEmpty(number)) { 49595e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (orNeeded) { 49605e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(" OR "); 49615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49625e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(Data._ID + 4963892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID 4964892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " FROM " + Tables.PHONE_LOOKUP 4965892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 4966892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append(number); 4967892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append("%')"); 496845d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 496945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov } 497045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov 497145d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov if (!hasCondition) { 497245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // If it is neither a phone number nor a name, the query should return 497345d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // an empty cursor. Let's ensure that. 497445d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov sb.append("0"); 49755e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 49765e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 4977a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 4978ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 49795e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = PhoneColumns.NORMALIZED_NUMBER + "," + RawContacts.CONTACT_ID; 4980a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 498146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 498246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 498346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + PHONE_FILTER_SORT_ORDER; 498446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 498546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = PHONE_FILTER_SORT_ORDER; 498646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 4987a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 4988ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4989ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4990ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 49914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case EMAILS: { 499282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 499389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 49944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov break; 49954a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 49964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 499748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: { 499882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 49994da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 50004da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'" 50014da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + " AND " + Data._ID + "=?"); 500248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 500348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 500448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 50055e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_LOOKUP: { 500682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 500789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 50084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov if (uri.getPathSegments().size() > 2) { 500908768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String email = uri.getLastPathSegment(); 501008768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String address = mDbHelper.extractAddressFromEmailAddress(email); 501108768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, address); 501208768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)"); 50134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 5014ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5015ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5016ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 50175e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_FILTER: { 501846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 501946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 502046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 502146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT; 502246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 502346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 502407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov String filterParam = null; 50257d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa 502607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 502707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = uri.getLastPathSegment(); 502807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (TextUtils.isEmpty(filterParam)) { 502907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = null; 503007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 503107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 50325e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 503307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (filterParam == null) { 503407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov // If the filter is unspecified, return nothing 503507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov qb.appendWhere(" AND 0"); 503607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } else { 503707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov StringBuilder sb = new StringBuilder(); 503807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append(" AND " + Data._ID + " IN ("); 503907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append( 504007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov "SELECT " + Data._ID + 504107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov " FROM " + Tables.DATA + 50422a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov " WHERE " + DataColumns.MIMETYPE_ID + "="); 50432a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(mDbHelper.getMimeTypeIdForEmail()); 50442a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(" AND " + Data.DATA1 + " LIKE "); 504507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 504620938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov if (!filterParam.contains("@")) { 5047155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append( 5048155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " UNION SELECT " + Data._ID + 5049155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.DATA + 5050155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE +" + DataColumns.MIMETYPE_ID + "="); 5051155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(mDbHelper.getMimeTypeIdForEmail()); 5052155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(" AND " + Data.RAW_CONTACT_ID + " IN " + 5053155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 5054155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 5055155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 5056155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 5057155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 5058155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 50592352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 5060155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 50615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 50625e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 5063a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 50645e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 50655e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = Email.DATA + "," + RawContacts.CONTACT_ID; 5066a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 506746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 506846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 506946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + EMAIL_FILTER_SORT_ORDER; 50707d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } else { 50717d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa sortOrder = EMAIL_FILTER_SORT_ORDER; 50727d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } 5073a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 50745e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov break; 50755e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 50765e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 5077ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 507882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 507989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 508089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 5081ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5082ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5083ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 508448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 508582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50864da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 508748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 508848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 50894da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 509048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 509148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 509248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 50935ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 5094763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 50956ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, RawContacts.RAW_CONTACT_IS_USER_PROFILE, true, 50966ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 50974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 50984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 50994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 51005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 51015ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 5102afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 5103763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 51044da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 51054da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 51064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 51074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 51084f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 51095ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 51105ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 511182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 51124da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 51134da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?"); 51146ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, RawContacts.RAW_CONTACT_IS_USER_PROFILE, true, 51156ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 511624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 511724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 511824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 51193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 51203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5121afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 51223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 51233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 51243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=?"); 51253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 51263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 512724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 512824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 512924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 513024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 513124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1"); 513224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 513324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 513424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 513524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: { 513624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 513724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = ContentUris.parseId(uri); 513824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 513924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 514024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 514124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts._ID + "=?"); 514224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 514324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 514424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 514524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 514624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 514724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 514824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 514924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 515024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 515124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + Data.RAW_CONTACT_ID + "=?"); 515224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 515324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 515424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 515524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_ENTITIES: { 515624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 515724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 515824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 515924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawEntities(qb, uri); 516024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere(" AND " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + "=1 AND " 516124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + RawContacts._ID + "=?"); 5162e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5163e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5164e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 5165e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey case DATA: { 516682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 51676ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro appendProfileRestriction(qb, uri, RawContacts.RAW_CONTACT_IS_USER_PROFILE, true, 51686ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro suppressProfileCheck); 5169e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5170e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5171e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 51724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case DATA_ID: { 517324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = ContentUris.parseId(uri); 5174afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForData(db, dataId, false); 517582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 51764da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 51774da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 5178a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov break; 5179a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov } 5180a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov 5181a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 51824a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 5183a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton if (TextUtils.isEmpty(sortOrder)) { 5184a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Default the sort order to something reasonable so we get consistent 5185a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // results when callers don't request an ordering 5186892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sortOrder = " length(lookup.normalized_number) DESC"; 5187a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5188a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5189e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : ""; 5190e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov String numberE164 = PhoneNumberUtils.formatNumberToE164(number, 5191e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov mDbHelper.getCurrentCountryIso()); 5192892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String normalizedNumber = 5193892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov PhoneNumberUtils.normalizeNumber(number); 5194892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov mDbHelper.buildPhoneLookupAndContactQuery(qb, normalizedNumber, numberE164); 5195e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov qb.setProjectionMap(sPhoneLookupProjectionMap); 5196e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov // Phone lookup cannot be combined with a selection 5197e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selection = null; 5198e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selectionArgs = null; 5199a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 5200a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5201a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5202ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 5203ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5204ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 520543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 5206ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5207ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5208ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5209ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 5210ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5211ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 52124da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 52134da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Groups._ID + "=?"); 5214ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5215ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5216ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5217ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 5218f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa final boolean returnGroupCountPerAccount = 5219f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa readBooleanQueryParameter(uri, Groups.PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT, 5220f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa false); 5221f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa qb.setTables(Views.GROUPS + " AS " + Tables.GROUPS); 5222f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa qb.setProjectionMap(returnGroupCountPerAccount ? 5223f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa sGroupsSummaryProjectionMapWithGroupCountPerAccount 5224f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa : sGroupsSummaryProjectionMap); 522543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 5226f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa groupBy = GroupsColumns.CONCRETE_ID; 5227ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5228ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5229ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5230b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 52310c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS); 5232b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 5233b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 5234b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 5235b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 523631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 5237d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 52382d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov String filter = null; 52392d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 52402d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov filter = uri.getPathSegments().get(3); 52412d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov } 524231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 5243d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov if (limit != null) { 5244d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov maxSuggestions = Integer.parseInt(limit); 524531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 524631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 524731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 524831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 52495b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ArrayList<AggregationSuggestionParameter> parameters = null; 52505b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov List<String> query = uri.getQueryParameters("query"); 52515b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov if (query != null && !query.isEmpty()) { 52525b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters = new ArrayList<AggregationSuggestionParameter>(query.size()); 52535b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov for (String parameter : query) { 52545b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov int offset = parameter.indexOf(':'); 52555b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters.add(offset == -1 52565b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ? new AggregationSuggestionParameter( 525776dfa406e2cde19c824983c37fc92c1c5bf63eecDaniel Lehmann AggregationSuggestions.PARAMETER_MATCH_NAME, 52585b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter) 52595b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov : new AggregationSuggestionParameter( 52605b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(0, offset), 52615b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(offset + 1))); 52625b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 52635b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 52645b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 5265763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 52667581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov 52677581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov return mContactAggregator.queryAggregationSuggestions(qb, projection, contactId, 52685b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov maxSuggestions, filter, parameters); 526931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 527031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 5271eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 5272eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setTables(Tables.SETTINGS); 5273eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setProjectionMap(sSettingsProjectionMap); 527443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, false); 5275e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5276e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // When requesting specific columns, this query requires 5277e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // late-binding of the GroupMembership MIME-type. 5278b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov final String groupMembershipMimetypeId = Long.toString(mDbHelper 5279e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 528082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 5281b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.isInProjection(projection, Settings.UNGROUPED_COUNT)) { 5282e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5283e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 528482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 5285b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov mDbHelper.isInProjection(projection, Settings.UNGROUPED_WITH_PHONES)) { 5286e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5287e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 5288e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5289eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 5290eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 5291eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 529282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES: { 52930a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 52945ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 52955ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 52965ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 529782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES_ID: { 52980a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 52994da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 53004da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(DataColumns.CONCRETE_ID + "=?"); 53015ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 53025ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 53035ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 5304c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: { 5305174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchSuggestionsQuery( 5306174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, uri, projection, limit); 5307c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5308c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 5309c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: { 53102d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill String lookupKey = uri.getLastPathSegment(); 5311174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String filter = getQueryParameter( 5312174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov uri, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 5313174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchShortcutRefresh( 5314174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, projection, lookupKey, filter); 5315c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5316c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 53171b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS: 5318ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 53191b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 53201b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 53211b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 53221b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_WITH_PHONES: 5323ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 53241b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 53251b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1"); 53261b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 53271b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 53281b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_FAVORITES: 5329ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 53301b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 53311b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.STARRED + "=1"); 53321b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 53331b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 53341b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_GROUP_NAME: 5335ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 53361b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 533771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 53381b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 53391b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 53401b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 534146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITIES: { 5342a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 534346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 534446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 534546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 534646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITY_ID: { 534746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5348a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 53494da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 53504da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 535146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 535246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 535346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 535409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov case PROVIDER_STATUS: { 535509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return queryProviderStatus(uri, projection); 535609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 535709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5358d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES : { 5359d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5360d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5361d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5362d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5363d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 5364d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID : { 5365385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov long id = ContentUris.parseId(uri); 5366d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5367d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5368385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(id)); 5369d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.appendWhere(Directory._ID + "=?"); 5370d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5371d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5372d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 53737a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov case COMPLETE_NAME: { 53747a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return completeName(uri, projection); 53757a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 53767a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 53774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 5378f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 5379c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov sortOrder, limit); 53804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 53814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 538209e69522745551522c55dff27424496f255def46Daniel Lehmann qb.setStrict(true); 53837f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov 5384ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov Cursor cursor = 5385ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit); 5386ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) { 5387ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov cursor = bundleLetterCountExtras(cursor, db, qb, selection, selectionArgs, sortOrder); 5388ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5389ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov return cursor; 53905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 53915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 53925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection, 53935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String selection, String[] selectionArgs, String sortOrder, String groupBy, 53945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String limit) { 5395038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana if (projection != null && projection.length == 1 5396038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana && BaseColumns._COUNT.equals(projection[0])) { 5397038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana qb.setProjectionMap(sCountProjectionMap); 5398038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana } 53995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null, 54005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sortOrder, limit); 54014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 54024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 54034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 54044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 54054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 54064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 540709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov /** 540809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov * Creates a single-row cursor containing the current status of the provider. 540909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov */ 541009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private Cursor queryProviderStatus(Uri uri, String[] projection) { 541109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 541209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov RowBuilder row = cursor.newRow(); 541309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov for (int i = 0; i < projection.length; i++) { 541409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov if (ProviderStatus.STATUS.equals(projection[i])) { 541509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mProviderStatus); 541609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } else if (ProviderStatus.DATA1.equals(projection[i])) { 541709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mEstimatedStorageRequirement); 541809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 541909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 542009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return cursor; 542109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 542209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5423a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** 5424a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * Runs the query with the supplied contact ID and lookup ID. If the query succeeds, 5425a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * it returns the resulting cursor, otherwise it returns null and the calling 5426a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * method needs to resolve the lookup key and rerun the query. 5427a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov */ 5428a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private Cursor queryWithContactIdAndLookupKey(SQLiteQueryBuilder lookupQb, 5429a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteDatabase db, Uri uri, 5430a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection, String selection, String[] selectionArgs, 5431a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String sortOrder, String groupBy, String limit, 5432a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn, long contactId, String lookupKeyColumn, String lookupKey) { 5433a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] args; 5434a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (selectionArgs == null) { 5435a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[2]; 5436a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } else { 5437a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[selectionArgs.length + 2]; 5438a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 5439a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5440a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[0] = String.valueOf(contactId); 5441a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[1] = Uri.encode(lookupKey); 5442a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(contactIdColumn + "=? AND " + lookupKeyColumn + "=?"); 5443a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = query(db, lookupQb, projection, selection, args, sortOrder, 5444a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov groupBy, limit); 5445a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c.getCount() != 0) { 5446a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5447a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5448a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5449a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov c.close(); 5450a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return null; 5451a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 545209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5453bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov private static final class AddressBookIndexQuery { 5454bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String LETTER = "letter"; 5455bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String TITLE = "title"; 5456bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String COUNT = "count"; 5457ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5458bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String[] COLUMNS = new String[] { 5459bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov LETTER, TITLE, COUNT 5460ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov }; 5461ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5462bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_LETTER = 0; 5463bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_TITLE = 1; 5464bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_COUNT = 2; 5465bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 546624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The first letter of the sort key column is what is used for the index headings, except 546724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // in the case of the user's profile, in which case it is empty. 546824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro public static final String SECTION_HEADING_TEMPLATE = 546924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "(CASE WHEN %1$s=1 THEN '' ELSE SUBSTR(%2$s,1,1) END)"; 547024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5471de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa public static final String ORDER_BY = LETTER + " COLLATE " + PHONEBOOK_COLLATOR_NAME; 5472ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5473ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5474ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov /** 5475ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * Computes counts by the address book index titles and adds the resulting tally 5476ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * to the returned cursor as a bundle of extras. 5477ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov */ 5478ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov private Cursor bundleLetterCountExtras(Cursor cursor, final SQLiteDatabase db, 5479ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov SQLiteQueryBuilder qb, String selection, String[] selectionArgs, String sortOrder) { 5480ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortKey; 5481ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5482ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // The sort order suffix could be something like "DESC". 5483ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // We want to preserve it in the query even though we will change 5484ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // the sort column itself. 5485ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortOrderSuffix = ""; 5486ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (sortOrder != null) { 548724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 548824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // If the sort order contains one of the "is_profile" columns, we need to strip it out 548924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // first. 549024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (sortOrder.contains(Contacts.IS_USER_PROFILE) 549124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro || sortOrder.contains(RawContacts.RAW_CONTACT_IS_USER_PROFILE)) { 549224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String[] splitOrderClauses = sortOrder.split(","); 549324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro StringBuilder rejoinedClause = new StringBuilder(); 549424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro for (String orderClause : splitOrderClauses) { 549524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!orderClause.contains(Contacts.IS_USER_PROFILE) 549624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro && !orderClause.contains(RawContacts.RAW_CONTACT_IS_USER_PROFILE)) { 549724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (rejoinedClause.length() > 0) { 549824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro rejoinedClause.append(", "); 549924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 550024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro rejoinedClause.append(orderClause.trim()); 550124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 550224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 550324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sortOrder = rejoinedClause.toString(); 550424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 550524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5506ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int spaceIndex = sortOrder.indexOf(' '); 5507ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (spaceIndex != -1) { 5508ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder.substring(0, spaceIndex); 5509ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortOrderSuffix = sortOrder.substring(spaceIndex); 5510ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5511ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder; 5512ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5513ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5514ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = Contacts.SORT_KEY_PRIMARY; 5515ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5516ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5517bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String locale = getLocale().toString(); 5518ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov HashMap<String, String> projectionMap = Maps.newHashMap(); 551924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 552024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The user profile column varies depending on the view. 5521ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann String profileColumn = qb.getTables().contains(Views.CONTACTS) 552224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro ? Contacts.IS_USER_PROFILE 552324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro : RawContacts.RAW_CONTACT_IS_USER_PROFILE; 552424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String sectionHeading = String.format( 552524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro AddressBookIndexQuery.SECTION_HEADING_TEMPLATE, profileColumn, sortKey); 5526bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov projectionMap.put(AddressBookIndexQuery.LETTER, 552724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sectionHeading + " AS " + AddressBookIndexQuery.LETTER); 5528bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5529bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov /** 5530bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * Use the GET_PHONEBOOK_INDEX function, which is an android extension for SQLite3, 5531bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * to map the first letter of the sort key to a character that is traditionally 5532bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * used in phonebooks to represent that letter. For example, in Korean it will 5533bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * be the first consonant in the letter; for Japanese it will be Hiragana rather 5534bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * than Katakana. 5535bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov */ 5536ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.TITLE, 553724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "GET_PHONEBOOK_INDEX(" + sectionHeading + ",'" + locale + "')" 5538bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov + " AS " + AddressBookIndexQuery.TITLE); 5539ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.COUNT, 5540ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov "COUNT(" + Contacts._ID + ") AS " + AddressBookIndexQuery.COUNT); 5541ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov qb.setProjectionMap(projectionMap); 5542ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5543f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs, 5544ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY, null /* having */, 5545ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY + sortOrderSuffix); 5546ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5547ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov try { 5548f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov int groupCount = indexCursor.getCount(); 5549ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String titles[] = new String[groupCount]; 5550ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int counts[] = new int[groupCount]; 5551bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int indexCount = 0; 5552bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String currentTitle = null; 5553bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5554bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // Since GET_PHONEBOOK_INDEX is a many-to-1 function, we may end up 5555bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // with multiple entries for the same title. The following code 5556bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // collapses those duplicates. 5557ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov for (int i = 0; i < groupCount; i++) { 5558f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.moveToNext(); 5559bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String title = indexCursor.getString(AddressBookIndexQuery.COLUMN_TITLE); 5560bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int count = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT); 5561bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount == 0 || !TextUtils.equals(title, currentTitle)) { 5562bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles[indexCount] = currentTitle = title; 5563bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount] = count; 5564bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov indexCount++; 5565bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } else { 5566bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount - 1] += count; 5567bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5568bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5569bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5570bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount < groupCount) { 5571bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String[] newTitles = new String[indexCount]; 5572bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(titles, 0, newTitles, 0, indexCount); 5573bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles = newTitles; 5574bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5575bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int[] newCounts = new int[indexCount]; 5576bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(counts, 0, newCounts, 0, indexCount); 5577bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts = newCounts; 5578ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5579ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5580e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return new AddressBookCursor((CrossProcessCursor) cursor, titles, counts); 5581ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } finally { 5582f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.close(); 5583ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5584ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5585ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 55862d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill /** 558792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Returns the contact Id for the contact identified by the lookupKey. 558892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Robust against changes in the lookup key: if the key has changed, will 558992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * look up the contact by the raw contact IDs or name encoded in the lookup 559092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * key. 55912d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill */ 55922d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) { 55935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey key = new ContactLookupKey(); 55945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments = key.parse(lookupKey); 55955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 559692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov long contactId = -1; 559792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_SOURCE_ID)) { 559892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdBySourceIds(db, segments); 559992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 560092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 560192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 560292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 560392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 560492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov boolean hasRawContactIds = 560592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID); 560692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds) { 560792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdByRawContactIds(db, segments); 560892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 560992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 561092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 561192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 561292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 561392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds 561492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME)) { 56155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = lookupContactIdByDisplayNames(db, segments); 56165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 56195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private interface LookupBySourceIdQuery { 562243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 56235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 56255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 562643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 56275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 56285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.SOURCE_ID 56295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 56305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 563243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 56335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 56345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int SOURCE_ID = 3; 56355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long lookupContactIdBySourceIds(SQLiteDatabase db, 56385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments) { 56395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 56405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(RawContacts.SOURCE_ID + " IN ("); 56415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 56425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 564392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID) { 56445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 56455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 56465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 56495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 56505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS, 56525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 56535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 56545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 565543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 565643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 56575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME); 56585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 565943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 56605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID); 56615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 56625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 566392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID 566492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 56655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(sourceId)) { 56665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID); 56675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 56685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 56725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 56735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 56765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 567892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByRawContactIdQuery { 567943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 56805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 56825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 568343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 56845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 568592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts._ID, 56865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 56875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 56885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 568943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 56905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 569192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ID = 3; 56925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 56935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 569492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByRawContactIds(SQLiteDatabase db, 569592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 569692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 569792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(RawContacts._ID + " IN ("); 56985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 56995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 570092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 570192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(segment.rawContactId); 570292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(","); 57035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 570592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 570692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 57075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 570892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov Cursor c = db.query(LookupByRawContactIdQuery.TABLE, LookupByRawContactIdQuery.COLUMNS, 570992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.toString(), null, null, null, null); 571092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov try { 571192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov while (c.moveToNext()) { 571243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = c.getString( 571343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro LookupByRawContactIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 571492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountName = c.getString(LookupByRawContactIdQuery.ACCOUNT_NAME); 571592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int accountHashCode = 571643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 571792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String rawContactId = c.getString(LookupByRawContactIdQuery.ID); 571892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 571992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 572092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID 572192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 572292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && segment.rawContactId.equals(rawContactId)) { 572392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov segment.contactId = c.getLong(LookupByRawContactIdQuery.CONTACT_ID); 572492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov break; 572592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 572692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 572792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 572892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } finally { 572992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov c.close(); 57305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 573292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return getMostReferencedContactId(segments); 573392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 573492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 573592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByDisplayNameQuery { 573692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS; 573792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 573892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String COLUMNS[] = { 573992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.CONTACT_ID, 574043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 574192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 574292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov NameLookupColumns.NORMALIZED_NAME 574392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov }; 574492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 574592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int CONTACT_ID = 0; 574643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 574792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_NAME = 2; 574892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int NORMALIZED_NAME = 3; 574992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 575092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 575192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByDisplayNames(SQLiteDatabase db, 575292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 57535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 57545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(NameLookupColumns.NORMALIZED_NAME + " IN ("); 57555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 57565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 575792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 575892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 57595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 57605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 57615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 57645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY 57655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov + " AND " + RawContacts.CONTACT_ID + " NOT NULL"); 57665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 57675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS, 57685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 57695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 57705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 577143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 577243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE_AND_DATA_SET); 57735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME); 57745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 577543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 57765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME); 57775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 57785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 577992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if ((segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 578092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) 578192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 57825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(name)) { 57835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID); 57845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 57855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 57895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 57905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 57925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 57935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 579592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private boolean lookupKeyContainsType(ArrayList<LookupKeySegment> segments, int lookupType) { 579692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 579792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 579892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == lookupType) { 579992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return true; 580092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 580192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 580292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 580392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return false; 580492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 580592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 5806ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateLookupKeyForRawContact(SQLiteDatabase db, long rawContactId) { 5807ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov mContactAggregator.updateLookupKeyForRawContact(db, rawContactId); 5808ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov } 5809ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov 58105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov /** 58115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov * Returns the contact ID that is mentioned the highest number of times. 58125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov */ 58135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) { 58145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Collections.sort(segments); 58155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long bestContactId = -1; 58175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int bestRefCount = 0; 58185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = -1; 58205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int count = 0; 58215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = segments.size(); 58235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segmentCount; i++) { 58245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 58255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId != -1) { 58265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId == contactId) { 58275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count++; 58285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 58295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 58305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestContactId = contactId; 58315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestRefCount = count; 58325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = segment.contactId; 58345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count = 1; 58355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 58395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 58405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 58415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return bestContactId; 58425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 5845763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 5846763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar String[] projection) { 58474928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 58482f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 58492f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 58502f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 58514928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * @param includeDataUsageStat true when the table should include DataUsageStat table. 58524928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Note that this uses INNER JOIN instead of LEFT OUTER JOIN, so some of data in Contacts 58534928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * may be dropped. 58542f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 58552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 58564928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa String[] projection, boolean includeDataUsageStat) { 585782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 5858ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 58592f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 58602f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Just for frequently contacted contacts in Strequent Uri handling. 58614928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (includeDataUsageStat) { 58622f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa sb.append(" INNER JOIN " + 5863ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA_USAGE_STAT + " AS " + Tables.DATA_USAGE_STAT + 58642f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa " ON (" + 58652f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DbQueryUtils.concatenateClauses( 58662f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DataUsageStatColumns.CONCRETE_TIMES_USED + " > 0", 58674928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) + 58682f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa ")"); 58692f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 58702f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 58717ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 58727ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 5873916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setTables(sb.toString()); 5874916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionMap); 5875916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov } 5876916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 5877916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** 5878916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * Finds name lookup records matching the supplied filter, picks one arbitrary match per 5879916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * contact and joins that with other contacts tables. 5880916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov */ 5881916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private void setTablesAndProjectionMapForContactsWithSnippet(SQLiteQueryBuilder qb, Uri uri, 58827ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov String[] projection, String filter, long directoryId) { 58837ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov 58847ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5885ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 5886916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 588703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (filter != null) { 588803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov filter = filter.trim(); 588903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 589003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 589130cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov if (TextUtils.isEmpty(filter) || (directoryId != -1 && directoryId != Directory.DEFAULT)) { 589230cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov sb.append(" JOIN (SELECT NULL AS " + SearchSnippetColumns.SNIPPET + " WHERE 0)"); 58935e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } else { 58945e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov appendSearchIndexJoin(sb, uri, projection, filter); 58955e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 58967ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 58977ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 589803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setTables(sb.toString()); 589903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionWithSnippetMap); 590003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 5901916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 590203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private void appendSearchIndexJoin( 590303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov StringBuilder sb, Uri uri, String[] projection, String filter) { 5904916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 5905174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET)) { 590603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String[] args = null; 590703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String snippetArgs = 590803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 590903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (snippetArgs != null) { 591003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov args = snippetArgs.split(","); 591103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 591203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 59135e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String startMatch = args != null && args.length > 0 ? args[0] 59145e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_START_MATCH; 59155e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String endMatch = args != null && args.length > 1 ? args[1] 59165e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_END_MATCH; 59175e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String ellipsis = args != null && args.length > 2 ? args[2] 59185e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_ELLIPSIS; 59195e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 59205e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 59215e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 5922174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin( 5923174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb, filter, true, startMatch, endMatch, ellipsis, maxTokens); 5924174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 5925174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin(sb, filter, false, null, null, null, 0); 5926174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5927174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5928174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 5929174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public void appendSearchIndexJoin(StringBuilder sb, String filter, 5930174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean snippetNeeded, String startMatch, String endMatch, String ellipsis, 5931174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int maxTokens) { 5932174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isEmailAddress = false; 5933174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String emailAddress = null; 5934174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isPhoneNumber = false; 5935174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String phoneNumber = null; 5936174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String numberE164 = null; 5937174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 59383716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // If the query consists of a single word, we can do snippetizing after-the-fact for a 59393716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // performance boost. 59403716f1447ceb21180d1301790eabd8b9453f486dDave Santoro boolean singleTokenSearch = filter.split(QUERY_TOKENIZER_REGEX).length == 1; 59413716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 5942174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (filter.indexOf('@') != -1) { 5943174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov emailAddress = mDbHelper.extractAddressFromEmailAddress(filter); 5944174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isEmailAddress = !TextUtils.isEmpty(emailAddress); 5945174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 5946174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isPhoneNumber = isPhoneNumber(filter); 594704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (isPhoneNumber) { 594804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann phoneNumber = PhoneNumberUtils.normalizeNumber(filter); 594904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann numberE164 = PhoneNumberUtils.formatNumberToE164(phoneNumber, 595004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann mDbHelper.getCountryIso()); 595104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 5952174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 5953174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 5954174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(" JOIN (SELECT " + SearchIndexColumns.CONTACT_ID + " AS snippet_contact_id"); 5955174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (snippetNeeded) { 59565e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(", "); 59575e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 59583d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 59595e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 596004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Email.ADDRESS + ")"); 596104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + Tables.DATA_JOIN_RAW_CONTACTS); 596204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 596304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID + " AND " + Email.ADDRESS + " LIKE "); 596404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann DatabaseUtils.appendEscapedSQLString(sb, filter + "%"); 596504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 59663d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 59673d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(","); 59683716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 59693716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 59703716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 59713716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 59723716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 59733716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 59743716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 59753d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(")"); 59763d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 59773d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 59783d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 597904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Phone.NUMBER + ")"); 598004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + 598104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann Tables.DATA_JOIN_RAW_CONTACTS + " JOIN " + Tables.PHONE_LOOKUP); 598204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" ON " + DataColumns.CONCRETE_ID); 598304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID); 598404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 598504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID); 598604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" AND " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 598704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(phoneNumber); 598804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 598904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(numberE164)) { 599004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" OR " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 599104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(numberE164); 599204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 599304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 599404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 59955e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 59965e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 59973716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 59983716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 59993716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 60003716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 60013716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 60023716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 60033716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 60045e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 600503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 600604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann final String normalizedFilter = NameNormalizer.normalize(filter); 600704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(normalizedFilter)) { 60083716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 60093716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 60103716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 60113716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 60123716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("(CASE WHEN EXISTS (SELECT 1 FROM "); 60133716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.RAW_CONTACTS + " AS rc INNER JOIN "); 60143716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.NAME_LOOKUP + " AS nl ON (rc." + RawContacts._ID); 60153716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=nl." + NameLookupColumns.RAW_CONTACT_ID); 60163716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") WHERE nl." + NameLookupColumns.NORMALIZED_NAME); 60173716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" GLOB '" + normalizedFilter + "*' AND "); 60183716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("nl." + NameLookupColumns.NAME_TYPE + "="); 60193716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(NameLookupType.NAME_COLLATION_KEY + " AND "); 60203716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 60213716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=rc." + RawContacts.CONTACT_ID); 60223716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") THEN NULL ELSE "); 60233716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 60243716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" END)"); 60253716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 602604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } else { 602704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("NULL"); 602804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 602903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 60305e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" AS " + SearchSnippetColumns.SNIPPET); 60315e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 603203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 60335e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" FROM " + Tables.SEARCH_INDEX); 60345e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" WHERE "); 60355e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(Tables.SEARCH_INDEX + " MATCH "); 60365e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 60372352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, "\"" + sanitizeMatch(filter) + "*\""); 60383d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 60392352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, 604004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann "\"" + sanitizeMatch(filter) + "*\" OR \"" + phoneNumber + "*\"" 60412352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov + (numberE164 != null ? " OR \"" + numberE164 + "\"" : "")); 604203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 60432352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filter) + "*"); 60449c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov } 604503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov sb.append(") ON (" + Contacts._ID + "=snippet_contact_id)"); 6046a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov } 6047a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov 60482352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov private String sanitizeMatch(String filter) { 60492352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov // TODO more robust preprocessing of match expressions 60502352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov return filter.replace('-', ' ').replace('\"', ' '); 60512352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov } 60522352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov 60535e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov private void appendSnippetFunction( 60545e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov StringBuilder sb, String startMatch, String endMatch, String ellipsis, int maxTokens) { 60555e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append("snippet(" + Tables.SEARCH_INDEX + ","); 60565e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 60575e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 60585e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 60595e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 60605e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, ellipsis); 60615e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 60625e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov // The index of the column used for the snippet, "content" 60635e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(",1,"); 60645e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(maxTokens); 60655e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 60665e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 60675e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 6068763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) { 6069763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar StringBuilder sb = new StringBuilder(); 6070ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.RAW_CONTACTS); 6071763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setTables(sb.toString()); 6072763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setProjectionMap(sRawContactsProjectionMap); 607343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 6074763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar } 6075763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar 6076a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForRawEntities(SQLiteQueryBuilder qb, Uri uri) { 6077ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.RAW_ENTITIES); 6078a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sRawEntityProjectionMap); 607943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 608046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 608146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 608282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 608382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String[] projection, boolean distinct) { 608446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, distinct, null); 608546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 608646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 608746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 608846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @param usageType when non-null {@link Tables#DATA_USAGE_STAT} is joined with the specified 608946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type. 609046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 609146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 609246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String[] projection, boolean distinct, Integer usageType) { 609382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6094ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 609582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov sb.append(" data"); 609682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov 6097a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID); 6098a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6099a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6100a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 61013296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey 610246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (usageType != null) { 610346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa appendDataUsageStatJoin(sb, usageType, DataColumns.CONCRETE_ID); 610446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 610546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 610682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov qb.setTables(sb.toString()); 6107f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov 6108f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov boolean useDistinct = distinct 6109f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov || !mDbHelper.isInProjection(projection, DISTINCT_DATA_PROHIBITING_COLUMNS); 6110f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setDistinct(useDistinct); 6111f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setProjectionMap(useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap); 611243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 6113ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov } 6114ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov 61150a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb, 61160a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String[] projection) { 61170a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6118ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 61190a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" data"); 6120a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6121a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 61220a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6123a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6124a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sStatusUpdatesProjectionMap); 6125a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6126a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 61273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItems(SQLiteQueryBuilder qb) { 61281dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.STREAM_ITEMS 61291dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.RAW_CONTACTS + " ON (" 61301dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemsColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 61311dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.CONTACTS + " ON (" 61321dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + RawContactsColumns.CONCRETE_CONTACT_ID + "=" + ContactsColumns.CONCRETE_ID + ")"); 61333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemsProjectionMap); 61343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 61353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 61363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItemPhotos(SQLiteQueryBuilder qb) { 61371dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.PHOTO_FILES 61381dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.STREAM_ITEM_PHOTOS + " ON (" 61391dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_PHOTO_FILE_ID + "=" 61401dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + PhotoFilesColumns.CONCRETE_ID 61411dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.STREAM_ITEMS + " ON (" 61421dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=" 61431dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemsColumns.CONCRETE_ID + ")"); 61443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemPhotosProjectionMap); 61453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 61463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 6147a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForEntities(SQLiteQueryBuilder qb, Uri uri, 6148a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection) { 6149a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6150ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.ENTITIES); 6151a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" data"); 6152a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6153a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts.Entity.CONTACT_ID); 6154a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6155a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, Contacts.Entity.DATA_ID); 6156a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, Contacts.Entity.DATA_ID); 6157a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6158a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6159a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sEntityProjectionMap); 616043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 6161a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6162a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6163a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactStatusUpdateJoin(StringBuilder sb, String[] projection, 6164a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lastStatusUpdateIdColumn) { 6165a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, 6166a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS, 6167a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_RES_PACKAGE, 6168a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_ICON, 6169a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_LABEL, 6170a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_TIMESTAMP)) { 6171a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " " 6172a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.ALIAS + 6173a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + lastStatusUpdateIdColumn + "=" 6174a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")"); 61750a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6176a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 61770a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6178a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataStatusUpdateJoin(StringBuilder sb, String[] projection, 6179a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 6180b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov if (mDbHelper.isInProjection(projection, 61810a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS, 61820a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_RES_PACKAGE, 61830a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_ICON, 61840a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_LABEL, 61850a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_TIMESTAMP)) { 61860a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + 6187a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "=" 6188a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + dataIdColumn + ")"); 61890a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6190a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6191a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 619246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void appendDataUsageStatJoin(StringBuilder sb, int usageType, String dataIdColumn) { 619346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" LEFT OUTER JOIN " + Tables.DATA_USAGE_STAT + 619446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" + dataIdColumn + 619546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " AND " + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" + usageType + ")"); 619646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 619746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 6198a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactPresenceJoin(StringBuilder sb, String[] projection, 6199a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn) { 6200a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, 6201a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_PRESENCE, Contacts.CONTACT_CHAT_CAPABILITY)) { 6202a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + 6203a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + contactIdColumn + " = " 6204a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + ")"); 6205a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6206a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6207a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6208a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataPresenceJoin(StringBuilder sb, String[] projection, 6209a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 6210a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (mDbHelper.isInProjection(projection, Data.PRESENCE, Data.CHAT_CAPABILITY)) { 6211a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE + 6212a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdates.DATA_ID + "=" + dataIdColumn + ")"); 6213a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6214a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6215a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 621624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private boolean appendLocalDirectorySelectionIfNeeded(SQLiteQueryBuilder qb, long directoryId) { 6217385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directoryId == Directory.DEFAULT) { 6218385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY); 621924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 6220385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directoryId == Directory.LOCAL_INVISIBLE){ 6221385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " NOT IN " + Tables.DEFAULT_DIRECTORY); 622224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 622324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 622424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return false; 622524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 622624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 622724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private void appendProfileRestriction(SQLiteQueryBuilder qb, Uri uri, String profileColumn, 62286ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean andRequired, boolean suppressProfileCheck) { 62296ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (!shouldIncludeProfile(uri, suppressProfileCheck)) { 623024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.appendWhere((andRequired ? " AND (" : "") 623124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + profileColumn + " IS NULL OR " 623224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + profileColumn + "=0" 623324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro + (andRequired ? ")" : "")); 6234385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } 6235385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } 6236385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov 62376ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private String prependProfileSortIfNeeded(Uri uri, String sortOrder, 62386ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro boolean suppressProfileCheck) { 62396ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (shouldIncludeProfile(uri, suppressProfileCheck)) { 624024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (TextUtils.isEmpty(sortOrder)) { 624124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return Contacts.IS_USER_PROFILE + " DESC"; 624224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } else { 624324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return Contacts.IS_USER_PROFILE + " DESC, " + sortOrder; 624424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 624524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 624624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return sortOrder; 624724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 624824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 62496ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro private boolean shouldIncludeProfile(Uri uri, boolean suppressProfileCheck) { 625024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // The user's profile may be returned alongside other contacts if it was requested and 625124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro // the calling application has permission to read profile data. 6252377850d2dfd28eaf1b22273a50cfe066f6667ab9Dave Santoro boolean profileRequested = readBooleanQueryParameter(uri, ContactsContract.ALLOW_PROFILE, 625324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro false); 62546ae89770d8047852b6a1f6fb3cbac812910aa476Dave Santoro if (profileRequested && !suppressProfileCheck) { 625524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro enforceProfilePermission(false); 625624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 625724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return profileRequested; 625824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 625924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 626043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri, 626143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro boolean includeDataSet) { 6262f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6263f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 626443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 6265e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6266e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6267e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6268e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 6269fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6270fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6271e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6272e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6273e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6274e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6275e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6276e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 627743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String toAppend = RawContacts.ACCOUNT_NAME + "=" 62784a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + DatabaseUtils.sqlEscapeString(accountName) + " AND " 62794a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + RawContacts.ACCOUNT_TYPE + "=" 628043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + DatabaseUtils.sqlEscapeString(accountType); 628143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (includeDataSet) { 628243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (dataSet == null) { 628343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro toAppend += " AND " + RawContacts.DATA_SET + " IS NULL"; 628443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } else { 628543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro toAppend += " AND " + RawContacts.DATA_SET + "=" + 628643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro DatabaseUtils.sqlEscapeString(dataSet); 628743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 628843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 628943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro qb.appendWhere(toAppend); 62904a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } else { 62914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere("1"); 62924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 62934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 62944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 6295e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong private String appendAccountToSelection(Uri uri, String selection) { 6296f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6297f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 629843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 6299e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6300e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6301e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6302e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 6303fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6304fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6305e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6306e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6307e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6308e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6309e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6310e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 6311e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "=" 6312e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountName) + " AND " 6313e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + RawContacts.ACCOUNT_TYPE + "=" 6314e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountType)); 631543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!TextUtils.isEmpty(dataSet)) { 631643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selectionSb.append(" AND " + RawContacts.DATA_SET + "=") 631743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .append(DatabaseUtils.sqlEscapeString(dataSet)); 631843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 6319e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong if (!TextUtils.isEmpty(selection)) { 6320e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(" AND ("); 6321e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(selection); 6322e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(')'); 6323e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6324e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selectionSb.toString(); 6325e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } else { 6326e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selection; 6327e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6328e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6329e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong 63307e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 6331c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * Gets the value of the "limit" URI query parameter. 6332c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * 6333c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * @return A string containing a non-negative integer, or <code>null</code> if 6334c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * the parameter is not set, or is set to an invalid value. 6335c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov */ 6336f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private String getLimit(Uri uri) { 63372e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limitParam = getQueryParameter(uri, ContactsContract.LIMIT_PARAM_KEY); 6338c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (limitParam == null) { 6339c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6340c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6341c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov // make sure that the limit is a non-negative integer 6342c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov try { 6343c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov int l = Integer.parseInt(limitParam); 6344c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (l < 0) { 6345c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6346c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6347c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6348c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return String.valueOf(l); 6349c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } catch (NumberFormatException ex) { 6350c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6351c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6352c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6353c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6354c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 6355b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov @Override 6356f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 6357415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6358f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mode.equals("r")) { 6359f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mReadAccessLatch); 6360f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6361f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mWriteAccessLatch); 6362f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6363415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6364b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov int match = sUriMatcher.match(uri); 6365b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov switch (match) { 6366a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 6367afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 636824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6369afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, false); 6370afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro return openPhotoAssetFile(db, uri, mode, 637124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Data._ID + "=" + Contacts.PHOTO_ID + " AND " + 637224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContacts.CONTACT_ID + "=?", 637324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(rawContactId)}); 6374e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6375b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6376f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: { 6377f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6378f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6379f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact ID can only be read."); 6380f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6381afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6382f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 6383afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6384afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = db.query(Tables.CONTACTS, 6385f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{Contacts.PHOTO_FILE_ID}, 6386f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID + "=?", new String[]{String.valueOf(contactId)}, 6387f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, null); 6388f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6389f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6390f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(0); 6391f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6392f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6393f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6394f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6395f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6396f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6397f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6398f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: { 6399f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6400f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6401f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact lookup key can only be read."); 6402f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6403f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro List<String> pathSegments = uri.getPathSegments(); 6404f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int segmentCount = pathSegments.size(); 6405f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount < 4) { 6406f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException(mDbHelper.exceptionMessage( 6407f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Missing a lookup key", uri)); 6408f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6409afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6410f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String lookupKey = pathSegments.get(2); 6411f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Contacts.PHOTO_FILE_ID}; 6412f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount == 5) { 6413f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(pathSegments.get(3)); 6414afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6415f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 6416f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 6417afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 6418f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro projection, null, null, null, null, null, 6419f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 6420f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c != null) { 6421f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6422f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6423f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6424f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6425f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6426f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6427f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6428f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6429f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6430f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6431f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6432f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 6433afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 6434afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 6435afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = qb.query(db, projection, Contacts._ID + "=?", 6436f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(contactId)}, null, null, null); 6437f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6438f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6439f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6440f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6441f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6442f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6443f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6444f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6445f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6446f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: { 6447f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6448f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean writeable = !mode.equals("r"); 6449afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 6450afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForRawContact(db, rawContactId, writeable); 6451f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6452f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Find the primary photo data record for this raw contact. 6453f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6454f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Data._ID, Photo.PHOTO_FILE_ID}; 6455f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 6456afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro Cursor c = qb.query(db, projection, 6457f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?", 6458f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(rawContactId), Photo.CONTENT_ITEM_TYPE}, 6459f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, Data.IS_PRIMARY + " DESC"); 6460f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long dataId = 0; 6461f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = 0; 6462f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6463f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c.getCount() >= 1) { 6464f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6465f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro dataId = c.getLong(0); 6466f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro photoFileId = c.getLong(1); 6467f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6468f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6469f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6470f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6471f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6472f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If writeable, open a writeable file descriptor that we can monitor. 6473f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // When the caller finishes writing content, we'll process the photo and 6474f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // update the data record. 6475f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (writeable) { 6476f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForWrite(rawContactId, dataId, uri, mode); 6477f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6478f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6479f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6480f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6481f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6482f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: { 6483f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = ContentUris.parseId(uri); 6484f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6485f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6486f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by key can only be read."); 6487f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6488f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6489f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6490f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6491e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov case DATA_ID: { 6492afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro SQLiteDatabase db = mDbHelper.getReadableDatabase(); 649324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = Long.parseLong(uri.getPathSegments().get(1)); 6494afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForData(db, dataId, false); 6495afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro return openPhotoAssetFile(db, uri, mode, 6496e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov Data._ID + "=? AND " + Data.MIMETYPE + "='" + Photo.CONTENT_ITEM_TYPE + "'", 649724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(dataId)}); 6498d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6499d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6500fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case PROFILE_AS_VCARD: { 6501fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // When opening a contact as file, we pass back contents as a 6502fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // vCard-encoded stream. We build into a local buffer first, 6503fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // then pipe into MemoryFile once the exact size is known. 6504fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6505fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6506fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen return buildAssetFileDescriptor(localStream); 6507fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 650842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 6509fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case CONTACTS_AS_VCARD: { 651042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // When opening a contact as file, we pass back contents as a 651142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // vCard-encoded stream. We build into a local buffer first, 651242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // then pipe into MemoryFile once the exact size is known. 651342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6514fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6515f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 651642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 651742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 651842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 651949d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov SQLiteDatabase db = mDbHelper.getReadableDatabase(); 652042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKeys = uri.getPathSegments().get(2); 652142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String[] loopupKeyList = lookupKeys.split(":"); 652242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final StringBuilder inBuilder = new StringBuilder(); 6523fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Uri queryUri = Contacts.CONTENT_URI; 652442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann int index = 0; 6525fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen 6526d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // SQLite has limits on how many parameters can be used 6527d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // so the IDs are concatenated to a query string here instead 652842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann for (String lookupKey : loopupKeyList) { 652942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann if (index == 0) { 6530d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append("("); 653142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } else { 6532d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append(","); 653342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 653424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long contactId = lookupContactIdByLookupKey(db, lookupKey); 6535afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro enforceProfilePermissionForContact(db, contactId, false); 653624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro inBuilder.append(contactId); 6537fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (mProfileIdCache.profileContactId == contactId) { 6538fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen queryUri = queryUri.buildUpon().appendQueryParameter( 6539377850d2dfd28eaf1b22273a50cfe066f6667ab9Dave Santoro ContactsContract.ALLOW_PROFILE, "true").build(); 6540fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 654142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann index++; 654242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 654342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann inBuilder.append(')'); 654442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String selection = Contacts._ID + " IN " + inBuilder.toString(); 6545d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6546d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // When opening a contact as file, we pass back contents as a 6547d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // vCard-encoded stream. We build into a local buffer first, 6548d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // then pipe into MemoryFile once the exact size is known. 6549d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6550fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(queryUri, localStream, selection, null); 6551f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 6552d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6553b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6554b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov default: 6555fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov throw new FileNotFoundException(mDbHelper.exceptionMessage("File does not exist", 6556fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov uri)); 6557b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6558b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6559b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6560afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private AssetFileDescriptor openPhotoAssetFile(SQLiteDatabase db, Uri uri, String mode, 6561afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro String selection, String[] selectionArgs) 6562e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throws FileNotFoundException { 6563e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov if (!"r".equals(mode)) { 6564e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throw new FileNotFoundException(mDbHelper.exceptionMessage("Mode " + mode 6565e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov + " not supported.", uri)); 6566e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6567e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6568e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov String sql = 6569ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann "SELECT " + Photo.PHOTO + " FROM " + Views.DATA + 6570e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov " WHERE " + selection; 657108ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood try { 6572f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6573f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert DatabaseUtils.blobFileDescriptorForQuery(db, sql, selectionArgs)); 657408ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } catch (SQLiteDoneException e) { 657508ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood // this will happen if the DB query returns no rows (i.e. contact does not exist) 657608ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood throw new FileNotFoundException(uri.toString()); 657708ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } 6578e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6579e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6580f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6581f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a display photo from the photo store for reading. 6582f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoFileId The display photo file ID 6583f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor that allows the file to be read. 6584f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @throws FileNotFoundException If no photo file for the given ID exists. 6585f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6586f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForRead(long photoFileId) 6587f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throws FileNotFoundException { 6588f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoStore.Entry entry = mPhotoStore.get(photoFileId); 6589f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 6590f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return makeAssetFileDescriptor( 6591f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(new File(entry.path), 6592f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.MODE_READ_ONLY), 6593f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro entry.size); 6594f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6595f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 6596f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new FileNotFoundException("No photo file found for ID " + photoFileId); 6597f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6598f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6599f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6600f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6601f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a file descriptor for a photo to be written. When the caller completes writing 6602f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to the file (closing the output stream), the image will be parsed out and processed. 6603f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If processing succeeds, the given raw contact ID's primary photo record will be 6604f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * populated with the inserted image (if no primary photo record exists, the data ID can 6605f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * be left as 0, and a new data record will be inserted). 6606f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rawContactId Raw contact ID this photo entry should be associated with. 6607f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param dataId Data ID for a photo mimetype that will be updated with the inserted 6608f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * image. May be set to 0, in which case the inserted image will trigger creation 6609f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * of a new primary photo image data row for the raw contact. 6610f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param uri The URI being used to access this file. 6611f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param mode Read/write mode string. 6612f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor the caller can use to write an image file for the 6613f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact. 6614f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6615f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForWrite(long rawContactId, long dataId, Uri uri, 6616f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String mode) { 6617f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6618f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return new AssetFileDescriptor(new MonitoredParcelFileDescriptor(rawContactId, dataId, 6619f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(File.createTempFile("img", null), 6620f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentResolver.modeToMode(uri, mode))), 6621f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 0, AssetFileDescriptor.UNKNOWN_LENGTH); 6622f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException ioe) { 6623f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Could not create temp image file in mode " + mode); 6624f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return null; 6625f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6626f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6627f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6628f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6629f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Parcel file descriptor wrapper that monitors when the file is closed. 6630f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If the file contains a valid image, the image is either inserted into the given 6631f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact or updated in the given data row. 6632f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6633f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private class MonitoredParcelFileDescriptor extends ParcelFileDescriptor { 6634f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mRawContactId; 6635f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mDataId; 6636f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private MonitoredParcelFileDescriptor(long rawContactId, long dataId, 6637f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor descriptor) { 6638f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro super(descriptor); 6639f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mRawContactId = rawContactId; 6640f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDataId = dataId; 6641f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6642f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6643f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro @Override 6644f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public void close() throws IOException { 6645f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6646f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check to see whether a valid image was written out. 6647f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Bitmap b = BitmapFactory.decodeFileDescriptor(getFileDescriptor()); 6648f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (b != null) { 6649f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoProcessor processor = new PhotoProcessor(b, mMaxDisplayPhotoDim, 6650f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim); 6651f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6652f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Store the compressed photo in the photo store. 6653f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = mPhotoStore.insert(processor); 6654f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6655f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Depending on whether we already had a data row to attach the photo to, 6656f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // do an update or insert. 6657f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mDataId != 0) { 6658f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Update the data record with the new photo. 6659f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 6660f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6661f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6662f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6663f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6664f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6665f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6666f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6667f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6668f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro update(ContentUris.withAppendedId(Data.CONTENT_URI, mDataId), updateValues, 6669f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null); 6670f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6671f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Insert a new primary data record with the photo. 6672f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues insertValues = new ContentValues(); 6673f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6674f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6675f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6676f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6677f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 6678f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.IS_PRIMARY, 1); 6679f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6680f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6681f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6682f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6683f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insert(RawContacts.CONTENT_URI.buildUpon() 6684f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(String.valueOf(mRawContactId)) 6685f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(RawContacts.Data.CONTENT_DIRECTORY).build(), 6686f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues); 6687f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6688f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6689f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6690f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro super.close(); 6691f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6692f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6693f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6694f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6695d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile"; 6696d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6697d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6698f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert * Returns an {@link AssetFileDescriptor} backed by the 6699d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * contents of the given {@link ByteArrayOutputStream}. 6700d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6701f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) { 6702d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey try { 6703d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey stream.flush(); 6704d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6705d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final byte[] byteData = stream.toByteArray(); 6706d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6707f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6708f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert ParcelFileDescriptor.fromData(byteData, CONTACT_MEMORY_FILE_NAME), 6709f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert byteData.length); 6710d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } catch (IOException e) { 6711ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert Log.w(TAG, "Problem writing stream into an ParcelFileDescriptor: " + e.toString()); 6712ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert return null; 6713d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6714d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6715d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6716f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd) { 6717f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor(fd, AssetFileDescriptor.UNKNOWN_LENGTH); 6718f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6719f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6720f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd, long length) { 6721f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return fd != null ? new AssetFileDescriptor(fd, 0, length) : null; 6722f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6723f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6724d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6725d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * Output {@link RawContacts} matching the requested selection in the vCard 6726d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * format to the given {@link OutputStream}. This method returns silently if 6727d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * any errors encountered. 6728d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6729fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen private void outputRawContactsAsVCard(Uri uri, OutputStream stream, 6730fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen String selection, String[] selectionArgs) { 6731d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final Context context = this.getContext(); 6732dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen int vcardconfig = VCardConfig.VCARD_TYPE_DEFAULT; 6733fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if(uri.getBooleanQueryParameter( 6734fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, false)) { 6735dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen vcardconfig |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT; 6736dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen } 67377a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa final VCardComposer composer = 6738dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen new VCardComposer(context, vcardconfig, false); 6739108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Writer writer = null; 6740108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6741108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer = new BufferedWriter(new OutputStreamWriter(stream)); 6742fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (!composer.init(uri, selection, selectionArgs, null)) { 6743108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "Failed to init VCardComposer"); 6744108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa return; 6745108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6746d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6747108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa while (!composer.isAfterLast()) { 6748108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.write(composer.createOneEntry()); 6749108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6750108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6751108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.e(TAG, "IOException: " + e); 6752108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } finally { 6753108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa composer.terminate(); 6754108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa if (writer != null) { 6755108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6756108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.close(); 6757108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6758108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "IOException during closing output stream: " + e); 6759108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6760d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6761d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6762d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6763b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 67644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 67654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 6766415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6767415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov waitForAccess(mReadAccessLatch); 6768415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6769a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 67704f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 6771b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS: 6772be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return Contacts.CONTENT_TYPE; 67732d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill case CONTACTS_LOOKUP: 6774b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_ID: 6775b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_LOOKUP_ID: 677624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 6777b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_ITEM_TYPE; 6778f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: 677942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: 678024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 6781f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey return Contacts.CONTENT_VCARD_TYPE; 6782f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov case CONTACTS_ID_PHOTO: 6783f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: 6784f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6785f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: 6786f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: 6787f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: 6788f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return "image/jpeg"; 6789b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS: 679024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 6791be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return RawContacts.CONTENT_TYPE; 6792b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS_ID: 679324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 6794b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return RawContacts.CONTENT_ITEM_TYPE; 6795f481f22a9323fe338672f99b88b26c5f0725cd42David Brown case DATA: 679624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 6797f481f22a9323fe338672f99b88b26c5f0725cd42David Brown return Data.CONTENT_TYPE; 6798508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 6799b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return mDbHelper.getDataMimeType(ContentUris.parseId(uri)); 680048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES: 680148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_TYPE; 680248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 680348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_ITEM_TYPE; 68049005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov case PHONE_LOOKUP: 68059005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov return PhoneLookup.CONTENT_TYPE; 680648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS: 680748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_TYPE; 680848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 680948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_ITEM_TYPE; 681048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS: 681148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_TYPE; 681248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: 681348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_ITEM_TYPE; 6814b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 6815b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_TYPE; 6816b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 6817b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_ITEM_TYPE; 6818b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case SETTINGS: 6819b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Settings.CONTENT_TYPE; 6820b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 6821b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_TYPE; 6822c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: 6823c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SUGGEST_MIME_TYPE; 6824c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: 6825c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SHORTCUT_MIME_TYPE; 6826d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES: 6827d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_TYPE; 6828d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID: 6829d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_ITEM_TYPE; 683061efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov default: 683161efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov return mLegacyApiSupport.getType(uri); 68324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 68334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 68347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 683509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov public String[] getDefaultProjection(Uri uri) { 683609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov final int match = sUriMatcher.match(uri); 683709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov switch (match) { 683809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS: 683909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP: 684009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_ID: 684109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP_ID: 684209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 684324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 684409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsProjectionMap.getColumnNames(); 684509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 68468727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov case CONTACTS_ID_ENTITIES: 684724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: 68488727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov return sEntityProjectionMap.getColumnNames(); 68498727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov 685009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_VCARD: 685109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_MULTI_VCARD: 685224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 685309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsVCardProjectionMap.getColumnNames(); 685409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 685509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS: 685609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS_ID: 685724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 685824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 685909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sRawContactsProjectionMap.getColumnNames(); 686009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 686109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DATA_ID: 686209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES: 686309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES_ID: 686409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS: 686509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS_ID: 686609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS: 686709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS_ID: 686824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 686909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDataProjectionMap.getColumnNames(); 687009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 687109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONE_LOOKUP: 687209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sPhoneLookupProjectionMap.getColumnNames(); 687309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 687409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 687509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 687609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sAggregationExceptionsProjectionMap.getColumnNames(); 687709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 687809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case SETTINGS: 687909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sSettingsProjectionMap.getColumnNames(); 688009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 688109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES: 688209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES_ID: 688309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDirectoryProjectionMap.getColumnNames(); 688409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 688509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov default: 688609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return null; 688709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 688809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 688909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 6890f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private class StructuredNameLookupBuilder extends NameLookupBuilder { 6891f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6892f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov public StructuredNameLookupBuilder(NameSplitter splitter) { 6893f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov super(splitter); 6894f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6895f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6896f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 6897f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected void insertNameLookup(long rawContactId, long dataId, int lookupType, 6898f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov String name) { 689978fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov mDbHelper.insertNameLookup(rawContactId, dataId, lookupType, name); 6900f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6901f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 6902f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 6903f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected String[] getCommonNicknameClusters(String normalizedName) { 6904d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); 6905f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6906f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 6907f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 69082d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) { 6909d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov sb.append("(" + 6910d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov "SELECT DISTINCT " + RawContacts.CONTACT_ID + 6911d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 6912d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " JOIN " + Tables.NAME_LOOKUP + 6913d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " ON(" + RawContactsColumns.CONCRETE_ID + "=" 6914d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov + NameLookupColumns.RAW_CONTACT_ID + ")" + 6915d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " WHERE normalized_name GLOB '"); 6916e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(NameNormalizer.normalize(filterParam)); 6917916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov sb.append("*' AND " + NameLookupColumns.NAME_TYPE + 6918916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov " IN(" + CONTACT_LOOKUP_NAME_TYPES + "))"); 6919e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 6920e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 69219a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov public boolean isPhoneNumber(String filter) { 69229a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean atLeastOneDigit = false; 69239a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov int len = filter.length(); 69249a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov for (int i = 0; i < len; i++) { 69259a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov char c = filter.charAt(i); 69269a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (c >= '0' && c <= '9') { 69279a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov atLeastOneDigit = true; 69289a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } else if (c != '*' && c != '#' && c != '+' && c != 'N' && c != '.' && c != ';' 69299a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov && c != '-' && c != '(' && c != ')' && c != ' ') { 69309a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return false; 69319a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 69329a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 69339a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return atLeastOneDigit; 69349a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 69359a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 69364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** 69377a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * Takes components of a name from the query parameters and returns a cursor with those 69387a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * components as well as all missing components. There is no database activity involved 69397a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * in this so the call can be made on the UI thread. 69407a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov */ 69417a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private Cursor completeName(Uri uri, String[] projection) { 69427a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (projection == null) { 69437a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov projection = sDataProjectionMap.getColumnNames(); 69447a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 69457a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69467a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ContentValues values = new ContentValues(); 6947f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataRowHandlerForStructuredName handler = (DataRowHandlerForStructuredName) 6948f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov getDataRowHandler(StructuredName.CONTENT_ITEM_TYPE); 69497a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69507a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov copyQueryParamsToContentValues(values, uri, 69517a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.DISPLAY_NAME, 69527a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PREFIX, 69537a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.GIVEN_NAME, 69547a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.MIDDLE_NAME, 69557a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.FAMILY_NAME, 69567a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.SUFFIX, 69577a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_NAME, 69587a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_FAMILY_NAME, 69597a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_MIDDLE_NAME, 69607a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_GIVEN_NAME 69617a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ); 69627a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69637a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov handler.fixStructuredNameComponents(values, values); 69647a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69657a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 69667a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov Object[] row = new Object[projection.length]; 69677a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 69687a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov row[i] = values.get(projection[i]); 69697a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 69707a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov cursor.addRow(row); 69717a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return cursor; 69727a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 69737a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69747a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private void copyQueryParamsToContentValues(ContentValues values, Uri uri, String... columns) { 69757a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (String column : columns) { 69767a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov String param = uri.getQueryParameter(column); 69777a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (param != null) { 69787a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov values.put(column, param); 69797a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 69807a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 69817a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 69827a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69837a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 69847a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov /** 69854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov * Inserts an argument at the beginning of the selection arg list. 69864a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov */ 69874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private String[] insertSelectionArg(String[] selectionArgs, String arg) { 6988b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 6989b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 6990b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 6991b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 6992b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 69934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov newSelectionArgs[0] = arg; 69944a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length); 6995b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 6996b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 6997b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 6998caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 69995e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar private String[] appendProjectionArg(String[] projection, String arg) { 70005e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection == null) { 70015e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return null; 70025e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 70035e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar final int length = projection.length; 70045e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar String[] newProjection = new String[length + 1]; 70055e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar System.arraycopy(projection, 0, newProjection, 0, length); 70065e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar newProjection[length] = arg; 70075e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return newProjection; 70085e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 70095e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 7010caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov protected Account getDefaultAccount() { 7011caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov AccountManager accountManager = AccountManager.get(getContext()); 7012caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov try { 70135f1f4a062ac34d75d2dbf586702cbeb121cf09caDmitri Plotnikov Account[] accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE); 7014caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov if (accounts != null && accounts.length > 0) { 7015caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov return accounts[0]; 7016caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 7017caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } catch (Throwable e) { 70186f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov Log.e(TAG, "Cannot determine the default account for contacts compatibility", e); 7019caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 70206f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov return null; 7021caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 7022f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 702373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov /** 702443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Returns true if the specified account type and data set is writable. 702573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov */ 702643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro protected boolean isWritableAccountWithDataSet(String accountTypeAndDataSet) { 702743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (accountTypeAndDataSet == null) { 7028bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov return true; 7029bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov } 7030bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov 703143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Boolean writable = mAccountWritability.get(accountTypeAndDataSet); 703273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable != null) { 703373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 703473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 703573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 7036627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov IContentService contentService = ContentResolver.getContentService(); 7037627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 703843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO(dsantoro): Need to update this logic to allow for sub-accounts. 7039627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) { 7040627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov if (ContactsContract.AUTHORITY.equals(sync.authority) && 704143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountTypeAndDataSet.equals(sync.accountType)) { 704273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = sync.supportsUploading(); 704373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov break; 7044627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7045627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7046627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } catch (RemoteException e) { 7047627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov Log.e(TAG, "Could not acquire sync adapter types"); 7048627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 704973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 705073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable == null) { 705173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = false; 705273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 705373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 705443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mAccountWritability.put(accountTypeAndDataSet, writable); 705573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 7056627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7057b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov 7058d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 7059f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter, 7060f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean defaultValue) { 7061f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7062f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov // Manually parse the query, which is much faster than calling uri.getQueryParameter 7063f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 7064f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 7065f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 7066f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7067f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7068f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = query.indexOf(parameter); 7069f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 7070f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 7071f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7072f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7073f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameter.length(); 7074f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7075f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return !matchQueryParameter(query, index, "=0", false) 7076f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && !matchQueryParameter(query, index, "=false", true); 7077f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7078f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7079f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private static boolean matchQueryParameter(String query, int index, String value, 7080f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean ignoreCase) { 7081f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int length = value.length(); 7082f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return query.regionMatches(ignoreCase, index, value, 0, length) 7083f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && (query.length() == index + length || query.charAt(index + length) == '&'); 7084f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7085f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7086f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /** 7087f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * A fast re-implementation of {@link Uri#getQueryParameter} 7088f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov */ 7089f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static String getQueryParameter(Uri uri, String parameter) { 7090f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 7091f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 7092f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7093f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7094f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7095f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int queryLength = query.length(); 7096f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int parameterLength = parameter.length(); 7097f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7098f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String value; 7099f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = 0; 7100f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov while (true) { 7101f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index = query.indexOf(parameter, index); 7102f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 7103f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 71045fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 71055fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa 71065fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // Should match against the whole parameter instead of its suffix. 71075fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // e.g. The parameter "param" must not be found in "some_param=val". 71085fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (index > 0) { 71095fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa char prevChar = query.charAt(index - 1); 71105fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (prevChar != '?' && prevChar != '&') { 71115fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // With "some_param=val1¶m=val2", we should find second "param" occurrence. 71125fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa index += parameterLength; 71135fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa continue; 71145fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 7115f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7116f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7117f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameterLength; 7118f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7119f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (queryLength == index) { 7120f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7121f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7122f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7123f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query.charAt(index) == '=') { 7124f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index++; 7125f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov break; 7126f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7127f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7128f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7129f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int ampIndex = query.indexOf('&', index); 7130f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (ampIndex == -1) { 7131f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index); 7132f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } else { 7133f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index, ampIndex); 7134f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7135f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7136f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return Uri.decode(value); 7137f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 71385dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 71390dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov protected boolean isAggregationUpgradeNeeded() { 71400dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov if (!mContactAggregator.isEnabled()) { 71410dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return false; 71420dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 71430dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 71440dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_AGGREGATION_ALGORITHM, "1")); 71450dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return version < PROPERTY_AGGREGATION_ALGORITHM_VERSION; 71460dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 71470dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 7148bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void upgradeAggregationAlgorithmInBackground() { 71490dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // This upgrade will affect very few contacts, so it can be performed on the 71500dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // main thread during the initial boot after an OTA 71510dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 71520dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Upgrading aggregation algorithm"); 71530dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int count = 0; 71540dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long start = SystemClock.currentThreadTimeMillis(); 71550dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 715649d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov mDb = mDbHelper.getWritableDatabase(); 71570dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.beginTransaction(); 71580dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Cursor cursor = mDb.query(true, 71590dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Tables.RAW_CONTACTS + " r1 JOIN " + Tables.RAW_CONTACTS + " r2", 71600dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov new String[]{"r1." + RawContacts._ID}, 71610dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov "r1." + RawContacts._ID + "!=r2." + RawContacts._ID + 71620dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.CONTACT_ID + "=r2." + RawContacts.CONTACT_ID + 71630dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.ACCOUNT_NAME + "=r2." + RawContacts.ACCOUNT_NAME + 716443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND r1." + RawContacts.ACCOUNT_TYPE + "=r2." + RawContacts.ACCOUNT_TYPE + 716543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND r1." + RawContacts.DATA_SET + "=r2." + RawContacts.DATA_SET, 71660dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov null, null, null, null, null); 71670dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 71680dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov while (cursor.moveToNext()) { 71690dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long rawContactId = cursor.getLong(0); 71700dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, 71710dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 71720dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov count++; 71730dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 71740dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 71750dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov cursor.close(); 71760dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 7177bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.aggregateInTransaction(mTransactionContext, mDb); 7178bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 71790dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.setTransactionSuccessful(); 71800dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDbHelper.setProperty(PROPERTY_AGGREGATION_ALGORITHM, 71810dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov String.valueOf(PROPERTY_AGGREGATION_ALGORITHM_VERSION)); 71820dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 71830dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mDb.endTransaction(); 71840dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long end = SystemClock.currentThreadTimeMillis(); 71850dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Aggregation algorithm upgraded for " + count 71860dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov + " contacts, in " + (end - start) + "ms"); 71870dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 71880dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 71899a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 71909a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov /* Visible for testing */ 71919a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean isPhone() { 71929a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (!sIsPhoneInitialized) { 71939a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhone = new TelephonyManager(getContext()).isVoiceCapable(); 71949a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhoneInitialized = true; 71959a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 71969a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return sIsPhone; 71979a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 719846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 719946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private boolean handleDataUsageFeedback(Uri uri) { 720046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final long currentTimeMillis = System.currentTimeMillis(); 720146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 720246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] ids = uri.getLastPathSegment().trim().split(","); 720346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ArrayList<Long> dataIds = new ArrayList<Long>(); 720446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 720546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (String id : ids) { 720646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa dataIds.add(Long.valueOf(id)); 720746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 720846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final boolean successful; 720946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (TextUtils.isEmpty(usageType)) { 721046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.w(TAG, "Method for data usage feedback isn't specified. Ignoring."); 721146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = false; 721246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 721346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = updateDataUsageStat(dataIds, usageType, currentTimeMillis) > 0; 721446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 721546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 721646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Handle old API. This doesn't affect the result of this entire method. 721746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] questionMarks = new String[ids.length]; 721846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Arrays.fill(questionMarks, "?"); 721946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = Data._ID + " IN (" + TextUtils.join(",", questionMarks) + ")"; 722046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final Cursor cursor = mDb.query( 7221ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA, 722246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { Data.CONTACT_ID }, 722346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa where, ids, null, null, null); 722446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 722546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa while (cursor.moveToNext()) { 722646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mSelectionArgs1[0] = cursor.getString(0); 722746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa ContentValues values2 = new ContentValues(); 722846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values2.put(Contacts.LAST_TIME_CONTACTED, currentTimeMillis); 722946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.update(Tables.CONTACTS, values2, Contacts._ID + "=?", mSelectionArgs1); 723046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 723146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 723246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 723346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 723446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 723546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 723646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 723746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return successful; 723846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 723946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 724046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 724146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Update {@link Tables#DATA_USAGE_STAT}. 724246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * 724346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @return the number of rows affected. 724446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 7245f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa @VisibleForTesting 7246f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa /* package */ int updateDataUsageStat( 7247f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa List<Long> dataIds, String type, long currentTimeMillis) { 724846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final int typeInt = sDataUsageTypeMap.get(type); 724946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = DataUsageStatColumns.DATA_ID + " =? AND " 725046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT + " =?"; 725146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] columns = 725246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { DataUsageStatColumns._ID, DataUsageStatColumns.TIMES_USED }; 725346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ContentValues values = new ContentValues(); 725446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (Long dataId : dataIds) { 725546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] args = new String[] { dataId.toString(), String.valueOf(typeInt) }; 725646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.beginTransaction(); 725746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 725846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final Cursor cursor = mDb.query(Tables.DATA_USAGE_STAT, columns, where, args, 725946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa null, null, null); 726046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 726146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (cursor.getCount() > 0) { 726246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!cursor.moveToFirst()) { 726346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.e(TAG, 726446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa "moveToFirst() failed while getAccount() returned non-zero."); 726546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 726646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 726746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, cursor.getInt(1) + 1); 726846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 726946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.update(Tables.DATA_USAGE_STAT, values, 727046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns._ID + " =?", 727146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { cursor.getString(0) }); 727246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 727346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 727446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 727546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.DATA_ID, dataId); 727646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.USAGE_TYPE_INT, typeInt); 727746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, 1); 727846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 727946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.insert(Tables.DATA_USAGE_STAT, null, values); 728046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 728146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.setTransactionSuccessful(); 728246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 728346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 728446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 728546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 728646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mDb.endTransaction(); 728746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 728846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 728946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 729046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return dataIds.size(); 729146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 729246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 729346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 729446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Returns a sort order String for promoting data rows (email addresses, phone numbers, etc.) 729546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * associated with a primary account. The primary account should be supplied from applications 729646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * with {@link ContactsContract#PRIMARY_ACCOUNT_NAME} and 729746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * {@link ContactsContract#PRIMARY_ACCOUNT_TYPE}. Null will be returned when the primary 729846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * account isn't available. 729946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 730046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private String getAccountPromotionSortOrder(Uri uri) { 730146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountName = 730246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME); 730346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountType = 730446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE); 730546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 730646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Data rows associated with primary account should be promoted. 730746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountName)) { 730846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa StringBuilder sb = new StringBuilder(); 730946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append("(CASE WHEN " + RawContacts.ACCOUNT_NAME + "="); 731046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountName); 731146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountType)) { 731246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 731346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountType); 731446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 731546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" THEN 0 ELSE 1 END)"); 731646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return sb.toString(); 731746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 731846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return null; 731946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 732046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 73214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 7322