ContactsProvider2.java revision 82792ae937085bfa1f7878166e89ca4ea84fd652
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 1953214b3ed12b0ff9cb589b6559311f2ac142f2e3Bjorn Bringertimport com.android.common.content.SyncStateContentProviderHelper; 205b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport com.android.providers.contacts.ContactAggregator.AggregationSuggestionParameter; 2197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactLookupKey.LookupKeySegment; 2297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns; 2397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; 2497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Clauses; 2597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns; 2697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsStatusUpdatesColumns; 2797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; 2871340347b4862d4b1368a5d69d1667e2245952e4Daisuke Miyakawaimport com.android.providers.contacts.ContactsDatabaseHelper.DataUsageStatColumns; 2997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns; 302f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawaimport com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns; 3197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns; 3297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType; 3397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneColumns; 3497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; 351dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.PhotoFilesColumns; 3697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 3797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 3803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SearchIndexColumns; 3997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SettingsColumns; 4097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns; 413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemPhotosColumns; 42f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemsColumns; 4397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables; 44ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmannimport com.android.providers.contacts.ContactsDatabaseHelper.Views; 452f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawaimport com.android.providers.contacts.util.DbQueryUtils; 4697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardComposer; 4797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardConfig; 4897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Lists; 4997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Maps; 5097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Sets; 51f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawaimport com.google.common.annotations.VisibleForTesting; 5297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 53b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account; 54caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager; 555b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanaimport android.accounts.OnAccountsUpdateListener; 56bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.Notification; 57bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.NotificationManager; 58bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.PendingIntent; 59c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager; 60568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation; 61568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult; 626ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.content.ContentResolver; 6335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris; 6467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues; 6567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context; 66627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.IContentService; 67bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.content.Intent; 68568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException; 693d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences; 70627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.SyncAdapterType; 7167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher; 720bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.pm.PackageManager; 730bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.pm.PackageManager.NameNotFoundException; 745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoroimport android.content.pm.ProviderInfo; 75f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringertimport android.content.res.AssetFileDescriptor; 763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.content.res.Resources; 770bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.res.Resources.NotFoundException; 78409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onukiimport android.database.AbstractCursor; 79e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikovimport android.database.CrossProcessCursor; 804f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor; 81e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikovimport android.database.CursorWindow; 82ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.database.CursorWrapper; 83ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils; 8409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor; 8509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor.RowBuilder; 86f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoroimport android.database.sqlite.SQLiteConstraintException; 874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase; 8808ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwoodimport android.database.sqlite.SQLiteDoneException; 894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder; 90f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.Bitmap; 91f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.BitmapFactory; 924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri; 93d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.net.Uri.Builder; 94c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoroimport android.os.AsyncTask; 95bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Binder; 966ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.os.Bundle; 97bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Handler; 98bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.HandlerThread; 99bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Message; 100ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringertimport android.os.ParcelFileDescriptor; 101c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoroimport android.os.ParcelFileDescriptor.AutoCloseInputStream; 102bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Process; 103b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException; 10415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikovimport android.os.StrictMode; 1050dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikovimport android.os.SystemClock; 1060e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport android.os.SystemProperties; 1073d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager; 108508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns; 1093de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract; 110b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions; 11182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoroimport android.provider.ContactsContract.Authorization; 11297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email; 11397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.GroupMembership; 11497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im; 11597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname; 1166d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Note; 11797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization; 11897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone; 11997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo; 1204928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.SipAddress; 12197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 12297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 123ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.provider.ContactsContract.ContactCounts; 1243de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Contacts; 1255b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.AggregationSuggestions; 1263de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Data; 12771340347b4862d4b1368a5d69d1667e2245952e4Daisuke Miyakawaimport android.provider.ContactsContract.DataUsageFeedback; 128d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.provider.ContactsContract.Directory; 129f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.DisplayPhoto; 1303de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Groups; 131bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.provider.ContactsContract.Intents; 1323de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup; 1331dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoroimport android.provider.ContactsContract.PhotoFiles; 1340c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoroimport android.provider.ContactsContract.Profile; 13509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.provider.ContactsContract.ProviderStatus; 1363de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.RawContacts; 1373711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenenimport android.provider.ContactsContract.RawContactsEntity; 138916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikovimport android.provider.ContactsContract.SearchSnippetColumns; 1393de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Settings; 14082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikovimport android.provider.ContactsContract.StatusUpdates; 1413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.provider.ContactsContract.StreamItemPhotos; 142f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.StreamItems; 14397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.LiveFolders; 14497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.OpenableColumns; 14597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.SyncStateContract; 146a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils; 1479a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikovimport android.telephony.TelephonyManager; 148a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils; 149c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log; 1504f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 151108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.BufferedWriter; 152d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.ByteArrayOutputStream; 153f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.File; 154b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException; 155d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.IOException; 156d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.OutputStream; 157108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.OutputStreamWriter; 158108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.Writer; 15942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.text.SimpleDateFormat; 1607e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList; 16146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawaimport java.util.Arrays; 1625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections; 16342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.util.Date; 164b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap; 1650e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.HashSet; 1665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List; 167622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkeyimport java.util.Locale; 168b5a4add17815167d20a90645779df34cdf45280dFred Quintanaimport java.util.Map; 16982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoroimport java.util.Random; 1700e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.Set; 171ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch; 1724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/** 1744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications 1754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}. 1764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 177078f588cef389358adabc579de00747878f3c108Dave Santoropublic class ContactsProvider2 extends AbstractContactsProvider 178078f588cef389358adabc579de00747878f3c108Dave Santoro implements OnAccountsUpdateListener { 179caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 180bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov private static final String TAG = "ContactsProvider"; 181bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov 182bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE); 1834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 18415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_INITIALIZE = 0; 18515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_OPEN_WRITE_ACCESS = 1; 18615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS = 2; 18715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_ACCOUNTS = 3; 18815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_LOCALE = 4; 18915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM = 5; 19005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_SEARCH_INDEX = 6; 19105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_PROVIDER_STATUS = 7; 19205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_DIRECTORIES = 8; 19305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_CHANGE_LOCALE = 9; 194f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int BACKGROUND_TASK_CLEANUP_PHOTOS = 10; 195619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** Default for the maximum number of returned aggregation suggestions. */ 1973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DEFAULT_MAX_SUGGESTIONS = 5; 1983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 1993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Limit for the maximum number of social stream items to store under a raw contact. */ 2003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int MAX_STREAM_ITEMS_PER_RAW_CONTACT = 5; 2013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 202f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Rate limit (in ms) for photo cleanup. Do it at most once per day. */ 203f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_CLEANUP_RATE_LIMIT = 24 * 60 * 60 * 1000; 204f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 2053d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /** 20682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Default expiration duration for pre-authorized URIs. May be overridden from a secure 20782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * setting. 20882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 20982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private static final int DEFAULT_PREAUTHORIZED_URI_EXPIRATION = 5 * 60 * 1000; 21082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 21182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro /** 21282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Random URI parameter that will be appended to preauthorized URIs for uniqueness. 21382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 21482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private static final String PREAUTHORIZED_URI_TOKEN = "perm_token"; 21582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 21682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro /** 217b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov * Property key for the legacy contact import version. The need for a version 2183d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov * as opposed to a boolean flag is that if we discover bugs in the contact import process, 2193d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov * we can trigger re-import by incrementing the import version. 2203d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov */ 221b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov private static final String PROPERTY_CONTACTS_IMPORTED = "contacts_imported_v1"; 222b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov private static final int PROPERTY_CONTACTS_IMPORT_VERSION = 1; 22351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov private static final String PREF_LOCALE = "locale"; 2243d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2250dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final String PROPERTY_AGGREGATION_ALGORITHM = "aggregation_v2"; 2260dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final int PROPERTY_AGGREGATION_ALGORITHM_VERSION = 2; 2270dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 2280e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate"; 2290e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff 2305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final ProfileAwareUriMatcher sUriMatcher = 2315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ProfileAwareUriMatcher(UriMatcher.NO_MATCH); 2324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2332f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 2342f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * Used to insert a column into strequent results, which enables SQL to sort the list using 2352f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * the total times contacted. See also {@link #sStrequentFrequentProjectionMap}. 2362f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 2372f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private static final String TIMES_USED_SORT_COLUMN = "times_used_sort"; 2385e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 239d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, " 2402f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa + TIMES_USED_SORT_COLUMN + " DESC, " 2419b43551f1ce33b79141772737a262ce609bd0cebMegha Joshi + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 242d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final String STREQUENT_LIMIT = 243d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE " 244d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov + Contacts.STARRED + "=1) + 25"; 245d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov 24645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final String FREQUENT_ORDER_BY = DataUsageStatColumns.TIMES_USED + " DESC," 24745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 24845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 2496e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE = 2509b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.CONTACTS + " SET " + Contacts.TIMES_CONTACTED + "=" + 2519b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " CASE WHEN " + Contacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " + 2529b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " (" + Contacts.TIMES_CONTACTED + " + 1) END WHERE " + Contacts._ID + "=?"; 2539b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 2546e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE = 2559b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.RAW_CONTACTS + " SET " + RawContacts.TIMES_CONTACTED + "=" + 2569b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " CASE WHEN " + RawContacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " + 2579b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " (" + RawContacts.TIMES_CONTACTED + " + 1) END WHERE " + RawContacts.CONTACT_ID + "=?"; 2589b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 259de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK"; 260de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa 2613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Regex for splitting query strings - we split on any group of non-alphanumeric characters, 2623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // excluding the @ symbol. 2633716f1447ceb21180d1301790eabd8b9453f486dDave Santoro /* package */ static final String QUERY_TOKENIZER_REGEX = "[^\\w@]+"; 2643716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 265d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS = 1000; 266d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS_ID = 1001; 2675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP = 1002; 2685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP_ID = 1003; 269a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_DATA = 1004; 2705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_FILTER = 1005; 2715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT = 1006; 2725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT_FILTER = 1007; 2735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_GROUP = 1008; 274a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_PHOTO = 1009; 275bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_PHOTO = 1010; 276bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_PHOTO = 1011; 277bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_ID_DISPLAY_PHOTO = 1012; 278bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_DISPLAY_PHOTO = 1013; 279bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_DISPLAY_PHOTO = 1014; 280bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_AS_VCARD = 1015; 281bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_AS_MULTI_VCARD = 1016; 282bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_DATA = 1017; 283bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_DATA = 1018; 284bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_ID_ENTITIES = 1019; 285bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ENTITIES = 1020; 286bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_ENTITIES = 1021; 287bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_ID_STREAM_ITEMS = 1022; 288bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_STREAM_ITEMS = 1023; 289bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_STREAM_ITEMS = 1024; 290bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_FREQUENT = 1025; 2914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2925ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS = 2002; 2935ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_ID = 2003; 2945ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_DATA = 2004; 29546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITY_ID = 2005; 296f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_DISPLAY_PHOTO = 2006; 297f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS = 2007; 29882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS_ID = 2008; 2994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 3006bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 3016bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 302ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 30348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_ID = 3003; 30448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_FILTER = 3004; 30548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS = 3005; 30648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_ID = 3006; 30748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_LOOKUP = 3007; 30848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_FILTER = 3008; 30948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS = 3009; 31048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS_ID = 3010; 311a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 3126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 3136bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 314b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 315b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 316b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 31782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES = 7000; 31882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES_ID = 7001; 3191f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 32031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 32131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 322eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey private static final int SETTINGS = 9000; 323eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 324ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 325ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 326ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 327ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 32835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 329b5a4add17815167d20a90645779df34cdf45280dFred Quintana private static final int SYNCSTATE_ID = 11001; 3305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_SYNCSTATE = 11002; 3315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_SYNCSTATE_ID = 11003; 33235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 333c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SUGGESTIONS = 12001; 334c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SHORTCUT = 12002; 335c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 3361b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS = 14000; 3371b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001; 3381b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002; 3391b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003; 3401b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 34146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITIES = 15001; 34246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 34309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private static final int PROVIDER_STATUS = 16001; 34409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 345d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES = 17001; 346d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES_ID = 17002; 347d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 3487a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private static final int COMPLETE_NAME = 18000; 3497a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 35024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE = 19000; 35124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_ENTITIES = 19001; 35224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA = 19002; 35324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA_ID = 19003; 35424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_AS_VCARD = 19004; 35524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS = 19005; 35624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID = 19006; 35724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_DATA = 19007; 35824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_ENTITIES = 19008; 3595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_STATUS_UPDATES = 19009; 3603202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro private static final int PROFILE_RAW_CONTACT_ENTITIES = 19010; 36185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro private static final int PROFILE_PHOTO = 19011; 36285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro private static final int PROFILE_DISPLAY_PHOTO = 19012; 36324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 36446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final int DATA_USAGE_FEEDBACK_ID = 20001; 36546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 3663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS = 21000; 3673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_PHOTOS = 21001; 3683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID = 21002; 3693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS = 21003; 3703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS_ID = 21004; 3713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_LIMIT = 21005; 3723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 373f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int DISPLAY_PHOTO = 22000; 374f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_DIMENSIONS = 22001; 375f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 3765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Inserts into URIs in this map will direct to the profile database if the parent record's 3775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // value (looked up from the ContentValues object with the key specified by the value in this 3785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // map) is in the profile ID-space (see {@link ProfileDatabaseHelper#PROFILE_ID_SPACE}). 3795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final Map<Integer, String> INSERT_URI_ID_VALUE_MAP = Maps.newHashMap(); 3805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro static { 3815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(DATA, Data.RAW_CONTACT_ID); 3825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(RAW_CONTACTS_DATA, Data.RAW_CONTACT_ID); 3835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STATUS_UPDATES, StatusUpdates.DATA_ID); 3845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS, StreamItems.RAW_CONTACT_ID); 3855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(RAW_CONTACTS_ID_STREAM_ITEMS, StreamItems.RAW_CONTACT_ID); 3865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID); 3875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS_ID_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID); 3885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 3895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 39036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Any interactions that involve these URIs will also require the calling package to have either 39136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // android.permission.READ_SOCIAL_STREAM permission or android.permission.WRITE_SOCIAL_STREAM 39236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // permission, depending on the type of operation being performed. 39336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro private static final List<Integer> SOCIAL_STREAM_URIS = Lists.newArrayList( 39436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro CONTACTS_ID_STREAM_ITEMS, 39536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro CONTACTS_LOOKUP_STREAM_ITEMS, 39636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro CONTACTS_LOOKUP_ID_STREAM_ITEMS, 39736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro RAW_CONTACTS_ID_STREAM_ITEMS, 39836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro RAW_CONTACTS_ID_STREAM_ITEMS_ID, 39936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS, 40036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_PHOTOS, 40136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_ID, 40236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_ID_PHOTOS, 40336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_ID_PHOTOS_ID 40436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro ); 40536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 406dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID = 407dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 408dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME 409dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "=" + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 410dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE 41143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + "=" + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND (" 41243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET 41343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + "=" + RawContactsColumns.CONCRETE_DATA_SET + " OR " 41443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 41543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " IS NULL)" 416dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND " + Groups.FAVORITES + " != 0"; 417dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 418dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID = 419dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 420dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 421dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 422dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 42343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND (" 42443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + "=" 42543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " OR " 42643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 42743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " IS NULL)" 42843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + " AND " + Groups.AUTO_ADD + " != 0"; 429dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 430dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String[] PROJECTION_GROUP_ID 431dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana = new String[]{Tables.GROUPS + "." + Groups._ID}; 432dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 433dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_GROUPMEMBERSHIP_DATA = DataColumns.MIMETYPE_ID + "=? " 434dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.GROUP_ROW_ID + "=? " 435dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.RAW_CONTACT_ID + "=?"; 436dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 437dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_STARRED_FROM_RAW_CONTACTS = 438dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana "SELECT " + RawContacts.STARRED 439dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " FROM " + Tables.RAW_CONTACTS + " WHERE " + RawContacts._ID + "=?"; 440dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 441d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private interface DataContactsQuery { 442f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov public static final String TABLE = "data " 443f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) " 444f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)"; 44567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 44667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 4476cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov RawContactsColumns.CONCRETE_ID, 4486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_TYPE, 4496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_NAME, 45043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContactsColumns.CONCRETE_DATA_SET, 4513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 452f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov ContactsColumns.CONCRETE_ID 453ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 454ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 455d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov public static final int RAW_CONTACT_ID = 0; 4566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_TYPE = 1; 4576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_NAME = 2; 45843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_SET = 3; 45943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_ID = 4; 46043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int CONTACT_ID = 5; 461ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 4621f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 463f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov interface RawContactsQuery { 46419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String TABLE = Tables.RAW_CONTACTS; 46519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 46619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String[] COLUMNS = new String[] { 467ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.DELETED, 468ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 469ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_NAME, 47043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.DATA_SET, 47119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka }; 47219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 47319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int DELETED = 0; 474ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_TYPE = 1; 475ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_NAME = 2; 47643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int DATA_SET = 3; 47719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 47819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 479c76cdd0723b99f478c9ba5329d14a971cd8dfb3dCostin Manolache public static final String DEFAULT_ACCOUNT_TYPE = "com.google"; 480caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 48171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov /** Sql where statement for filtering on groups. */ 48271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov private static final String CONTACTS_IN_GROUP_SELECT = 48371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov Contacts._ID + " IN " 48471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + RawContacts.CONTACT_ID 48571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.RAW_CONTACTS 48671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN " 48771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 48871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.DATA_JOIN_MIMETYPES 4897cf50494501938f175d288077145acf49da8f171Daniel Lehmann + " WHERE " + DataColumns.MIMETYPE_ID + "=?" 4907cf50494501938f175d288077145acf49da8f171Daniel Lehmann + " AND " + GroupMembership.GROUP_ROW_ID + "=" 49171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + Tables.GROUPS + "." + Groups._ID 49271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.GROUPS 49371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Groups.TITLE + "=?)))"; 49471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov 495a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating DIRTY flag on multiple raw contacts */ 496a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_DIRTY_SQL = 497a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 498a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.DIRTY + "=1" + 499a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 500a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 501a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating VERSION on multiple raw contacts */ 502a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL = 503a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 504a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.VERSION + " = " + RawContacts.VERSION + " + 1" + 505a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 506a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 507c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Current contacts - those contacted within the last 3 days (in seconds) 508c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_CURRENT = 3 * 24 * 60 * 60; 509c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 510c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Recent contacts - those contacted within the last 30 days (in seconds) 511c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_RECENT = 30 * 24 * 60 * 60; 512c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 513f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa private static final String TIME_SINCE_LAST_USED = 514f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa "(strftime('%s', 'now') - " + DataUsageStatColumns.LAST_TIME_USED + "/1000)"; 515f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa 516c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov /* 517c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * Sorting order for email address suggestions: first starred, then the rest. 5182262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * second in_visible_group, then the rest. 5192262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * Within the four (starred/unstarred, in_visible_group/not-in_visible_group) groups 5202262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * - three buckets: very recently contacted, then fairly 521c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * recently contacted, then the rest. Within each of the bucket - descending count 52246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * of times contacted (both for data row and for contact row). If all else fails, alphabetical. 52346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * (Super)primary email address is returned before other addresses for the same contact. 524c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov */ 525c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final String EMAIL_FILTER_SORT_ORDER = 5262262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa Contacts.STARRED + " DESC, " 5272262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa + Contacts.IN_VISIBLE_GROUP + " DESC, " 528f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + "(CASE WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_CURRENT 52946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 0 " 530f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + " WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_RECENT 53146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 1 " 53246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " ELSE 2 END), " 53346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.TIMES_USED + " DESC, " 53446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Contacts.DISPLAY_NAME + ", " 53546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Data.CONTACT_ID + ", " 536c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_SUPER_PRIMARY + " DESC, " 537c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_PRIMARY + " DESC"; 53846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 53946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** Currently same as {@link #EMAIL_FILTER_SORT_ORDER} */ 54046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final String PHONE_FILTER_SORT_ORDER = EMAIL_FILTER_SORT_ORDER; 541c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 542916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Name lookup types used for contact filtering */ 543916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private static final String CONTACT_LOOKUP_NAME_TYPES = 544916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.NAME_COLLATION_KEY + "," + 545916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.EMAIL_BASED_NICKNAME + "," + 54692ddc5cdc4d89ee2c6e861ae7b3a3a913ffa0100Dmitri Plotnikov NameLookupType.NICKNAME; 547916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 548f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov /** 549f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * If any of these columns are used in a Data projection, there is no point in 550f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * using the DISTINCT keyword, which can negatively affect performance. 551f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov */ 552f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov private static final String[] DISTINCT_DATA_PROHIBITING_COLUMNS = { 553f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data._ID, 554f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.RAW_CONTACT_ID, 555f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.NAME_RAW_CONTACT_ID, 556f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 557f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 55843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.DATA_SET, 55943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 560f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.DIRTY, 561f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.NAME_VERIFIED, 562f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.SOURCE_ID, 563f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.VERSION, 564f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov }; 565916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 566f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsColumns = ProjectionMap.builder() 567f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CUSTOM_RINGTONE) 568f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME) 569f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_ALTERNATIVE) 570f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_SOURCE) 571f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.IN_VISIBLE_GROUP) 572f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LAST_TIME_CONTACTED) 573f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LOOKUP_KEY) 574f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME) 575f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME_STYLE) 576f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHOTO_ID) 577f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .add(Contacts.PHOTO_FILE_ID) 5783d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_URI) 5793d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_THUMBNAIL_URI) 580f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SEND_TO_VOICEMAIL) 581f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_ALTERNATIVE) 582f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_PRIMARY) 583f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.STARRED) 584f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.TIMES_CONTACTED) 585cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 586f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 587f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 588f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsPresenceColumns = ProjectionMap.builder() 589f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 590f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE) 591f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 592f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 593f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 594f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 595f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 596f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 597f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 598f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 599f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 600f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 601f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 602f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 603f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 604f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 605f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSnippetColumns = ProjectionMap.builder() 60603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov .add(SearchSnippetColumns.SNIPPET) 607f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 608f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 609f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactColumns = ProjectionMap.builder() 610f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_NAME) 611f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_TYPE) 61243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.DATA_SET) 61343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.ACCOUNT_TYPE_AND_DATA_SET) 614f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DIRTY) 615f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.NAME_VERIFIED) 616f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SOURCE_ID) 617f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.VERSION) 618f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 619f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 620f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactSyncColumns = ProjectionMap.builder() 621f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC1) 622f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC2) 623f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC3) 624f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC4) 625f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 626f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 627f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataColumns = ProjectionMap.builder() 628f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA1) 629f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA2) 630f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA3) 631f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA4) 632f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA5) 633f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA6) 634f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA7) 635f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA8) 636f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA9) 637f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA10) 638f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA11) 639f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA12) 640f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA13) 641f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA14) 642f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA15) 643f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA_VERSION) 644f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_PRIMARY) 645f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_SUPER_PRIMARY) 646f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.MIMETYPE) 647f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RES_PACKAGE) 648f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC1) 649f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC2) 650f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC3) 651f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC4) 652f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(GroupMembership.GROUP_SOURCE_ID) 653f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 654f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 655f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactPresenceColumns = ProjectionMap.builder() 656f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 657f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.PRESENCE) 658f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 659f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.CHAT_CAPABILITY) 660f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 661f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 662f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 663f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 664f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 665f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 666f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 667f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 668f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 669f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 670f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 671f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 672f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataPresenceColumns = ProjectionMap.builder() 673f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.PRESENCE, Tables.PRESENCE + "." + StatusUpdates.PRESENCE) 674f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CHAT_CAPABILITY, Tables.PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 675f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS, StatusUpdatesColumns.CONCRETE_STATUS) 676f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_TIMESTAMP, StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 677f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_RES_PACKAGE, StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 678f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_LABEL, StatusUpdatesColumns.CONCRETE_STATUS_LABEL) 679f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_ICON, StatusUpdatesColumns.CONCRETE_STATUS_ICON) 680f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 681f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 682038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana /** Contains just BaseColumns._COUNT */ 683f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sCountProjectionMap = ProjectionMap.builder() 684f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(BaseColumns._COUNT, "COUNT(*)") 685f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 686f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 687e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov /** Contains just the contacts columns */ 688f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionMap = ProjectionMap.builder() 689f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts._ID) 690f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 691f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.NAME_RAW_CONTACT_ID) 69224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 693f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 694f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsPresenceColumns) 695f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 696f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 697916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Contains just the contacts columns */ 698f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionWithSnippetMap = ProjectionMap.builder() 699f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 700f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sSnippetColumns) 701f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 702916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 7035e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar /** Used for pushing starred contacts to the top of a times contacted list **/ 704f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentStarredProjectionMap = ProjectionMap.builder() 705f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 7062f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 707f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 708f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 709f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder() 710f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 7112f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, "SUM(" + DataUsageStatColumns.CONCRETE_TIMES_USED + ")") 712f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 713f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 7154928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 7164928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. Right now Starred part just returns NULL for 7174928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * those data columns (frequent part should return real ones in data table). 7184928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 7194928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyStarredProjectionMap 7204928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 7214928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 7224928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 7234928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER, "NULL") 7244928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE, "NULL") 7254928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL, "NULL") 7264928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7274928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 7284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 7294928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 7304928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. We hard-code {@link Contacts#IS_USER_PROFILE} to NULL, 7314928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * because sContactsProjectionMap specifies a field that doesn't exist in the view behind the 7324928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * query that uses this projection map. 7334928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 7344928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyFrequentProjectionMap 7354928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 7364928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 7374928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, DataUsageStatColumns.CONCRETE_TIMES_USED) 7384928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER) 7394928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE) 7404928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL) 7414928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Contacts.IS_USER_PROFILE, "NULL") 7424928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7434928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 744f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey /** Contains just the contacts vCard columns */ 745f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsVCardProjectionMap = ProjectionMap.builder() 746fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen .add(Contacts._ID) 747f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME + " || '.vcf'") 748f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.SIZE, "NULL") 749f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 750f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 751ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov /** Contains just the raw contacts columns */ 752f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactsProjectionMap = ProjectionMap.builder() 753f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 754f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 755f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 756f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_PRIMARY) 757f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_ALTERNATIVE) 758f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_SOURCE) 759f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME) 760f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME_STYLE) 761f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_PRIMARY) 762f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_ALTERNATIVE) 763f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.TIMES_CONTACTED) 764f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.LAST_TIME_CONTACTED) 765f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CUSTOM_RINGTONE) 766f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SEND_TO_VOICEMAIL) 767f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 768f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.AGGREGATION_MODE) 76924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 770f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 771f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 772f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 773f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 774a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the raw entity view*/ 775f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawEntityProjectionMap = ProjectionMap.builder() 776f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 777f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 778f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.Entity.DATA_ID) 779f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 780f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 78124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 782f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 783f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 784f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 785f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 786f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 787a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the contact entity view*/ 788f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sEntityProjectionMap = ProjectionMap.builder() 789f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity._ID) 790f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.CONTACT_ID) 791f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.RAW_CONTACT_ID) 792f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DATA_ID) 793f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.NAME_RAW_CONTACT_ID) 794f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DELETED) 79524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 796f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 797f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 798f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 799f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 800f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 801f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 802f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 803f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 8044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** Contains columns from the data view */ 805f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataProjectionMap = ProjectionMap.builder() 806f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID) 807f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RAW_CONTACT_ID) 808f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CONTACT_ID) 809f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.NAME_RAW_CONTACT_ID) 81024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 811f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 812f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 813f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 814f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 815f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 816f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 817f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 8185e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov /** Contains columns from the data view */ 819f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDistinctDataProjectionMap = ProjectionMap.builder() 820f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID, "MIN(" + Data._ID + ")") 821f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 82224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 823f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 824f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 825f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 826f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 827f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 828f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 8299261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data and contacts columns, for joined tables */ 830f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sPhoneLookupProjectionMap = ProjectionMap.builder() 831f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup._ID, "contacts_view." + Contacts._ID) 832f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LOOKUP_KEY, "contacts_view." + Contacts.LOOKUP_KEY) 833f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.DISPLAY_NAME, "contacts_view." + Contacts.DISPLAY_NAME) 834f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LAST_TIME_CONTACTED, "contacts_view." + Contacts.LAST_TIME_CONTACTED) 835f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TIMES_CONTACTED, "contacts_view." + Contacts.TIMES_CONTACTED) 836f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.STARRED, "contacts_view." + Contacts.STARRED) 837f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.IN_VISIBLE_GROUP, "contacts_view." + Contacts.IN_VISIBLE_GROUP) 838f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.PHOTO_ID, "contacts_view." + Contacts.PHOTO_ID) 8393d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_URI, "contacts_view." + Contacts.PHOTO_URI) 8403d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_THUMBNAIL_URI, "contacts_view." + Contacts.PHOTO_THUMBNAIL_URI) 841f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.CUSTOM_RINGTONE, "contacts_view." + Contacts.CUSTOM_RINGTONE) 842f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.HAS_PHONE_NUMBER, "contacts_view." + Contacts.HAS_PHONE_NUMBER) 843f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.SEND_TO_VOICEMAIL, "contacts_view." + Contacts.SEND_TO_VOICEMAIL) 844f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.NUMBER, Phone.NUMBER) 845f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TYPE, Phone.TYPE) 846f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LABEL, Phone.LABEL) 8472530512f639c4979fd7371c7dd25dd67e8118124Bai Tao .add(PhoneLookup.NORMALIZED_NUMBER, Phone.NORMALIZED_NUMBER) 848f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 849f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 850ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 851f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsProjectionMap = ProjectionMap.builder() 852f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups._ID) 853f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_NAME) 854f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_TYPE) 85543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.DATA_SET) 85643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.ACCOUNT_TYPE_AND_DATA_SET) 857f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SOURCE_ID) 858f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DIRTY) 859f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.VERSION) 860f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.RES_PACKAGE) 861f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE) 862f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE_RES) 863f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.GROUP_VISIBLE) 864f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYSTEM_ID) 865f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DELETED) 866f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.NOTES) 867f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SHOULD_SYNC) 868f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.FAVORITES) 869f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.AUTO_ADD) 870c039cfb78c40730483fd71178df63ada5826a315Dmitri Plotnikov .add(Groups.GROUP_IS_READ_ONLY) 871f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC1) 872f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC2) 873f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC3) 874f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC4) 875f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 876f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 877ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains {@link Groups} columns along with summary details */ 878f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsSummaryProjectionMap = ProjectionMap.builder() 879f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sGroupsProjectionMap) 880f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_COUNT, 881f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 882f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 883f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")") 884f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_WITH_PHONES, 885f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 886f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 887f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " WHERE " + Contacts.HAS_PHONE_NUMBER + ")") 888f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .build(); 889f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa 890f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa // This is only exposed as hidden API for the contacts app, so we can be very specific in 891f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa // the filtering 892f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa private static final ProjectionMap sGroupsSummaryProjectionMapWithGroupCountPerAccount = 893f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa ProjectionMap.builder() 894f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .addAll(sGroupsSummaryProjectionMap) 895f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .add(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 896f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(*) FROM " + Views.GROUPS + " WHERE " 897f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + "(" + Groups.ACCOUNT_NAME + "=" 898f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + GroupsColumns.CONCRETE_ACCOUNT_NAME 899f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " AND " 900f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.ACCOUNT_TYPE + "=" + GroupsColumns.CONCRETE_ACCOUNT_TYPE 901f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " AND " 902f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.DELETED + "=0 AND " 903f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.FAVORITES + "=0 AND " 904f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.AUTO_ADD + "=0" 905f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")" 906f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " GROUP BY " 907f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.ACCOUNT_NAME + ", " + Groups.ACCOUNT_TYPE 908f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")") 909f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 910f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 911373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov /** Contains the agg_exceptions columns */ 912f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sAggregationExceptionsProjectionMap = ProjectionMap.builder() 913f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id") 914f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.TYPE) 915f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID1) 916f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID2) 917f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 918f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 919eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey /** Contains the agg_exceptions columns */ 920f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSettingsProjectionMap = ProjectionMap.builder() 921f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_NAME) 922f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_TYPE) 923f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro .add(Settings.DATA_SET) 924f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_VISIBLE) 925f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.SHOULD_SYNC) 926f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ANY_UNSYNCED, 927f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN MIN(" + Settings.SHOULD_SYNC 928f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ",(SELECT " 929f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "(CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL" 930f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 931f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE MIN(" + Groups.SHOULD_SYNC + ")" 932f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)" 933f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.GROUPS 934f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 935f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_NAME 936f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 937f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + SettingsColumns.CONCRETE_ACCOUNT_TYPE 938f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + " AND ((" + GroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 939f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + SettingsColumns.CONCRETE_DATA_SET + " IS NULL) OR (" 940f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + GroupsColumns.CONCRETE_DATA_SET + "=" 941f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + SettingsColumns.CONCRETE_DATA_SET + "))))=0" 942f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 943f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE 0" 944f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)") 945f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_COUNT, 946f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 947f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 948f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 949f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 950f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 951f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 952f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_WITH_PHONES, 953f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 954f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 955f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 956f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Contacts.HAS_PHONE_NUMBER 957f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 958f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 959f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 960f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 961f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 96282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov /** Contains StatusUpdates columns */ 963f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStatusUpdatesProjectionMap = ProjectionMap.builder() 964f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PresenceColumns.RAW_CONTACT_ID) 965f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.DATA_ID, DataColumns.CONCRETE_ID) 966f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_ACCOUNT) 967f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_HANDLE) 968f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PROTOCOL) 969f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 970f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // properly enforce uniqueness of null values 971f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CUSTOM_PROTOCOL, 972f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL + "=''" 973f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN NULL" 974f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END)") 975f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PRESENCE) 976f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CHAT_CAPABILITY) 977f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS) 978f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_TIMESTAMP) 979f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_RES_PACKAGE) 980f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_ICON) 981f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_LABEL) 982f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 983f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 9843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Contains StreamItems columns */ 9853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemsProjectionMap = ProjectionMap.builder() 9869b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems._ID) 9879b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.CONTACT_ID) 988af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann .add(StreamItems.CONTACT_LOOKUP_KEY) 9899b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.ACCOUNT_NAME) 9909b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.ACCOUNT_TYPE) 9919b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.DATA_SET) 9923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9939b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.RAW_CONTACT_SOURCE_ID) 9943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_PACKAGE) 9953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_ICON) 9963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_LABEL) 9973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TEXT) 9983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TIMESTAMP) 9993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.COMMENTS) 10000bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC1) 10010bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC2) 10020bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC3) 10030bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC4) 10043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 10053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 10063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemPhotosProjectionMap = ProjectionMap.builder() 10073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos._ID, StreamItemPhotosColumns.CONCRETE_ID) 10083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 10090bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.RAW_CONTACT_SOURCE_ID, RawContactsColumns.CONCRETE_SOURCE_ID) 10103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.STREAM_ITEM_ID) 10113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.SORT_INDEX) 10126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_FILE_ID) 10136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_URI, 10146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro "'" + DisplayPhoto.CONTENT_URI + "'||'/'||" + StreamItemPhotos.PHOTO_FILE_ID) 10151dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.HEIGHT) 10161dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.WIDTH) 10171dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.FILESIZE) 10180bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC1) 10190bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC2) 10200bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC3) 10210bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC4) 10223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 10233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 10241b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov /** Contains Live Folders columns */ 1025f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sLiveFoldersProjectionMap = ProjectionMap.builder() 1026f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders._ID, Contacts._ID) 1027f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders.NAME, Contacts.DISPLAY_NAME) 1028f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // TODO: Put contact photo back when we have a way to display a default icon 1029f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // for contacts without a photo 1030f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // .add(LiveFolders.ICON_BITMAP, Photos.DATA) 1031f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 1032f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 1033d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** Contains {@link Directory} columns */ 1034f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDirectoryProjectionMap = ProjectionMap.builder() 1035f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory._ID) 1036f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.PACKAGE_NAME) 1037f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.TYPE_RESOURCE_ID) 1038f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DISPLAY_NAME) 1039f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DIRECTORY_AUTHORITY) 1040f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_TYPE) 1041f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_NAME) 1042f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.EXPORT_SUPPORT) 1043778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.SHORTCUT_SUPPORT) 1044778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.PHOTO_SUPPORT) 1045f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 10467e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // where clause to update the status_updates table 10489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE = 10499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID + 10509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE + 10519705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE "; 10529705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 10532526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private static final String[] EMPTY_STRING_ARRAY = new String[0]; 10542526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1055bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1056bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Notification ID for failure to import contacts. 1057bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1058bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private static final int LEGACY_IMPORT_FAILED_NOTIFICATION = 1; 105951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 106003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_START_MATCH = "["; 106103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_END_MATCH = "]"; 106203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_ELLIPSIS = "..."; 106303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final int DEFAULT_SNIPPET_ARG_MAX_TOKENS = -10; 106403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 10659a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhoneInitialized; 10669a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhone; 10679a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 1068f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov private StringBuilder mSb = new StringBuilder(); 10691129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs1 = new String[1]; 10701129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs2 = new String[2]; 10712526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private ArrayList<String> mSelectionArgs = Lists.newArrayList(); 10722526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1073f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private Account mAccount; 1074f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 107546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 107646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Stores mapping from type Strings exposed via {@link DataUsageFeedback} to 107746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type integers in {@link DataUsageStatColumns}. 107846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 107946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final Map<String, Integer> sDataUsageTypeMap; 108046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 10814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 10824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 1083a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 1084d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 1085d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 1086a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA); 1087a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES); 10883653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", 10893653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 10902d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", 10912d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov AGGREGATION_SUGGESTIONS); 1092a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO); 1093f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", 1094f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_ID_DISPLAY_PHOTO); 10953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", 10963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_ID_STREAM_ITEMS); 1097c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER); 10985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER); 10995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP); 11002149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA); 1101bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/photo", 1102bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro CONTACTS_LOOKUP_PHOTO); 11035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID); 11042149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", 11052149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov CONTACTS_LOOKUP_ID_DATA); 1106bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/photo", 1107bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro CONTACTS_LOOKUP_ID_PHOTO); 1108f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", 1109f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_DISPLAY_PHOTO); 1110f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo", 1111f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_ID_DISPLAY_PHOTO); 1112a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities", 1113a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ENTITIES); 1114a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities", 1115a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ID_ENTITIES); 11163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items", 11173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_STREAM_ITEMS); 11183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items", 11193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_ID_STREAM_ITEMS); 1120f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD); 112142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*", 112242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann CONTACTS_AS_MULTI_VCARD); 11235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT); 1124ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*", 1125ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov CONTACTS_STREQUENT_FILTER); 11265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP); 112745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "contacts/frequent", CONTACTS_FREQUENT); 11283653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 11295ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); 11305ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); 11315ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA); 1132f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/display_photo", 1133f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro RAW_CONTACTS_ID_DISPLAY_PHOTO); 113446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ENTITY_ID); 11353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items", 11363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RAW_CONTACTS_ID_STREAM_ITEMS); 113782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items/#", 113882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro RAW_CONTACTS_ID_STREAM_ITEMS_ID); 113946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 114046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES); 1141b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 11424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 11434f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 1144ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 114548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID); 11465e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER); 1147ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 11484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS); 114948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID); 11501dac83b8fa58944acfd00f44e717a7dddc659d2dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP); 11515e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP); 11525e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER); 11534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER); 1154ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 115548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID); 115646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** "*" is in CSV form with data ids ("123,456,789") */ 115746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/usagefeedback/*", DATA_USAGE_FEEDBACK_ID); 11581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1159ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 1160ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 1161ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 1162ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 116335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 1164b5a4add17815167d20a90645779df34cdf45280dFred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#", 1165b5a4add17815167d20a90645779df34cdf45280dFred Quintana SYNCSTATE_ID); 11665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/" + SyncStateContentProviderHelper.PATH, 11675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_SYNCSTATE); 11685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, 11695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "profile/" + SyncStateContentProviderHelper.PATH + "/#", 11705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_SYNCSTATE_ID); 117135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1172a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 1173b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 1174b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 1175b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 1176b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 11774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1178eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS); 1179eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 118082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES); 118182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID); 11821f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1183c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, 1184c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 1185c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 1186c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 11872d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 1188c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SHORTCUT); 1189c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 11901b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts", 11911b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS); 11921b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*", 11931b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_GROUP_NAME); 11941b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones", 11951b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_WITH_PHONES); 11961b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites", 11971b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_FAVORITES); 119809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 119909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS); 1200d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1201d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES); 1202d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID); 12037a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 12047a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME); 120524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 120624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile", PROFILE); 120724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/entities", PROFILE_ENTITIES); 120824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data", PROFILE_DATA); 120924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data/#", PROFILE_DATA_ID); 121085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/photo", PROFILE_PHOTO); 121185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/display_photo", PROFILE_DISPLAY_PHOTO); 121224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/as_vcard", PROFILE_AS_VCARD); 121324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts", PROFILE_RAW_CONTACTS); 121424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#", 121524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID); 121624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/data", 121724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_DATA); 121824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/entity", 121924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_ENTITIES); 12205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/status_updates", 12215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_STATUS_UPDATES); 12223202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contact_entities", 12233202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro PROFILE_RAW_CONTACT_ENTITIES); 122446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 12253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items", STREAM_ITEMS); 12263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/photo", STREAM_ITEMS_PHOTOS); 12273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#", STREAM_ITEMS_ID); 12283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo", STREAM_ITEMS_ID_PHOTOS); 12293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo/#", 12303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann STREAM_ITEMS_ID_PHOTOS_ID); 12313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items_limit", STREAM_ITEMS_LIMIT); 12323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 12335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "display_photo/#", DISPLAY_PHOTO); 1234f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS); 1235f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 123646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa HashMap<String, Integer> tmpTypeMap = new HashMap<String, Integer>(); 123746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_CALL, DataUsageStatColumns.USAGE_TYPE_INT_CALL); 123846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, 123946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT); 124046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, 124146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT); 124246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sDataUsageTypeMap = Collections.unmodifiableMap(tmpTypeMap); 124319a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov } 124419a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov 1245d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static class DirectoryInfo { 1246d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String authority; 1247d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountName; 1248d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountType; 1249d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 1250d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1251d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 1252d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Cached information about contact directories. 1253d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 12544458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private HashMap<String, DirectoryInfo> mDirectoryCache = new HashMap<String, DirectoryInfo>(); 12554458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private boolean mDirectoryCacheValid = false; 1256d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 12573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 125843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * An entry in group id cache. It maps the combination of (account type, account name, data set, 1259ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov * and source id) to group row id. 1260ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov */ 1261e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov public static class GroupIdCacheEntry { 1262ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType; 1263ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName; 126443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet; 1265ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String sourceId; 1266ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov long groupId; 1267ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov } 1268a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov 1269e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // We don't need a soft cache for groups - the assumption is that there will only 1270e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // be a small number of contact groups. The cache is keyed off source id. The value 1271e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // is a list of groups with this group id. 1272e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap(); 1273e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov 127424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 1275f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of display photos. Larger images will be scaled 1276f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to fit. 1277f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1278f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxDisplayPhotoDim; 1279f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1280f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1281f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of photo thumbnails. 1282f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1283f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxThumbnailPhotoDim; 1284f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 12865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Sub-provider for handling profile requests against the profile database. 12875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 12885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ProfileProvider mProfileProvider; 1289f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12904097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 1291f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private NameLookupBuilder mNameLookupBuilder; 1292315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov 1293622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private PostalSplitter mPostalSplitter; 1294622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey 129572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov private ContactDirectoryManager mContactDirectoryManager; 12965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1297078f588cef389358adabc579de00747878f3c108Dave Santoro // The database tag to use for representing the contacts DB in contacts transactions. 1298078f588cef389358adabc579de00747878f3c108Dave Santoro /* package */ static final String CONTACTS_DB_TAG = "contacts"; 1299078f588cef389358adabc579de00747878f3c108Dave Santoro 1300078f588cef389358adabc579de00747878f3c108Dave Santoro // The database tag to use for representing the profile DB in contacts transactions. 1301078f588cef389358adabc579de00747878f3c108Dave Santoro /* package */ static final String PROFILE_DB_TAG = "profile"; 1302078f588cef389358adabc579de00747878f3c108Dave Santoro 13035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 13045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * The active (thread-local) database. This will be switched between a contacts-specific 13055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database and a profile-specific database, depending on what the current operation is 13065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * targeted to. 13075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 13085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<SQLiteDatabase> mActiveDb = new ThreadLocal<SQLiteDatabase>(); 13095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13106efb7db26598b105342d02207e0ca1c8725c10daDave Santoro /** 13116efb7db26598b105342d02207e0ca1c8725c10daDave Santoro * The thread-local holder of the active transaction. Shared between this and the profile 13126efb7db26598b105342d02207e0ca1c8725c10daDave Santoro * provider, to keep transactions on both databases synchronized. 13136efb7db26598b105342d02207e0ca1c8725c10daDave Santoro */ 13146efb7db26598b105342d02207e0ca1c8725c10daDave Santoro private final ThreadLocal<ContactsTransaction> mTransactionHolder = 13156efb7db26598b105342d02207e0ca1c8725c10daDave Santoro new ThreadLocal<ContactsTransaction>(); 13166efb7db26598b105342d02207e0ca1c8725c10daDave Santoro 13175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // This variable keeps track of whether the current operation is intended for the profile DB. 13185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<Boolean> mInProfileMode = new ThreadLocal<Boolean>(); 13195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Separate data row handler instances for contact data and profile data. 13215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private HashMap<String, DataRowHandler> mDataRowHandlers; 13225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private HashMap<String, DataRowHandler> mProfileDataRowHandlers; 13235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile, we will use one of two 13255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // database helper instances. 13265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<ContactsDatabaseHelper> mDbHelper = 13275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ThreadLocal<ContactsDatabaseHelper>(); 13285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ContactsDatabaseHelper mContactsHelper; 13295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ProfileDatabaseHelper mProfileHelper; 13305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile or not, we will use one of 13325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // two aggregator instances. 13335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<ContactAggregator> mAggregator = new ThreadLocal<ContactAggregator>(); 1334622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private ContactAggregator mContactAggregator; 13355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ContactAggregator mProfileAggregator; 13365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile or not, we will use one of 13385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // two photo store instances (with their files stored in separate subdirectories). 13395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<PhotoStore> mPhotoStore = new ThreadLocal<PhotoStore>(); 13405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private PhotoStore mContactsPhotoStore; 13415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private PhotoStore mProfilePhotoStore; 13425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // The active transaction context will switch depending on the operation being performed. 13445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Both transaction contexts will be cleared out when a batch transaction is started, and 13455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // each will be processed separately when a batch transaction completes. 13465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private TransactionContext mContactTransactionContext = new TransactionContext(false); 13475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private TransactionContext mProfileTransactionContext = new TransactionContext(true); 13485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<TransactionContext> mTransactionContext = 13495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ThreadLocal<TransactionContext>(); 13505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 135182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Duration in milliseconds that pre-authorized URIs will remain valid. 135282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private long mPreAuthorizedUriDuration; 135382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 135482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Map of single-use pre-authorized URIs to expiration times. 135582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private Map<Uri, Long> mPreAuthorizedUris = Maps.newHashMap(); 135682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 135782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Random number generator seeded with the current time. 135882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private Random mRandom = new Random(System.currentTimeMillis()); 135982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 1360f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 1361a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private GlobalSearchSupport mGlobalSearchSupport; 1362d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov private CommonNicknameCache mCommonNicknameCache; 1363f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov private SearchIndexManager mSearchIndexManager; 1364a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 136520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private ContentValues mValues = new ContentValues(); 136673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov private HashMap<String, Boolean> mAccountWritability = Maps.newHashMap(); 136720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 136809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private int mProviderStatus = ProviderStatus.STATUS_NORMAL; 13693826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private boolean mProviderStatusUpdateNeeded; 137009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private long mEstimatedStorageRequirement = 0; 137115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mReadAccessLatch; 137215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mWriteAccessLatch; 137315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private boolean mAccountUpdateListenerRegistered; 1374bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private boolean mOkToOpenAccess = true; 137573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 13761a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey private boolean mVisibleTouched = false; 13771a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 137881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov private boolean mSyncToNetwork; 137981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 13804cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao private Locale mCurrentLocale; 13813826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private int mContactsAccountCount; 1382d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov 1383bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private HandlerThread mBackgroundThread; 1384bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private Handler mBackgroundHandler; 1385bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1386f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mLastPhotoCleanup = 0; 1387f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 13884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 13894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 1390663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) { 1391663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki Log.d(Constants.PERFORMANCE_TAG, "ContactsProvider2.onCreate start"); 1392663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } 1393de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov super.onCreate(); 1394ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov try { 1395ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return initialize(); 1396ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } catch (RuntimeException e) { 1397ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov Log.e(TAG, "Cannot start provider", e); 1398ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return false; 1399663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } finally { 1400663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) { 1401663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki Log.d(Constants.PERFORMANCE_TAG, "ContactsProvider2.onCreate finish"); 1402663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } 1403ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 1404ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 140535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1406ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov private boolean initialize() { 140715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov StrictMode.setThreadPolicy( 140815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 140915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 14103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Resources resources = getContext().getResources(); 1411f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxDisplayPhotoDim = resources.getInteger( 1412f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_display_photo_dim); 1413f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim = resources.getInteger( 1414f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_thumbnail_photo_dim); 14153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 1416078f588cef389358adabc579de00747878f3c108Dave Santoro mContactsHelper = getDatabaseHelper(getContext()); 14175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mContactsHelper); 1418078f588cef389358adabc579de00747878f3c108Dave Santoro 1419078f588cef389358adabc579de00747878f3c108Dave Santoro // Set up the DB helper for keeping transactions serialized. 1420078f588cef389358adabc579de00747878f3c108Dave Santoro setDbHelperToSerializeOn(mContactsHelper, CONTACTS_DB_TAG); 1421078f588cef389358adabc579de00747878f3c108Dave Santoro 142272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov mContactDirectoryManager = new ContactDirectoryManager(this); 1423a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov mGlobalSearchSupport = new GlobalSearchSupport(this); 142465ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov 1425bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // The provider is closed for business until fully initialized 142615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = new CountDownLatch(1); 142715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = new CountDownLatch(1); 142872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1429bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread = new HandlerThread("ContactsProviderWorker", 1430bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov Process.THREAD_PRIORITY_BACKGROUND); 1431bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread.start(); 1432bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler = new Handler(mBackgroundThread.getLooper()) { 1433bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov @Override 1434bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov public void handleMessage(Message msg) { 1435bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov performBackgroundTask(msg.what, msg.obj); 1436bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1437bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov }; 14382a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov 14395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Set up the sub-provider for handling profiles. 14405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileProvider = getProfileProvider(); 1441c990980ab4beb7b81c3337526f1bdcd5d1a14730Dave Santoro mProfileProvider.setDbHelperToSerializeOn(mContactsHelper, CONTACTS_DB_TAG); 14425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ProviderInfo profileInfo = new ProviderInfo(); 14435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileInfo.readPermission = "android.permission.READ_PROFILE"; 14445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileInfo.writePermission = "android.permission.WRITE_PROFILE"; 14455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileProvider.attachInfo(getContext(), profileInfo); 1446078f588cef389358adabc579de00747878f3c108Dave Santoro mProfileHelper = mProfileProvider.getDatabaseHelper(getContext()); 14475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 144882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Initialize the pre-authorized URI duration. 144982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mPreAuthorizedUriDuration = android.provider.Settings.Secure.getLong( 145082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro getContext().getContentResolver(), 145182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro android.provider.Settings.Secure.CONTACTS_PREAUTH_URI_EXPIRATION, 145282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro DEFAULT_PREAUTHORIZED_URI_EXPIRATION); 145382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 145415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_INITIALIZE); 1455bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1456bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 1457bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_LOCALE); 1458bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM); 145905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_SEARCH_INDEX); 1460bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_PROVIDER_STATUS); 146115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_OPEN_WRITE_ACCESS); 1462f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 14633826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 146449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov return true; 14654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 14664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1467767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov /** 146851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * (Re)allocates all locale-sensitive structures. 146951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 147004b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov private void initForDefaultLocale() { 147115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 14725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mLegacyApiSupport = new LegacyApiSupport(context, mContactsHelper, this, 14735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mGlobalSearchSupport); 14744cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mCurrentLocale = getLocale(); 14755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mNameSplitter = mContactsHelper.createNameSplitter(); 14764cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter); 14774cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mPostalSplitter = new PostalSplitter(mCurrentLocale); 14785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mCommonNicknameCache = new CommonNicknameCache(mContactsHelper.getReadableDatabase()); 1479cdd03b2ba03718a7fa85663a2438136284a1557cBai Tao ContactLocaleUtils.getIntance().setLocale(mCurrentLocale); 14805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator = new ContactAggregator(this, mContactsHelper, 148115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 14825b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 14835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator = new ProfileAggregator(this, mProfileHelper, 14845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 14855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 1486f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov mSearchIndexManager = new SearchIndexManager(this); 14875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 14885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore = new PhotoStore(getContext().getFilesDir(), mContactsHelper); 14895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore = new PhotoStore(new File(getContext().getFilesDir(), "profile"), 14905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper); 14915b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 1492bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers = new HashMap<String, DataRowHandler>(); 14935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro initDataRowHandlers(mDataRowHandlers, mContactsHelper, mContactAggregator, 14945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore); 14955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDataRowHandlers = new HashMap<String, DataRowHandler>(); 14965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro initDataRowHandlers(mProfileDataRowHandlers, mProfileHelper, mProfileAggregator, 14975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore); 14985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 14995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Set initial thread-local state variables for the Contacts DB. 15005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 15015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 1502bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 15035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private void initDataRowHandlers(Map<String, DataRowHandler> handlerMap, 15045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ContactsDatabaseHelper dbHelper, ContactAggregator contactAggregator, 15055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore photoStore) { 15065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Context context = getContext(); 15075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Email.CONTENT_ITEM_TYPE, 15085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForEmail(context, dbHelper, contactAggregator)); 15095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Im.CONTENT_ITEM_TYPE, 15105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForIm(context, dbHelper, contactAggregator)); 15115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Organization.CONTENT_ITEM_TYPE, 15125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForOrganization(context, dbHelper, contactAggregator)); 15135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Phone.CONTENT_ITEM_TYPE, 15145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForPhoneNumber(context, dbHelper, contactAggregator)); 15155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Nickname.CONTENT_ITEM_TYPE, 15165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForNickname(context, dbHelper, contactAggregator)); 15175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(StructuredName.CONTENT_ITEM_TYPE, 15185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForStructuredName(context, dbHelper, contactAggregator, 1519bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mNameSplitter, mNameLookupBuilder)); 15205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(StructuredPostal.CONTENT_ITEM_TYPE, 15215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForStructuredPostal(context, dbHelper, contactAggregator, 1522bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mPostalSplitter)); 15235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(GroupMembership.CONTENT_ITEM_TYPE, 15245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForGroupMembership(context, dbHelper, contactAggregator, 1525bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mGroupIdCache)); 15265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Photo.CONTENT_ITEM_TYPE, 15275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForPhoto(context, dbHelper, contactAggregator, photoStore)); 15285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Note.CONTENT_ITEM_TYPE, 15295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForNote(context, dbHelper, contactAggregator)); 1530bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1531bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1532bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /** 1533bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Visible for testing. 1534bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov */ 1535bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /* package */ PhotoPriorityResolver createPhotoPriorityResolver(Context context) { 1536bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov return new PhotoPriorityResolver(context); 1537bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1538bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1539bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task) { 1540bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendEmptyMessage(task); 1541bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1542bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1543bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task, Object arg) { 1544bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(task, arg)); 1545bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1546bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1547bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void performBackgroundTask(int task, Object arg) { 1548bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov switch (task) { 154915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_INITIALIZE: { 155015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov initForDefaultLocale(); 155115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch.countDown(); 155215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = null; 155315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov break; 155415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 155515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 155615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_OPEN_WRITE_ACCESS: { 1557bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (mOkToOpenAccess) { 155815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch.countDown(); 155915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = null; 1560bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1561bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1562bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1563bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1564bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS: { 1565bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isLegacyContactImportNeeded()) { 1566bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov importLegacyContactsInBackground(); 1567bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1568bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1569bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1570bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1571bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_ACCOUNTS: { 157215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 157315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (!mAccountUpdateListenerRegistered) { 157415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov AccountManager.get(context).addOnAccountsUpdatedListener(this, null, false); 157515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mAccountUpdateListenerRegistered = true; 157615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 157715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 15785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Update the accounts for both the contacts and profile DBs. 157915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Account[] accounts = AccountManager.get(context).getAccounts(); 15805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 1581bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov boolean accountsChanged = updateAccountsInBackground(accounts); 15825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 15835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro accountsChanged |= updateAccountsInBackground(accounts); 15845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1585bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateContactsAccountCount(accounts); 1586bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateDirectoriesInBackground(accountsChanged); 1587bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1588bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1589bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1590bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_LOCALE: { 1591bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateLocaleInBackground(); 1592bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1593bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1594bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1595fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov case BACKGROUND_TASK_CHANGE_LOCALE: { 1596fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov changeLocaleInBackground(); 1597fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov break; 1598fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1599fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1600bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM: { 1601bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isAggregationUpgradeNeeded()) { 1602bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov upgradeAggregationAlgorithmInBackground(); 1603bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1604bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1605bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1606bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 160705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_SEARCH_INDEX: { 160805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov updateSearchIndexInBackground(); 160905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov break; 161005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 161105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1612bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_PROVIDER_STATUS: { 1613bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateProviderStatus(); 1614bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1615bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1616bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1617bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_DIRECTORIES: { 1618bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (arg != null) { 1619bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.onPackageChanged((String) arg); 1620bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1621bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1622bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1623f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1624f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case BACKGROUND_TASK_CLEANUP_PHOTOS: { 1625f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check rate limit. 1626f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long now = System.currentTimeMillis(); 1627f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (now - mLastPhotoCleanup > PHOTO_CLEANUP_RATE_LIMIT) { 1628f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mLastPhotoCleanup = now; 16295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 16305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Clean up photo stores for both contacts and profiles. 16315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 16325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro cleanupPhotoStore(); 16335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 1634f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupPhotoStore(); 1635f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro break; 1636f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1637f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1638bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 16394cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 16404cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao 164153fac8f99f3884c372c907a76766d27fa9e1d95fDmitri Plotnikov public void onLocaleChanged() { 16423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 16433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 16444f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov return; 16454f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov } 16464f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov 1647fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_CHANGE_LOCALE); 16484cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 164951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 165051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov /** 165151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * Verifies that the contacts database is properly configured for the current locale. 165251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * If not, changes the database locale to the current locale using an asynchronous task. 165351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * This needs to be done asynchronously because the process involves rebuilding 165451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * large data structures (name lookup, sort keys), which can take minutes on 165551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * a large set of contacts. 165651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 1657bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateLocaleInBackground() { 1658f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 1659f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov // The process is already running - postpone the change 1660f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov if (mProviderStatus == ProviderStatus.STATUS_CHANGING_LOCALE) { 1661f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov return; 1662f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov } 1663f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 166451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 166551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final String providerLocale = prefs.getString(PREF_LOCALE, null); 166651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final Locale currentLocale = mCurrentLocale; 166751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov if (currentLocale.toString().equals(providerLocale)) { 166851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov return; 166951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 167051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 167151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov int providerStatus = mProviderStatus; 167251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_CHANGING_LOCALE); 16735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.setLocale(this, currentLocale); 16745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper.setLocale(this, currentLocale); 1675bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).apply(); 1676bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov setProviderStatus(providerStatus); 1677bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 167851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 1679fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov /** 1680fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov * Reinitializes the provider for a new locale. 1681fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov */ 1682fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov private void changeLocaleInBackground() { 1683fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Re-initializing the provider without stopping it. 1684fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Locking the database will prevent inserts/updates/deletes from 1685fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // running at the same time, but queries may still be running 1686fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // on other threads. Those queries may return inconsistent results. 16875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mContactsHelper.getWritableDatabase(); 16885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase profileDb = mProfileHelper.getWritableDatabase(); 1689fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.beginTransaction(); 16905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.beginTransaction(); 1691fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov try { 1692fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov initForDefaultLocale(); 1693fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.setTransactionSuccessful(); 16945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.setTransactionSuccessful(); 1695fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } finally { 1696fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.endTransaction(); 16975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.endTransaction(); 1698fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1699fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1700fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov updateLocaleInBackground(); 1701fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1702fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 170305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov protected void updateSearchIndexInBackground() { 170405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov mSearchIndexManager.updateIndex(); 170505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 170605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1707bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateDirectoriesInBackground(boolean rescan) { 1708bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanAllPackages(rescan); 170951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 171051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 17113826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateProviderStatus() { 17123826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 17133826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 17143826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return; 17153826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 17163826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 17173e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson // No accounts/no contacts status is true if there are no account and 17185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // there are no contacts or one profile contact 17193e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson if (mContactsAccountCount == 0) { 17205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactsNum = DatabaseUtils.queryNumEntries(mContactsHelper.getReadableDatabase(), 17213e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson Tables.CONTACTS, null); 17225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long profileNum = DatabaseUtils.queryNumEntries(mProfileHelper.getReadableDatabase(), 17235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Tables.CONTACTS, null); 17245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 17255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // TODO: Different status if there is a profile but no contacts? 17265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (contactsNum == 0 && profileNum <= 1) { 17273e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson setProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 17283e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson } else { 17293e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson setProviderStatus(ProviderStatus.STATUS_NORMAL); 17303e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson } 17313826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } else { 17323826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 17333826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 17343826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 17353826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 173631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* Visible for testing */ 1737f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro protected void cleanupPhotoStore() { 17385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 1739d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro mActiveDb.set(db); 17406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 17416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Assemble the set of photo store file IDs that are in use, and send those to the photo 1742f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // store. Any photos that aren't in that set will be deleted, and any photos that no 1743f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // longer exist in the photo store will be returned for us to clear out in the DB. 17447cf50494501938f175d288077145acf49da8f171Daniel Lehmann long photoMimeTypeId = mDbHelper.get().getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 17456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = db.query(Views.DATA, new String[]{Data._ID, Photo.PHOTO_FILE_ID}, 17467cf50494501938f175d288077145acf49da8f171Daniel Lehmann DataColumns.MIMETYPE_ID + "=" + photoMimeTypeId + " AND " 1747f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro + Photo.PHOTO_FILE_ID + " IS NOT NULL", null, null, null, null); 17486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> usedPhotoFileIds = Sets.newHashSet(); 17496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToDataId = Maps.newHashMap(); 1750f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1751f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro while (c.moveToNext()) { 17526802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = c.getLong(0); 17536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(1); 17546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 17556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToDataId.put(photoFileId, dataId); 17566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 17576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 17586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 17596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 17606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 17616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Also query for all social stream item photos. 1762c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro c = db.query(Tables.STREAM_ITEM_PHOTOS + " JOIN " + Tables.STREAM_ITEMS 1763c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro + " ON " + StreamItemPhotos.STREAM_ITEM_ID + "=" + StreamItemsColumns.CONCRETE_ID 1764c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro + " JOIN " + Tables.RAW_CONTACTS 1765c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro + " ON " + StreamItems.RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID, 17666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{ 1767c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro StreamItemPhotosColumns.CONCRETE_ID, 1768c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID, 1769c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro StreamItemPhotos.PHOTO_FILE_ID, 1770c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro RawContacts.ACCOUNT_TYPE, 1771c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro RawContacts.ACCOUNT_NAME 17726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro }, 17736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro null, null, null, null, null); 17746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToStreamItemPhotoId = Maps.newHashMap(); 17756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> streamItemPhotoIdToStreamItemId = Maps.newHashMap(); 1776c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro Map<Long, Account> streamItemPhotoIdToAccount = Maps.newHashMap(); 17776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 17786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro while (c.moveToNext()) { 17796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = c.getLong(0); 17806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = c.getLong(1); 17816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(2); 1782c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro String accountType = c.getString(3); 1783c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro String accountName = c.getString(4); 17846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 17856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToStreamItemPhotoId.put(photoFileId, streamItemPhotoId); 17866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemPhotoIdToStreamItemId.put(streamItemPhotoId, streamItemId); 1787c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro Account account = new Account(accountName, accountType); 1788c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro streamItemPhotoIdToAccount.put(photoFileId, account); 1789f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1790f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 1791f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 1792f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1793f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1794f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Run the photo store cleanup. 17955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> missingPhotoIds = mPhotoStore.get().cleanup(usedPhotoFileIds); 1796f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1797d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // If any of the keys we're using no longer exist, clean them up. We need to do these 1798d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // using internal APIs or direct DB access to avoid permission errors. 17996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!missingPhotoIds.isEmpty()) { 1800f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1801d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.beginTransactionWithListener(this); 1802d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro for (long missingPhotoId : missingPhotoIds) { 1803d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro if (photoFileIdToDataId.containsKey(missingPhotoId)) { 1804d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro long dataId = photoFileIdToDataId.get(missingPhotoId); 1805d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro ContentValues updateValues = new ContentValues(); 1806d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro updateValues.putNull(Photo.PHOTO_FILE_ID); 1807d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro updateData(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), 1808d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro updateValues, null, null, false); 1809d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1810d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro if (photoFileIdToStreamItemPhotoId.containsKey(missingPhotoId)) { 1811d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // For missing photos that were in stream item photos, just delete the 1812d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // stream item photo. 1813d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro long streamItemPhotoId = photoFileIdToStreamItemPhotoId.get(missingPhotoId); 1814d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.delete(Tables.STREAM_ITEM_PHOTOS, StreamItemPhotos._ID + "=?", 1815d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro new String[]{String.valueOf(streamItemPhotoId)}); 1816d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1817d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1818d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.setTransactionSuccessful(); 1819d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } catch (Exception e) { 1820d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // Cleanup failure is not a fatal problem. We'll try again later. 1821d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro Log.e(TAG, "Failed to clean up outdated photo references", e); 1822d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } finally { 1823d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.endTransaction(); 1824f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1825f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1826f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1827f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 18286efb7db26598b105342d02207e0ca1c8725c10daDave Santoro @Override 1829b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 1830b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return ContactsDatabaseHelper.getInstance(context); 183131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 183231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 18336efb7db26598b105342d02207e0ca1c8725c10daDave Santoro @Override 18346efb7db26598b105342d02207e0ca1c8725c10daDave Santoro protected ThreadLocal<ContactsTransaction> getTransactionHolder() { 18356efb7db26598b105342d02207e0ca1c8725c10daDave Santoro return mTransactionHolder; 18366efb7db26598b105342d02207e0ca1c8725c10daDave Santoro } 18376efb7db26598b105342d02207e0ca1c8725c10daDave Santoro 18385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public ProfileProvider getProfileProvider() { 18395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return new ProfileProvider(this); 18405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 18415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1842524913c66ce75ca8dec127ac88e3bc2249c246d9Dave Santoro @VisibleForTesting 1843f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* package */ PhotoStore getPhotoStore() { 18445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mContactsPhotoStore; 1845f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1846f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1847d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro @VisibleForTesting 1848d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro /* package */ PhotoStore getProfilePhotoStore() { 1849d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro return mProfilePhotoStore; 1850d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1851d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro 185287614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxDisplayPhotoDim() { 185387614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxDisplayPhotoDim; 185487614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 185587614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 185687614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxThumbnailPhotoDim() { 185787614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxThumbnailPhotoDim; 185887614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 185987614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1860013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov /* package */ NameSplitter getNameSplitter() { 1861013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov return mNameSplitter; 1862013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov } 1863013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov 18645df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov /* package */ NameLookupBuilder getNameLookupBuilder() { 18655df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov return mNameLookupBuilder; 18665df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov } 18675df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov 18685dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov /* Visible for testing */ 1869ed78fd6df5e9f3a2d572162e5d374d1f4a625bddDmitri Plotnikov public ContactDirectoryManager getContactDirectoryManagerForTest() { 187072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov return mContactDirectoryManager; 187172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 187272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 187372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov /* Visible for testing */ 18745dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov protected Locale getLocale() { 18755dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov return Locale.getDefault(); 18765dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov } 18775dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 18785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean inProfileMode() { 18795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Boolean profileMode = mInProfileMode.get(); 18805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return profileMode != null && profileMode; 18815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 18825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 18833d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov protected boolean isLegacyContactImportNeeded() { 18845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int version = Integer.parseInt( 18855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.getProperty(PROPERTY_CONTACTS_IMPORTED, "0")); 1886b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov return version < PROPERTY_CONTACTS_IMPORT_VERSION; 18873d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 18883d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1889568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov protected LegacyContactImporter getLegacyContactImporter() { 1890568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return new LegacyContactImporter(getContext(), this); 1891568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1892568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1893568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 1894bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Imports legacy contacts as a background task. 1895568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 1896bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private void importLegacyContactsInBackground() { 1897bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Importing legacy contacts"); 1898bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADING); 1899568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1900bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 19015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.setLocale(this, mCurrentLocale); 1902bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, mCurrentLocale.toString()).commit(); 1903568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1904bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov LegacyContactImporter importer = getLegacyContactImporter(); 1905bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (importLegacyContacts(importer)) { 1906bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportSuccess(); 1907bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } else { 1908bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportFailure(); 1909bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1910568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1911568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1912bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1913bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Unlocks the provider and declares that the import process is complete. 1914bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1915bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportSuccess() { 1916bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1917bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)getContext().getSystemService(Context.NOTIFICATION_SERVICE); 1918bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.cancel(LEGACY_IMPORT_FAILED_NOTIFICATION); 1919bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1920b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov // Store a property in the database indicating that the conversion process succeeded 19215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.setProperty(PROPERTY_CONTACTS_IMPORTED, 1922b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov String.valueOf(PROPERTY_CONTACTS_IMPORT_VERSION)); 1923bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 1924bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Completed import of legacy contacts"); 1925bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1926bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1927bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1928bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Announces the provider status and keeps the provider locked. 1929bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1930bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportFailure() { 1931bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Context context = getContext(); 1932bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1933bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); 1934bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1935bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // Show a notification 1936bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Notification n = new Notification(android.R.drawable.stat_notify_error, 1937bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_ticker), 1938bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov System.currentTimeMillis()); 1939bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.setLatestEventInfo(context, 1940bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_title), 1941bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_text), 1942bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov PendingIntent.getActivity(context, 0, new Intent(Intents.UI.LIST_DEFAULT), 0)); 1943bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; 1944bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1945bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.notify(LEGACY_IMPORT_FAILED_NOTIFICATION, n); 1946bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1947bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADE_OUT_OF_MEMORY); 1948bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Failed to import legacy contacts"); 1949bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1950bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // Do not let any database changes until this issue is resolved. 1951bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mOkToOpenAccess = false; 19523d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 19533d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 19543d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /* Visible for testing */ 1955568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /* package */ boolean importLegacyContacts(LegacyContactImporter importer) { 19560e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff boolean aggregatorEnabled = mContactAggregator.isEnabled(); 19573d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov mContactAggregator.setEnabled(false); 19583d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov try { 1959bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (importer.importContacts()) { 1960bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1961bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // TODO aggregate all newly added raw contacts 1962bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mContactAggregator.setEnabled(aggregatorEnabled); 1963bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return true; 1964bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 19653d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } catch (Throwable e) { 19663d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov Log.e(TAG, "Legacy contact import failed", e); 19673d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 1968bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mEstimatedStorageRequirement = importer.getEstimatedStorageRequirement(); 1969bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return false; 19703d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 19713d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1972a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 1973a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 1974a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 1975a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /* package */ void wipeData() { 19765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.wipeData(); 19775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper.wipeData(); 19785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore.clear(); 19795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore.clear(); 19803826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS; 1981a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 1982a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1983568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 198415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov * During intialization, this content provider will 1985568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * block all attempts to change contacts data. In particular, it will hold 1986568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * up all contact syncs. As soon as the import process is complete, all 1987568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * processes waiting to write to the provider are unblocked and can proceed 1988568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * to compete for the database transaction monitor. 1989568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 199015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private void waitForAccess(CountDownLatch latch) { 199115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (latch == null) { 199215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 199315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 199415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 199515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov while (true) { 199615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov try { 199715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov latch.await(); 199815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 199915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } catch (InterruptedException e) { 200015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Thread.currentThread().interrupt(); 2001ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov } 2002568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2003568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2004568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 20055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 20065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Determines whether the given URI should be directed to the profile 20075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database rather than the contacts database. This is true under either 20085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * of three conditions: 20095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 1. The URI itself is specifically for the profile. 20105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 2. The URI contains ID references that are in the profile ID-space. 20115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 3. The URI contains lookup key references that match the special profile lookup key. 20125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param uri The URI to examine. 20135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @return Whether to direct the DB operation to the profile database. 20145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 20155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean mapsToProfileDb(Uri uri) { 20165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return sUriMatcher.mapsToProfile(uri); 20175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 20195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 20205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Determines whether the given URI with the given values being inserted 20215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * should be directed to the profile database rather than the contacts 20225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database. This is true if the URI already maps to the profile DB from 20235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a call to {@link #mapsToProfileDb} or if the URI matches a URI that 20245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * specifies parent IDs via the ContentValues, and the given ContentValues 20255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * contains an ID in the profile ID-space. 20265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param uri The URI to examine. 20275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param values The values being inserted. 20285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @return Whether to direct the DB insert to the profile database. 20295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 20305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean mapsToProfileDbWithInsertedValues(Uri uri, ContentValues values) { 20315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 20325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return true; 20335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int match = sUriMatcher.match(uri); 20355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (INSERT_URI_ID_VALUE_MAP.containsKey(match)) { 20365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String idField = INSERT_URI_ID_VALUE_MAP.get(match); 20375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (values.containsKey(idField)) { 20385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long id = values.getAsLong(idField); 20395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (ContactsContract.isProfileId(id)) { 20405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return true; 20415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return false; 20455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 20475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 20485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Switches the provider's thread-local context variables to prepare for performing 20495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a profile operation. 20505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 20516efb7db26598b105342d02207e0ca1c8725c10daDave Santoro protected void switchToProfileMode() { 20525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mProfileHelper); 20535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.set(mProfileTransactionContext); 20545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.set(mProfileAggregator); 20555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mPhotoStore.set(mProfilePhotoStore); 20565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mInProfileMode.set(true); 20575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 20595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 20605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Switches the provider's thread-local context variables to prepare for performing 20615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a contacts operation. 20625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 20636efb7db26598b105342d02207e0ca1c8725c10daDave Santoro protected void switchToContactMode() { 20645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mContactsHelper); 20655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.set(mContactTransactionContext); 20665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.set(mContactAggregator); 20675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mPhotoStore.set(mContactsPhotoStore); 20685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mInProfileMode.set(false); 20695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 207036aa19fbab3722288b7f0917166ef6990ab7b52cDave Santoro // Clear out the active database; modification operations will set this to the contacts DB. 207136aa19fbab3722288b7f0917166ef6990ab7b52cDave Santoro mActiveDb.set(null); 20725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 2074568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 2075568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public Uri insert(Uri uri, ContentValues values) { 207615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 207736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 207836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 207936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamWritePermission(uri); 208036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 20815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDbWithInsertedValues(uri, values)) { 2082078f588cef389358adabc579de00747878f3c108Dave Santoro switchToProfileMode(); 2083078f588cef389358adabc579de00747878f3c108Dave Santoro return mProfileProvider.insert(uri, values); 20845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 20855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 20865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.insert(uri, values); 20875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 2088568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2089568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 2090568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 2091568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 209215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (mWriteAccessLatch != null) { 2093bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // We are stuck trying to upgrade contacts db. The only update request 2094bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // allowed in this case is an update of provider status, which will trigger 2095bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // an attempt to upgrade contacts again. 2096bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov int match = sUriMatcher.match(uri); 2097bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (match == PROVIDER_STATUS) { 2098bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Integer newStatus = values.getAsInteger(ProviderStatus.STATUS); 2099bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (newStatus != null && newStatus == ProviderStatus.STATUS_UPGRADING) { 2100bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 2101bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 1; 2102bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } else { 2103bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 0; 2104bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 2105bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 2106bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 210715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 210836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 210936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 211036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamWritePermission(uri); 211136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 21125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 2113078f588cef389358adabc579de00747878f3c108Dave Santoro switchToProfileMode(); 2114078f588cef389358adabc579de00747878f3c108Dave Santoro return mProfileProvider.update(uri, values, selection, selectionArgs); 21155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 21165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 21175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.update(uri, values, selection, selectionArgs); 21185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 2119568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2120568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 2121568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 2122568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int delete(Uri uri, String selection, String[] selectionArgs) { 212315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 212436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 212536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 212636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamWritePermission(uri); 212736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 21285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 2129078f588cef389358adabc579de00747878f3c108Dave Santoro switchToProfileMode(); 2130078f588cef389358adabc579de00747878f3c108Dave Santoro return mProfileProvider.delete(uri, selection, selectionArgs); 21315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 21325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 21335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.delete(uri, selection, selectionArgs); 21345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 21355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 21365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 21375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 21385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Replaces the current (thread-local) database to use for the operation with the given one. 21395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param db The database to use. 21405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 21415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /* package */ void substituteDb(SQLiteDatabase db) { 21425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(db); 2143568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2144568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 2145568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 214682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro public Bundle call(String method, String arg, Bundle extras) { 214782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro waitForAccess(mReadAccessLatch); 214882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (method.equals(Authorization.AUTHORIZATION_METHOD)) { 214982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Uri uri = (Uri) extras.getParcelable(Authorization.KEY_URI_TO_AUTHORIZE); 215082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 215182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Check permissions on the caller. The URI can only be pre-authorized if the caller 215282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // already has the necessary permissions. 215382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro enforceSocialStreamReadPermission(uri); 215482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (mapsToProfileDb(uri)) { 215582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mProfileProvider.enforceReadPermission(uri); 215682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 215782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 215882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // If there hasn't been a security violation yet, we're clear to pre-authorize the URI. 215982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Uri authUri = preAuthorizeUri(uri); 216082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Bundle response = new Bundle(); 216182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro response.putParcelable(Authorization.KEY_AUTHORIZED_URI, authUri); 216282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return response; 216382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 216482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return null; 216582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 216682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 216782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro /** 216882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Pre-authorizes the given URI, adding an expiring permission token to it and placing that 216982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * in our map of pre-authorized URIs. 217082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @param uri The URI to pre-authorize. 217182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @return A pre-authorized URI that will not require special permissions to use. 217282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 217382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private Uri preAuthorizeUri(Uri uri) { 217482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro String token = String.valueOf(mRandom.nextLong()); 217582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Uri authUri = uri.buildUpon() 217682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro .appendQueryParameter(PREAUTHORIZED_URI_TOKEN, token) 217782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro .build(); 217882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro long expiration = SystemClock.elapsedRealtime() + mPreAuthorizedUriDuration; 217982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mPreAuthorizedUris.put(authUri, expiration); 218082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 218182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return authUri; 218282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 218382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 218482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro /** 218582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Checks whether the given URI has an unexpired permission token that would grant access to 218682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * query the content. If it does, the regular permission check should be skipped. 218782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @param uri The URI being accessed. 218882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @return Whether the URI is a pre-authorized URI that is still valid. 218982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 219082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro public boolean isValidPreAuthorizedUri(Uri uri) { 219182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Only proceed if the URI has a permission token parameter. 219282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (uri.getQueryParameter(PREAUTHORIZED_URI_TOKEN) != null) { 219382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // First expire any pre-authorization URIs that are no longer valid. 219482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro long now = SystemClock.elapsedRealtime(); 219582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Set<Uri> expiredUris = Sets.newHashSet(); 219682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro for (Uri preAuthUri : mPreAuthorizedUris.keySet()) { 219782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (mPreAuthorizedUris.get(preAuthUri) < now) { 219882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro expiredUris.add(preAuthUri); 219982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 220082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 220182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro for (Uri expiredUri : expiredUris) { 220282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mPreAuthorizedUris.remove(expiredUri); 220382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 220482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 220582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Now check to see if the pre-authorized URI map contains the URI. 220682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (mPreAuthorizedUris.containsKey(uri)) { 220782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Unexpired token - skip the permission check. 220882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return true; 220982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 221082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 221182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return false; 221282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 221382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 221482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro @Override 2215078f588cef389358adabc579de00747878f3c108Dave Santoro protected boolean yield(ContactsTransaction transaction) { 2216078f588cef389358adabc579de00747878f3c108Dave Santoro // If there's a profile transaction in progress, and we're yielding, we need to 2217078f588cef389358adabc579de00747878f3c108Dave Santoro // end it. Unlike the Contacts DB yield (which re-starts a transaction at its 2218078f588cef389358adabc579de00747878f3c108Dave Santoro // conclusion), we can just go back into a state in which we have no active 2219078f588cef389358adabc579de00747878f3c108Dave Santoro // profile transaction, and let it be re-created as needed. We can't hold onto 2220078f588cef389358adabc579de00747878f3c108Dave Santoro // the transaction without risking a deadlock. 2221078f588cef389358adabc579de00747878f3c108Dave Santoro SQLiteDatabase profileDb = transaction.removeDbForTag(PROFILE_DB_TAG); 2222078f588cef389358adabc579de00747878f3c108Dave Santoro if (profileDb != null) { 2223078f588cef389358adabc579de00747878f3c108Dave Santoro profileDb.setTransactionSuccessful(); 2224078f588cef389358adabc579de00747878f3c108Dave Santoro profileDb.endTransaction(); 2225078f588cef389358adabc579de00747878f3c108Dave Santoro } 2226078f588cef389358adabc579de00747878f3c108Dave Santoro 2227078f588cef389358adabc579de00747878f3c108Dave Santoro // Now proceed with the Contacts DB yield. 2228078f588cef389358adabc579de00747878f3c108Dave Santoro SQLiteDatabase contactsDb = transaction.getDbForTag(CONTACTS_DB_TAG); 2229078f588cef389358adabc579de00747878f3c108Dave Santoro return contactsDb != null && contactsDb.yieldIfContendedSafely(SLEEP_AFTER_YIELD_DELAY); 2230078f588cef389358adabc579de00747878f3c108Dave Santoro } 2231078f588cef389358adabc579de00747878f3c108Dave Santoro 2232078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 2233568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 2234568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov throws OperationApplicationException { 223515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 2236078f588cef389358adabc579de00747878f3c108Dave Santoro return super.applyBatch(operations); 2237568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2238568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 22394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 22407b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov public int bulkInsert(Uri uri, ContentValues[] values) { 22417b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov waitForAccess(mWriteAccessLatch); 2242078f588cef389358adabc579de00747878f3c108Dave Santoro return super.bulkInsert(uri, values); 22437b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov } 22447b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov 22457b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov @Override 2246078f588cef389358adabc579de00747878f3c108Dave Santoro public void onBegin() { 2247bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 2248b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "onBeginTransaction"); 2249b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 22505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (inProfileMode()) { 22515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator.clearPendingAggregations(); 22525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileTransactionContext.clear(); 22535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 22545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator.clearPendingAggregations(); 22555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactTransactionContext.clear(); 22565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 2257b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2258b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2259285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2260078f588cef389358adabc579de00747878f3c108Dave Santoro public void onCommit() { 2261bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 2262b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "beforeTransactionCommit"); 2263b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2264b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 22655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateInTransaction(mTransactionContext.get(), mActiveDb.get()); 22661a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (mVisibleTouched) { 22671a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = false; 22685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().updateAllVisible(); 22691a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey } 22703826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 2271bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 2272bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 22733826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatusUpdateNeeded) { 22743826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 22753826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = false; 22763826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 2277b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2278b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2279078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 2280078f588cef389358adabc579de00747878f3c108Dave Santoro public void onRollback() { 2281078f588cef389358adabc579de00747878f3c108Dave Santoro // Not used. 2282078f588cef389358adabc579de00747878f3c108Dave Santoro } 2283078f588cef389358adabc579de00747878f3c108Dave Santoro 2284bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov private void updateSearchIndexInTransaction() { 22855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> staleContacts = mTransactionContext.get().getStaleSearchIndexContactIds(); 22865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> staleRawContacts = mTransactionContext.get().getStaleSearchIndexRawContactIds(); 2287bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov if (!staleContacts.isEmpty() || !staleRawContacts.isEmpty()) { 2288bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mSearchIndexManager.updateIndexForRawContacts(staleContacts, staleRawContacts); 22895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().clearSearchIndexUpdates(); 2290bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 2291bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 2292bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 2293b5a4add17815167d20a90645779df34cdf45280dFred Quintana private void flushTransactionalChanges() { 2294bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 2295b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "flushTransactionChanges"); 2296b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 22971129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 22985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro for (long rawContactId : mTransactionContext.get().getInsertedRawContactIds()) { 22995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().updateRawContactDisplayName(mActiveDb.get(), rawContactId); 23005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().onRawContactInsert(mTransactionContext.get(), mActiveDb.get(), 23015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro rawContactId); 230224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 230324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 23045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> dirtyRawContacts = mTransactionContext.get().getDirtyRawContactIds(); 2305d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!dirtyRawContacts.isEmpty()) { 2306a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 2307a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL); 2308d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, dirtyRawContacts); 2309a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 23105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(mSb.toString()); 2311a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov } 2312a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 23135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> updatedRawContacts = mTransactionContext.get().getUpdatedRawContactIds(); 2314d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!updatedRawContacts.isEmpty()) { 2315a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 2316a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL); 2317d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, updatedRawContacts); 2318a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 23195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(mSb.toString()); 2320b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2321b5a4add17815167d20a90645779df34cdf45280dFred Quintana 23225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Update sync states. 23235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro for (Map.Entry<Long, Object> entry : mTransactionContext.get().getUpdatedSyncStates()) { 2324b5a4add17815167d20a90645779df34cdf45280dFred Quintana long id = entry.getKey(); 23255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().getSyncState().update(mActiveDb.get(), id, entry.getValue()) <= 0) { 23269d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana throw new IllegalStateException( 23279d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana "unable to update sync state, does it still exist?"); 23289d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana } 2329b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2330b5a4add17815167d20a90645779df34cdf45280dFred Quintana 23315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().clear(); 2332b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2333b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2334a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** 2335a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * Appends comma separated ids. 2336a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * @param ids Should not be empty 2337a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov */ 2338d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private void appendIds(StringBuilder sb, Set<Long> ids) { 2339b5a4add17815167d20a90645779df34cdf45280dFred Quintana for (long id : ids) { 2340a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(id).append(','); 2341b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2342a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 2343a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.setLength(sb.length() - 1); // Yank the last comma 2344285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 2345285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 2346285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2347cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov protected void notifyChange() { 234881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov notifyChange(mSyncToNetwork); 234981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = false; 235081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 235181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 235281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov protected void notifyChange(boolean syncToNetwork) { 235381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null, 235481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov syncToNetwork); 2355cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov } 2356568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 235751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov protected void setProviderStatus(int status) { 23583826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != status) { 23593826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = status; 23603826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov getContext().getContentResolver().notifyChange(ProviderStatus.CONTENT_URI, null, false); 23613826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 236251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 236351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 2364f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public DataRowHandler getDataRowHandler(final String mimeType) { 23655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (inProfileMode()) { 23665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return getDataRowHandlerForProfile(mimeType); 23675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 23683cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataRowHandler handler = mDataRowHandlers.get(mimeType); 23693cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (handler == null) { 23706d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov handler = new DataRowHandlerForCustomMimetype( 23715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro getContext(), mContactsHelper, mContactAggregator, mimeType); 23723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(mimeType, handler); 23733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 23743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return handler; 23753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 23763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 23775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public DataRowHandler getDataRowHandlerForProfile(final String mimeType) { 23785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro DataRowHandler handler = mProfileDataRowHandlers.get(mimeType); 23795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (handler == null) { 23805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handler = new DataRowHandlerForCustomMimetype( 23815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro getContext(), mProfileHelper, mProfileAggregator, mimeType); 23825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDataRowHandlers.put(mimeType, handler); 23835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 23845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return handler; 23855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 23865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 23874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 2388de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected Uri insertInTransaction(Uri uri, ContentValues values) { 2389bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 23901129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Log.v(TAG, "insertInTransaction: " + uri + " " + values); 2391b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2392f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 23935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 23945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 2395078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getWritableDatabase()); 23965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 23975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 2398f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 2399f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 2400f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2401a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 2402a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 240335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2404a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 240535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 24065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 24075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = mDbHelper.get().getSyncState().insert(mActiveDb.get(), values); 240835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 240935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2410d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 2411d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov insertContact(values); 24126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 24136bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 24146bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 241524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 241624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro throw new UnsupportedOperationException( 241724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "The profile contact is created automatically"); 241824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 241924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2420d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS: 2421d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS: { 24225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter); 2423f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2424a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2425a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2426a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2427d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS_DATA: 2428d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 2429d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro int segment = match == RAW_CONTACTS_DATA ? 1 : 2; 2430d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(segment)); 2431f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2432f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2433a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2434a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2435a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 24363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 24373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItems.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 24383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 24393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 24403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 24413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24430c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case DATA: 24440c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case PROFILE_DATA: { 2445f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2446f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2447a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2448a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2449a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2450ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 2451f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov id = insertGroup(uri, values, callerIsSyncAdapter); 2452f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2453ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2454ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2455ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2456eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 24575aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey id = insertSettings(uri, values); 245843880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 2459eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 2460eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 2461eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 24625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 24635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 246482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov id = insertStatusUpdate(values); 24651f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 24661f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 24671f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 24683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 24693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 24703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 24713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 24723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 24753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 24763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 24773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 24783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 24813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItemPhotos.STREAM_ITEM_ID, uri.getPathSegments().get(1)); 24823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 24833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 24843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 24853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2487a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 248881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 2489f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 2490a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2491a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 24927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 24937e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 24947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24957e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2496de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return ContentUris.withAppendedId(uri, id); 2497a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2498a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2499a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2500e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * If account is non-null then store it in the values. If the account is 2501e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * already specified in the values then it must be consistent with the 2502e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * account, if it is non-null. 2503e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * 2504e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param uri Current {@link Uri} being operated on. 2505e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param values {@link ContentValues} to read and possibly update. 2506e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when only one of 2507e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_NAME} or 2508e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the 2509e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * other undefined. 2510e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME} 2511e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between 2512e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * the given {@link Uri} and {@link ContentValues}. 25137e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 2514e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException { 2515f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 2516f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 2517e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 2518f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2519f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME); 2520f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 2521e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialValues = TextUtils.isEmpty(valueAccountName) 2522e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey ^ TextUtils.isEmpty(valueAccountType); 2523e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2524e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri || partialValues) { 2525e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 25265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 2527fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 2528e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2529e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2530e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 2531e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 2532e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validUri = !TextUtils.isEmpty(accountName); 2533e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validValues = !TextUtils.isEmpty(valueAccountName); 2534e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2535e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validValues && validUri) { 2536e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Check that accounts match when both present 2537e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean accountMatch = TextUtils.equals(accountName, valueAccountName) 2538e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey && TextUtils.equals(accountType, valueAccountType); 2539e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (!accountMatch) { 25405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 2541fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "When both specified, ACCOUNT_NAME and ACCOUNT_TYPE must match", uri)); 2542e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2543e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validUri) { 2544e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Fill values from Uri when not present 2545f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_NAME, accountName); 2546f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_TYPE, accountType); 2547e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validValues) { 2548f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountName = valueAccountName; 2549f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountType = valueAccountType; 2550e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else { 2551e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return null; 2552f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 2553f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2554e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Use cached Account object when matches, otherwise create 2555f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mAccount == null 2556f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.name.equals(accountName) 2557f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.type.equals(accountType)) { 2558f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mAccount = new Account(accountName, accountType); 2559035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 2560f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2561e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return mAccount; 25627e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 25637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 25647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 256543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Resolves the account and builds an {@link AccountWithDataSet} based on the data set specified 256643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * in the URI or values (if any). 256743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param uri Current {@link Uri} being operated on. 256843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param values {@link ContentValues} to read and possibly update. 256943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro */ 257043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private AccountWithDataSet resolveAccountWithDataSet(Uri uri, ContentValues values) { 25713593682b8d9213fde576a0cff54458ad50563980Dave Santoro final Account account = resolveAccount(uri, values); 257243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = null; 257343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (account != null) { 257443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 257543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (dataSet == null) { 25763593682b8d9213fde576a0cff54458ad50563980Dave Santoro dataSet = values.getAsString(RawContacts.DATA_SET); 2577a71dc460ca951c7aca591f3f470c160cde70a1e3Dave Santoro } else { 25783593682b8d9213fde576a0cff54458ad50563980Dave Santoro values.put(RawContacts.DATA_SET, dataSet); 257943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 258043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet = new AccountWithDataSet(account.name, account.type, dataSet); 258143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 258243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro return accountWithDataSet; 258343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 258443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 258543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro /** 2586d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov * Inserts an item in the contacts table 25876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 25886bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 25896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 25906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 2591d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private long insertContact(ContentValues values) { 2592de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new UnsupportedOperationException("Aggregate contacts are created automatically"); 25936bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 25946bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 25956bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 259624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Inserts an item in the raw contacts table 2597a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2598f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param uri the values for the new row 2599f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param values the account this contact should be associated with. may be null. 2600dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana * @param callerIsSyncAdapter 2601a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2602a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 26035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private long insertRawContact(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2604f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2605f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2606f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 2607f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 260843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = resolveAccountWithDataSet(uri, mValues); 26097e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 26103d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov if (values.containsKey(RawContacts.DELETED) 26113d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov && values.getAsInteger(RawContacts.DELETED) != 0) { 2612f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 26133d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 26143d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 26155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long rawContactId = mActiveDb.get().insert(Tables.RAW_CONTACTS, 26165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro RawContacts.CONTACT_ID, mValues); 2617f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = RawContacts.AGGREGATION_MODE_DEFAULT; 26185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mValues.containsKey(RawContacts.AGGREGATION_MODE)) { 2619f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov aggregationMode = mValues.getAsInteger(RawContacts.AGGREGATION_MODE); 2620f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 26215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markNewForAggregation(rawContactId, aggregationMode); 2622285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 26235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Trigger creation of a Contact based on this RawContact at the end of transaction 26245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().rawContactInserted(rawContactId, accountWithDataSet); 2625f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2626dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 2627dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 2628dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long starred = values.getAsLong(RawContacts.STARRED); 2629dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (starred != null && starred != 0) { 2630dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred != 0); 2631dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2632dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2633dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 26343826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 2635023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov return rawContactId; 2636a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2637a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2638dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void addAutoAddMembership(long rawContactId) { 2639dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID, 2640dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2641dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2642dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2643dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2644dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2645dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2646dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private Long findGroupByRawContactId(String selection, long rawContactId) { 26475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.GROUPS + "," + Tables.RAW_CONTACTS, 26485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROJECTION_GROUP_ID, selection, 2649dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}, 2650dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana null /* groupBy */, null /* having */, null /* orderBy */); 2651dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 2652dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (c.moveToNext()) { 2653dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return c.getLong(0); 2654dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2655dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return null; 2656dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 2657dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana c.close(); 2658dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2659dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2660dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2661dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void updateFavoritesMembership(long rawContactId, boolean isStarred) { 2662dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID, 2663dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2664dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2665dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (isStarred) { 2666dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2667dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2668dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana deleteDataGroupMembership(rawContactId, groupId); 2669dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2670dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2671dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2672dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2673dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void insertDataGroupMembership(long rawContactId, long groupId) { 2674dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ContentValues groupMembershipValues = new ContentValues(); 2675dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.GROUP_ROW_ID, groupId); 2676dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 2677dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(DataColumns.MIMETYPE_ID, 26785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 26795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().insert(Tables.DATA, null, groupMembershipValues); 2680dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2681dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2682dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void deleteDataGroupMembership(long rawContactId, long groupId) { 2683dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final String[] selectionArgs = { 26845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Long.toString(mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)), 2685dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(groupId), 2686dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(rawContactId)}; 26875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.DATA, SELECTION_GROUPMEMBERSHIP_DATA, selectionArgs); 2688dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2689dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2690a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2691a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 2692a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2693a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 2694a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2695a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 2696f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private long insertData(ContentValues values, boolean callerIsSyncAdapter) { 2697a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 2698de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.clear(); 2699de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.putAll(values); 270067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 2701de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID); 270220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2703de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace package with internal mapping 2704de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String packageName = mValues.getAsString(Data.RES_PACKAGE); 2705de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (packageName != null) { 27065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 2707de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 2708de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 2709508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 2710de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace mimetype with internal mapping 2711de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String mimeType = mValues.getAsString(Data.MIMETYPE); 2712de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (TextUtils.isEmpty(mimeType)) { 2713de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new IllegalArgumentException(Data.MIMETYPE + " is required"); 2714de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 27154097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 27165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.get().getMimeTypeId(mimeType)); 2717de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 2718a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2719a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 27205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = rowHandler.insert(mActiveDb.get(), mTransactionContext.get(), rawContactId, mValues); 2721f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 27225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().markRawContactDirty(rawContactId); 2723a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 27245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().rawContactUpdated(rawContactId); 2725a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 27264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 27274f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 27283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 27293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_items table. The account is checked against the 27303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account in the raw contact for which the stream item is being inserted. If the 27313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * new stream item results in more stream items under this raw contact than the limit, 27323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest one will be deleted (note that if the stream item inserted was the 27333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * oldest, it will be immediately deleted, and this will return 0). 27343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 27353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 27363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 27373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return the stream item _ID of the newly created row, or 0 if it was not created 27383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 27393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItem(Uri uri, ContentValues values) { 27403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 27413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 27423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 27433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = mValues.getAsLong(StreamItems.RAW_CONTACT_ID); 27453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 27473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 27483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 27493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27506802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream items table. 27516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 27526802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 27536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 27543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Insert the new stream item. 27555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = mActiveDb.get().insert(Tables.STREAM_ITEMS, null, mValues); 27566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (id == -1) { 27576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insertion failed. 27586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 27596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check to see if we're over the limit for stream items under this raw contact. 27623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // It's possible that the inserted stream item is older than the the existing 27633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // ones, in which case it may be deleted immediately (resetting the ID to 0). 27643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = cleanUpOldStreamItems(rawContactId, id); 27653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 27673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 27703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_item_photos table. The account is checked against 27713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the account in the raw contact that owns the stream item being modified. 27723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 27733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 27743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 27756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return the stream item photo _ID of the newly created row, or 0 if there was an issue 27766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * with processing the photo or creating the row 27773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 27783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItemPhoto(Uri uri, ContentValues values) { 27793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 27803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 27813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 27823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = mValues.getAsLong(StreamItemPhotos.STREAM_ITEM_ID); 27843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemId != 0) { 27853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = lookupRawContactIdForStreamId(streamItemId); 27863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 27883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 27893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 27903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream item 27926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 27936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 27946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 27953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 27976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(mValues, false)) { 27986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insert the stream item photo. 27995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = mActiveDb.get().insert(Tables.STREAM_ITEM_PHOTOS, null, mValues); 28006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 28033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 28066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Processes the photo contained in the {@link ContactsContract.StreamItemPhotos#PHOTO} 28076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * field of the given values, attempting to store it in the photo store. If successful, 28086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * the resulting photo file ID will be added to the values for insert/update in the table. 28096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * <p> 28106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * If updating, it is valid for the picture to be empty or unspecified (the function will 28116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * still return true). If inserting, a valid picture must be specified. 28126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param values The content values provided by the caller. 28136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param forUpdate Whether this photo is being processed for update (vs. insert). 28146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return Whether the insert or update should proceed. 28156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 28166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro private boolean processStreamItemPhoto(ContentValues values, boolean forUpdate) { 28176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!values.containsKey(StreamItemPhotos.PHOTO)) { 28186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 28196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro byte[] photoBytes = values.getAsByteArray(StreamItemPhotos.PHOTO); 28216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoBytes == null) { 28226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 28236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 28256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 28266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 28275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long photoFileId = mPhotoStore.get().insert(new PhotoProcessor(photoBytes, 28281dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim, true), true); 28296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileId != 0) { 28306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.put(StreamItemPhotos.PHOTO_FILE_ID, photoFileId); 28316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(StreamItemPhotos.PHOTO); 28326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return true; 28336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 28346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Couldn't store the photo, return 0. 28356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert"); 28366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 28376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } catch (IOException ioe) { 28396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert", ioe); 28406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 28416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28436802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 28446802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 28453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Looks up the raw contact ID that owns the specified stream item. 28463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param streamItemId The ID of the stream item. 28473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The associated raw contact ID, or -1 if no such stream item exists. 28483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 28493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long lookupRawContactIdForStreamId(long streamItemId) { 28503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = -1; 28515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.STREAM_ITEMS, 28525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{StreamItems.RAW_CONTACT_ID}, 28533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems._ID + "=?", new String[]{String.valueOf(streamItemId)}, 28543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 28553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 28563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c.moveToFirst()) { 28573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann rawContactId = c.getLong(0); 28583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 28603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 28613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return rawContactId; 28633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 286636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * If the given URI is reading stream items or stream photos, this will run a permission check 286736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * for the android.permission.READ_SOCIAL_STREAM permission - otherwise it will do nothing. 286836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * @param uri The URI to check. 286936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro */ 287036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro private void enforceSocialStreamReadPermission(Uri uri) { 287182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (SOCIAL_STREAM_URIS.contains(sUriMatcher.match(uri)) 287282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro && !isValidPreAuthorizedUri(uri)) { 287336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro getContext().enforceCallingOrSelfPermission( 287436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro "android.permission.READ_SOCIAL_STREAM", null); 287536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 287636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 287736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 287836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro /** 287936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * If the given URI is modifying stream items or stream photos, this will run a permission check 288036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * for the android.permission.WRITE_SOCIAL_STREAM permission - otherwise it will do nothing. 288136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * @param uri The URI to check. 288236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro */ 288336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro private void enforceSocialStreamWritePermission(Uri uri) { 288436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro if (SOCIAL_STREAM_URIS.contains(sUriMatcher.match(uri))) { 288536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro getContext().enforceCallingOrSelfPermission( 288636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro "android.permission.WRITE_SOCIAL_STREAM", null); 288736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 288836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 288936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 289036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro /** 28913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given raw contact ID is owned by the given account. 28923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account is null, this will return true iff the raw contact 28933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * is also associated with the "null" account. 28943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 28953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account does not match, this will throw a security exception. 28963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 28973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to check for. 28983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 28993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void enforceModifyingAccount(Account account, long rawContactId) { 29003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String accountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 29013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + "=? AND " 29023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + "=?"; 29033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String noAccountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 29043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " IS NULL AND " 29053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " IS NULL"; 29063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c; 29073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (account != null) { 29085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro c = mActiveDb.get().query(Tables.RAW_CONTACTS, 29095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{RawContactsColumns.CONCRETE_ID}, accountSelection, 29103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(rawContactId), mAccount.name, mAccount.type}, 29113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 29123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 29135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro c = mActiveDb.get().query(Tables.RAW_CONTACTS, 29145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{RawContactsColumns.CONCRETE_ID}, noAccountSelection, 29155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{String.valueOf(rawContactId)}, 29163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 29173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 29193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if(c.getCount() == 0) { 29203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new SecurityException("Caller account does not match raw contact ID " 29213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + rawContactId); 29223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 29243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 29253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 29283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 29293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream items matches up with the given 29303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 29313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 29323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 29333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 29343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 29353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item IDs that would be included in this selection. 29363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 29373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItems(Account account, String selection, 29383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 29393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = Lists.newArrayList(); 29403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 29413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 29425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = qb.query(mActiveDb.get(), 29433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{StreamItems._ID, StreamItems.RAW_CONTACT_ID}, 29443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 29453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 29463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 29473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemIds.add(c.getLong(0)); 29483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 29493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 29503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 29513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 29533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 29543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds; 29563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 29583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 29593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream item photos matches up with the given 29603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 29613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 29623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 29633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 29643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 29653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item photo IDs that would be included in this selection. 29663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 29673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItemPhotos(Account account, String selection, 29683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 29693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemPhotoIds = Lists.newArrayList(); 29703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 29713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 29725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = qb.query(mActiveDb.get(), 29735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{StreamItemPhotos._ID, StreamItems.RAW_CONTACT_ID}, 29743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 29753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 29763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 29773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemPhotoIds.add(c.getLong(0)); 29783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 29793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 29803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 29813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 29833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 29843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemPhotoIds; 29863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 29883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 29893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Queries the database for stream items under the given raw contact. If there are 29903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * more entries than {@link ContactsProvider2#MAX_STREAM_ITEMS_PER_RAW_CONTACT}, 29913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest entries (as determined by timestamp) will be deleted. 29923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to examine for stream items. 29933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param insertedStreamItemId The ID of the stream item that was just inserted, 29943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * prompting this cleanup. Callers may pass 0 if no insertion prompted the 29953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * cleanup. 29963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The ID of the inserted stream item if it still exists after cleanup; 29973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 0 otherwise. 29983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 29993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long cleanUpOldStreamItems(long rawContactId, long insertedStreamItemId) { 30003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long postCleanupInsertedStreamId = insertedStreamItemId; 30015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.STREAM_ITEMS, new String[]{StreamItems._ID}, 30023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 30033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, StreamItems.TIMESTAMP + " DESC, " + StreamItems._ID + " DESC"); 30043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 30053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int streamItemCount = c.getCount(); 30063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemCount <= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 30073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Still under the limit - nothing to clean up! 30083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return insertedStreamItemId; 30093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 30103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToLast(); 30113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.getPosition() >= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 30123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = c.getLong(0); 30133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (insertedStreamItemId == streamItemId) { 30143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // The stream item just inserted is being deleted. 30153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann postCleanupInsertedStreamId = 0; 30163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 30173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(c.getLong(0)); 30183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToPrevious(); 30193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 30203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 30213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 30223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 30233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 30243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return postCleanupInsertedStreamId; 30253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 30263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 30279261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 302820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov * Delete data row by row so that fixing of primaries etc work correctly. 302920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov */ 3030f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) { 303120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 303220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3033de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 3034de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 30350c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro Uri dataUri = inProfileMode() 30360c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro ? Uri.withAppendedPath(Profile.CONTENT_URI, RawContacts.Data.CONTENT_DIRECTORY) 30370c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro : Data.CONTENT_URI; 30380c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro Cursor c = query(dataUri, DataRowHandler.DataDeleteQuery.COLUMNS, 3039f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov selection, selectionArgs, null); 3040de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov try { 3041de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov while(c.moveToNext()) { 3042f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 3043f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 3044a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 30455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro count += rowHandler.delete(mActiveDb.get(), mTransactionContext.get(), c); 3046f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 30475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().markRawContactDirty(rawContactId); 304888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov } 304920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 305020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 3051de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov c.close(); 305220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 305320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 305420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 305520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 305620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 305788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov /** 305888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov * Delete a data row provided that it is one of the allowed mime types. 305988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov */ 306020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov public int deleteData(long dataId, String[] allowedMimeTypes) { 3061f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 306288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 306388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 30644da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 3065f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, Data._ID + "=?", 30664da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1, null); 3067f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 306820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 306920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!c.moveToFirst()) { 307020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 307120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 307220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 3073f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 307420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean valid = false; 307520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov for (int i = 0; i < allowedMimeTypes.length; i++) { 307620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.equals(mimeType, allowedMimeTypes[i])) { 307720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov valid = true; 307820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 307920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 308020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 308120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 308220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!valid) { 30837a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana throw new IllegalArgumentException("Data type mismatch: expected " 308420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov + Lists.newArrayList(allowedMimeTypes)); 308520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3086a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 30875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return rowHandler.delete(mActiveDb.get(), mTransactionContext.get(), c); 308820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 308920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 309020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 309120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 309220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 309320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov /** 3094ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 3095ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 3096f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 3097f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 3098f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 3099f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 31003593682b8d9213fde576a0cff54458ad50563980Dave Santoro final AccountWithDataSet accountWithDataSet = resolveAccountWithDataSet(uri, mValues); 3101ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3102ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 3103f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String packageName = mValues.getAsString(Groups.RES_PACKAGE); 310467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 31055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 310667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 3107f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.remove(Groups.RES_PACKAGE); 3108ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3109dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final boolean isFavoritesGroup = mValues.getAsLong(Groups.FAVORITES) != null 3110dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ? mValues.getAsLong(Groups.FAVORITES) != 0 3111dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana : false; 3112dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3113f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 3114f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(Groups.DIRTY, 1); 311573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 311673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 31175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long result = mActiveDb.get().insert(Tables.GROUPS, Groups.TITLE, mValues); 3118ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 3119dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && isFavoritesGroup) { 3120dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // add all starred raw contacts to this group 3121dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String selection; 3122dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs; 31233593682b8d9213fde576a0cff54458ad50563980Dave Santoro if (accountWithDataSet == null) { 3124dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + " IS NULL AND " 312543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.ACCOUNT_TYPE + " IS NULL AND " 312643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.DATA_SET + " IS NULL"; 3127dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = null; 31283593682b8d9213fde576a0cff54458ad50563980Dave Santoro } else if (accountWithDataSet.getDataSet() == null) { 3129dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + "=? AND " 31303593682b8d9213fde576a0cff54458ad50563980Dave Santoro + RawContacts.ACCOUNT_TYPE + "=? AND " 31313593682b8d9213fde576a0cff54458ad50563980Dave Santoro + RawContacts.DATA_SET + " IS NULL"; 31323593682b8d9213fde576a0cff54458ad50563980Dave Santoro selectionArgs = new String[] { 31333593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountName(), 31343593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountType() 31353593682b8d9213fde576a0cff54458ad50563980Dave Santoro }; 313643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } else { 313743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selection = RawContacts.ACCOUNT_NAME + "=? AND " 313843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.ACCOUNT_TYPE + "=? AND " 313943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.DATA_SET + "=?"; 31403593682b8d9213fde576a0cff54458ad50563980Dave Santoro selectionArgs = new String[] { 31413593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountName(), 31423593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountType(), 31433593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getDataSet() 31443593682b8d9213fde576a0cff54458ad50563980Dave Santoro }; 3145dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 31465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.RAW_CONTACTS, 3147dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{RawContacts._ID, RawContacts.STARRED}, 3148dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, selectionArgs, null, null, null); 3149892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov try { 3150892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov while (c.moveToNext()) { 3151892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (c.getLong(1) != 0) { 3152892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov final long rawContactId = c.getLong(0); 3153892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov insertDataGroupMembership(rawContactId, result); 31545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().markRawContactDirty(rawContactId); 3155892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } 3156dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3157892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } finally { 3158892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov c.close(); 3159dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3160dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3161dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3162f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mValues.containsKey(Groups.GROUP_VISIBLE)) { 31631a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3164ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey } 3165ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 3166ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey return result; 3167ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3168ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 31695aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private long insertSettings(Uri uri, ContentValues values) { 3170f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // Before inserting, ensure that no settings record already exists for the 3171f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // values being inserted (this used to be enforced by a primary key, but that no 3172f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // longer works with the nullable data_set field added). 3173f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro String accountName = values.getAsString(Settings.ACCOUNT_NAME); 3174f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro String accountType = values.getAsString(Settings.ACCOUNT_TYPE); 3175f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro String dataSet = values.getAsString(Settings.DATA_SET); 3176f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro Uri.Builder settingsUri = Settings.CONTENT_URI.buildUpon(); 3177f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (accountName != null) { 3178f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro settingsUri.appendQueryParameter(Settings.ACCOUNT_NAME, accountName); 3179f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 3180f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (accountType != null) { 3181f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro settingsUri.appendQueryParameter(Settings.ACCOUNT_TYPE, accountType); 3182f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 3183f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (dataSet != null) { 3184f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro settingsUri.appendQueryParameter(Settings.DATA_SET, dataSet); 3185f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 3186f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro Cursor c = queryLocal(settingsUri.build(), null, null, null, null, 0); 3187f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro try { 3188f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (c.getCount() > 0) { 31890e21a867a572679d64d79041eb574d13665178d4Dave Santoro // If a record was found, replace it with the new values. 31900e21a867a572679d64d79041eb574d13665178d4Dave Santoro String selection = null; 31910e21a867a572679d64d79041eb574d13665178d4Dave Santoro String[] selectionArgs = null; 31920e21a867a572679d64d79041eb574d13665178d4Dave Santoro if (accountName != null && accountType != null) { 31930e21a867a572679d64d79041eb574d13665178d4Dave Santoro selection = Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE + "=?"; 31940e21a867a572679d64d79041eb574d13665178d4Dave Santoro if (dataSet == null) { 31950e21a867a572679d64d79041eb574d13665178d4Dave Santoro selection += " AND " + Settings.DATA_SET + " IS NULL"; 31960e21a867a572679d64d79041eb574d13665178d4Dave Santoro selectionArgs = new String[] {accountName, accountType}; 31970e21a867a572679d64d79041eb574d13665178d4Dave Santoro } else { 31980e21a867a572679d64d79041eb574d13665178d4Dave Santoro selection += " AND " + Settings.DATA_SET + "=?"; 31990e21a867a572679d64d79041eb574d13665178d4Dave Santoro selectionArgs = new String[] {accountName, accountType, dataSet}; 32000e21a867a572679d64d79041eb574d13665178d4Dave Santoro } 32010e21a867a572679d64d79041eb574d13665178d4Dave Santoro } 32020e21a867a572679d64d79041eb574d13665178d4Dave Santoro return updateSettings(uri, values, selection, selectionArgs); 3203f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 3204f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } finally { 3205f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro c.close(); 3206f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 3207f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro 3208f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // If we didn't find a duplicate, we're fine to insert. 32095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long id = mActiveDb.get().insert(Tables.SETTINGS, null, values); 32105aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey 32111a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 32121a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3213e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 32141a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 3215e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return id; 3216e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3217e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3218ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 321982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov * Inserts a status update. 32201f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 322182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov public long insertStatusUpdate(ContentValues values) { 322282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov final String handle = values.getAsString(StatusUpdates.IM_HANDLE); 32230a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL); 32244dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov String customProtocol = null; 32254dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov 32260a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) { 322782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL); 32284dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov if (TextUtils.isEmpty(customProtocol)) { 32294dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov throw new IllegalArgumentException( 32304dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM"); 32314dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov } 32321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 32331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3234dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long rawContactId = -1; 3235dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long contactId = -1; 323682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov Long dataId = values.getAsLong(StatusUpdates.DATA_ID); 32376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountType = null; 32386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountName = null; 3239f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov mSb.setLength(0); 32402526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.clear(); 3241dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (dataId != null) { 3242dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the contact info for the given data row. 3243dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 32442526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(Tables.DATA + "." + Data._ID + "=?"); 32452526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(dataId)); 32461f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 3247dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the data row to attach this presence update to 3248dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 32490a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(handle) || protocol == null) { 32500a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required"); 32510a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 32520a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 3253dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // TODO: generalize to allow other providers to match against email 3254dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol; 3255dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 32565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String mimeTypeIdIm = String.valueOf(mDbHelper.get().getMimeTypeIdForIm()); 3257dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (matchEmail) { 32585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String mimeTypeIdEmail = String.valueOf(mDbHelper.get().getMimeTypeIdForEmail()); 3259f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 3260f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise 3261f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the "OR" conjunction confuses it and it switches to a full scan of 3262f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the raw_contacts table. 3263f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 3264f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // This code relies on the fact that Im.DATA and Email.DATA are in fact the same 3265f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // column - Data.DATA1 32662526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + " IN (?,?)" + 32672526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Data.DATA1 + "=?" + 32682526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND ((" + DataColumns.MIMETYPE_ID + "=? AND " + Im.PROTOCOL + "=?"); 32692526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 32702526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 32712526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 32722526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 32732526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 3274dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 32752526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 32762526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 3277dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 32782526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=?))"); 32792526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 3280dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } else { 32812526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + "=?" + 32822526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.PROTOCOL + "=?" + 32832526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.DATA + "=?"); 32842526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 32852526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 32862526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 3287dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 32882526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 32892526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 3290dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 3291dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 32921f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 329382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.DATA_ID)) { 32942526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + DataColumns.CONCRETE_ID + "=?"); 32952526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(values.getAsString(StatusUpdates.DATA_ID)); 3296dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 329770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 329870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 32991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 33001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 33015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro cursor = mActiveDb.get().query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 33022526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null, 33034394086494fe7909aaca70f56fb4bb08beebf303Dmitri Plotnikov Clauses.CONTACT_VISIBLE + " DESC, " + Data.RAW_CONTACT_ID); 33041f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 330567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataId = cursor.getLong(DataContactsQuery.DATA_ID); 33065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID); 33076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountType = cursor.getString(DataContactsQuery.ACCOUNT_TYPE); 33086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountName = cursor.getString(DataContactsQuery.ACCOUNT_NAME); 3309e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 33101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 33111f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 33121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 33131f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 33141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 331531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 331631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 331731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 33181f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 33191f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 332082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.PRESENCE)) { 3321a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (customProtocol == null) { 3322a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 3323a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // properly enforce uniqueness of null values 3324a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov customProtocol = ""; 3325a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3326a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3327a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.clear(); 332882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.DATA_ID, dataId); 3329a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId); 3330a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.CONTACT_ID, contactId); 333182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PROTOCOL, protocol); 333282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 333382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_HANDLE, handle); 333482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.IM_ACCOUNT)) { 333582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT)); 3336a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 333782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PRESENCE, 333882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov values.getAsString(StatusUpdates.PRESENCE)); 3339aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori mValues.put(StatusUpdates.CHAT_CAPABILITY, 3340aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori values.getAsString(StatusUpdates.CHAT_CAPABILITY)); 33411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3342a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // Insert the presence update 33435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().replace(Tables.PRESENCE, null, mValues); 3344a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3345e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 33460a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 334782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.STATUS)) { 334882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String status = values.getAsString(StatusUpdates.STATUS); 33490a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE); 33500bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Resources resources = getContext().getResources(); 33510bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (!TextUtils.isEmpty(resPackage)) { 33520bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann PackageManager pm = getContext().getPackageManager(); 33530bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann try { 33540bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann resources = pm.getResourcesForApplication(resPackage); 33550bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } catch (NameNotFoundException e) { 33560bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Log.w(TAG, "Contact status update resource package not found: " 33570bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + resPackage); 33580bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 33590bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 33600bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Integer labelResourceId = values.getAsInteger(StatusUpdates.STATUS_LABEL); 33610a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 33620bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if ((labelResourceId == null || labelResourceId == 0) && protocol != null) { 33630bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann labelResourceId = Im.getProtocolLabelResource(protocol); 33640a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 33650bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann String labelResource = getResourceName(resources, "string", labelResourceId); 33660a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 33670bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Integer iconResourceId = values.getAsInteger(StatusUpdates.STATUS_ICON); 33680a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov // TODO compute the default icon based on the protocol 33690a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 33700bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann String iconResource = getResourceName(resources, "drawable", iconResourceId); 33710bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 3372a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (TextUtils.isEmpty(status)) { 33735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().deleteStatusUpdate(dataId); 3374a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } else { 33756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP); 33766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (timestamp != null) { 33775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().replaceStatusUpdate(dataId, timestamp, status, resPackage, 33780bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann iconResourceId, labelResourceId); 33796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 33805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().insertStatusUpdate(dataId, status, resPackage, iconResourceId, 33810bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann labelResourceId); 33826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 33836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 33846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For forward compatibility with the new stream item API, insert this status update 33856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // there as well. If we already have a stream item from this source, update that 33866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // one instead of inserting a new one (since the semantics of the old status update 33876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // API is to only have a single record). 33886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (rawContactId != -1 && !TextUtils.isEmpty(status)) { 33896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentValues streamItemValues = new ContentValues(); 33906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 3391d5ef5903570e533a501abe6a8e3d533fdb5318fcFlavio Lerda // Status updates are text only but stream items are HTML. 3392e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda streamItemValues.put(StreamItems.TEXT, statusUpdateToHtml(status)); 33936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.COMMENTS, ""); 33946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_PACKAGE, resPackage); 33956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_ICON, iconResource); 33966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_LABEL, labelResource); 33976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TIMESTAMP, 33986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro timestamp == null ? System.currentTimeMillis() : timestamp); 33996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 34006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Note: The following is basically a workaround for the fact that status 34016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates didn't do any sort of account enforcement, while social stream item 34026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates do. We can't expect callers of the old API to start passing account 34036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // information along, so we just populate the account params appropriately for 340443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // the raw contact. Data set is not relevant here, as we only check account 340543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // name and type. 34066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (accountName != null && accountType != null) { 34076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_NAME, accountName); 34086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_TYPE, accountType); 34096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 34106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 34116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Check for an existing stream item from this source, and insert or update. 34126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Uri streamUri = StreamItems.CONTENT_URI; 341336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro Cursor c = queryLocal(streamUri, new String[]{StreamItems._ID}, 34146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", 341536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro new String[]{String.valueOf(rawContactId)}, 341636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro null, -1 /* directory ID */); 34176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 34186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (c.getCount() > 0) { 34196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.moveToFirst(); 342036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro updateInTransaction(ContentUris.withAppendedId(streamUri, c.getLong(0)), 34216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues, null, null); 34226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 342336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro insertInTransaction(streamUri, streamItemValues); 34246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 34256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 34266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 34276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 34286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 3429e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3430e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3431bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov 3432a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (contactId != -1) { 34335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateLastStatusUpdateId(contactId); 3434a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3435a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3436a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov return dataId; 34371f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 34381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3439e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda /** Converts a status update to HTML. */ 3440e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda private String statusUpdateToHtml(String status) { 34414747809486541f7a3d342d3e1dd48fb5ea255ad6Flavio Lerda return TextUtils.htmlEncode(status); 3442e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda } 3443e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda 34440bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann private String getResourceName(Resources resources, String expectedType, Integer resourceId) { 34450bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann try { 34460bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (resourceId == null || resourceId == 0) return null; 34470bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 34480bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann // Resource has an invalid type (e.g. a string as icon)? ignore 34490bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann final String resourceEntryName = resources.getResourceEntryName(resourceId); 34500bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann final String resourceTypeName = resources.getResourceTypeName(resourceId); 34510bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (!expectedType.equals(resourceTypeName)) { 34520bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Log.w(TAG, "Resource " + resourceId + " (" + resourceEntryName + ") is of type " + 34530bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann resourceTypeName + " but " + expectedType + " is required."); 34540bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return null; 34550bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 34560bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 34570bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return resourceEntryName; 34580bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } catch (NotFoundException e) { 34590bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return null; 34600bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 34610bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 34620bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 34634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3464de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 3465bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3466b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "deleteInTransaction: " + uri); 3467b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 34685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 34695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 34705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 3471078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getWritableDatabase()); 34725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 34735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 3474b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3475f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3476f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 3477508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 3478508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 347935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 34805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 34815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().delete(mActiveDb.get(), selection, 34825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 34835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 34845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case SYNCSTATE_ID: { 34855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String selectionWithId = 34865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 34875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 34885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().delete(mActiveDb.get(), selectionWithId, 34895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 34905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 349135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 34925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE_ID: { 3493b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3494b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3495b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 34965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileHelper.getSyncState().delete(mActiveDb.get(), selectionWithId, 34975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 34985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 3499b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3500cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov case CONTACTS: { 3501cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov // TODO 3502cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return 0; 3503cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3504cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3505d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3506d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 3507dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 35086bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 35096bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 35109fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP: { 35112e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 35122e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 35132e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 35145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 3515fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 35162e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 35172e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 35185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 3519dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 35202e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 35212e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 35229fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP_ID: { 35239fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // lookup contact by id and lookup key to see if they still match the actual record 35249fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final List<String> pathSegments = uri.getPathSegments(); 35259fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final String lookupKey = pathSegments.get(2); 35269fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 35279fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann setTablesAndProjectionMapForContacts(lookupQb, uri, null); 3528a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 35299fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann String[] args; 35309fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (selectionArgs == null) { 35319fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[2]; 35329fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 35339fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[selectionArgs.length + 2]; 35349fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 35359fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 35369fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args[0] = String.valueOf(contactId); 353760de6f6c3c70e53b603a47b0efc80993353a8368Daniel Lehmann args[1] = Uri.encode(lookupKey); 35389fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?"); 35395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = query(mActiveDb.get(), lookupQb, null, selection, args, null, null, 35405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro null); 35419fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann try { 35429fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (c.getCount() == 1) { 35439fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // contact was unmodified so go ahead and delete it 3544dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 35459fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 35469fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // row was changed (e.g. the merging might have changed), we got multiple 35479fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // rows or the supplied selection filtered the record out 35489fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann return 0; 35499fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 35509fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } finally { 35519fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann c.close(); 35529fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 35539fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 35549fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann 3555d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS: 3556d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS: { 35572971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 35585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.RAW_CONTACTS, 3559fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov new String[]{RawContacts._ID, RawContacts.CONTACT_ID}, 3560e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 35612971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 35622971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 35632971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = c.getLong(0); 3564fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov long contactId = c.getLong(1); 3565fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov numDeletes += deleteRawContact(rawContactId, contactId, 3566fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 35672971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 35682971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 35692971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 35702971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 35712971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 35722971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 35732971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 3574d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS_ID: 3575d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID: { 35762971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = ContentUris.parseId(uri); 35775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return deleteRawContact(rawContactId, mDbHelper.get().getContactId(rawContactId), 3578fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 3579508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3580508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 35810c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case DATA: 35820c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case PROFILE_DATA: { 3583f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 3584944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong return deleteData(appendAccountToSelection(uri, selection), selectionArgs, 3585f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana callerIsSyncAdapter); 358620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 358720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 358848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 358948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 359048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 3591d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case POSTALS_ID: 3592d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_DATA_ID: { 3593508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 3594f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 35954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 35964da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter); 3597ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3598ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3599ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3600f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 36015aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter); 36022971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 36032971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 36042971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case GROUPS: { 36052971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 36065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.GROUPS, new String[]{Groups._ID}, 3607e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 36082971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 36092971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 36105aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter); 36112971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 36122971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 36132971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 36142971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 361581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (numDeletes > 0) { 3616f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 361781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 36182971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 3619508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3620508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 3621eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 362243880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3623e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs); 3624eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3625eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 36265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 36275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 36280a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov return deleteStatusUpdates(selection, selectionArgs); 36291f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 36301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 36313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 36323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 36333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), selection, selectionArgs); 36343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 36373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 36383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), 36399b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann StreamItems._ID + "=?", 36403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 36413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 364382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro case RAW_CONTACTS_ID_STREAM_ITEMS_ID: { 364482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro mSyncToNetwork |= !callerIsSyncAdapter; 364582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String rawContactId = uri.getPathSegments().get(1); 364682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String streamItemId = uri.getLastPathSegment(); 364782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro return deleteStreamItems(uri, new ContentValues(), 364882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems.RAW_CONTACT_ID + "=? AND " + StreamItems._ID + "=?", 364982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro new String[]{rawContactId, streamItemId}); 365082780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 365182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 365282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 36533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 36543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 36555d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro String streamItemId = uri.getPathSegments().get(1); 36565d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro String selectionWithId = 36575d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro (StreamItemPhotos.STREAM_ITEM_ID + "=" + streamItemId + " ") 36585d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 36595d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro return deleteStreamItemPhotos(uri, new ContentValues(), 36605d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro selectionWithId, selectionArgs); 36613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 36633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 36643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 36653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 36663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 36673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), 36683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " 36693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + StreamItemPhotos.STREAM_ITEM_ID + "=?", 36703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 36713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 367381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 367481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 36753cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return mLegacyApiSupport.delete(uri, selection, selectionArgs); 367681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3677508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 36784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 36794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 36801c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) { 3681ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 36825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long groupMembershipMimetypeId = mDbHelper.get() 368394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 36845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 368594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 368694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupId, null); 368794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 368894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana try { 3689f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 36905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 369194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } else { 369294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.clear(); 369394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.put(Groups.DELETED, 1); 3694f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mValues.put(Groups.DIRTY, 1); 36955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, 36965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro null); 369794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 369894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } finally { 36991a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 370094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 370194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 370294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 37035aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int deleteSettings(Uri uri, String selection, String[] selectionArgs) { 37045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final int count = mActiveDb.get().delete(Tables.SETTINGS, selection, selectionArgs); 37051a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3706e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3707e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3708e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3709dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int deleteContact(long contactId, boolean callerIsSyncAdapter) { 371096b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(contactId); 37115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, 371296b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker RawContacts.CONTACT_ID + "=?", mSelectionArgs1, 371396b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker null, null, null); 3714cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov try { 3715cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov while (c.moveToNext()) { 3716cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov long rawContactId = c.getLong(0); 3717dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 3718cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3719cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } finally { 3720cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov c.close(); 3721cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3722cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 37233826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 37243826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 37255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 3726cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3727cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3728fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) { 37295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().invalidateAggregationExceptionCache(); 37303826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 37313826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 373282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro // Find and delete stream items associated with the raw contact. 373382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro Cursor c = mActiveDb.get().query(Tables.STREAM_ITEMS, 373482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro new String[]{StreamItems._ID}, 373582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 373682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro null, null, null); 373782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro try { 373882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro while (c.moveToNext()) { 373982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro deleteStreamItem(c.getLong(0)); 374082780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 374182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } finally { 374282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro c.close(); 374382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 374482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 3745d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro if (callerIsSyncAdapter || rawContactIsLocal(rawContactId)) { 37465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.PRESENCE, 37475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null); 37485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int count = mActiveDb.get().delete(Tables.RAW_CONTACTS, 37495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro RawContacts._ID + "=" + rawContactId, null); 375041f76a59a31946f6d784dacf9f13d9a4c0bbe203Dave Santoro mAggregator.get().updateAggregateData(mTransactionContext.get(), contactId); 3751fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return count; 375233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } else { 37535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().removeContactIfSingleton(rawContactId); 3754dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 375533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 375633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 375733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 3758d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro /** 3759d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro * Returns whether the given raw contact ID is local (i.e. has no account associated with it). 3760d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro */ 3761d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro private boolean rawContactIsLocal(long rawContactId) { 3762d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro Cursor c = mActiveDb.get().query(Tables.RAW_CONTACTS, 3763d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro new String[] { 3764d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro RawContacts.ACCOUNT_NAME, 3765d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro RawContacts.ACCOUNT_TYPE, 3766d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro RawContacts.DATA_SET 3767d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro }, 3768d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro RawContacts._ID + "=?", 3769d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro new String[] {String.valueOf(rawContactId)}, null, null, null); 3770d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro try { 3771d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro return c.moveToFirst() && c.isNull(0) && c.isNull(1) && c.isNull(2); 3772d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro } finally { 3773d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro c.close(); 3774d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro } 3775d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro } 3776d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro 37770a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private int deleteStatusUpdates(String selection, String[] selectionArgs) { 37789705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // delete from both tables: presence and status_updates 37799705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 37809705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (VERBOSE_LOGGING) { 37819705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori Log.v(TAG, "deleting data from status_updates for " + selection); 37829705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 37835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection), 37849705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 37855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.PRESENCE, selection, selectionArgs); 37860a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 37870a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 37883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItems(Uri uri, ContentValues values, String selection, 37893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 37903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream items to be deleted, and check that they belong 37913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // to the account. 37923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 37933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = enforceModifyingAccountForStreamItems( 37943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann account, selection, selectionArgs); 37953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 37963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 37973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann for (long streamItemId : streamItemIds) { 37983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(streamItemId); 37993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mVisibleTouched = true; 38023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds.size(); 38033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItem(long streamItemId) { 38063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 38073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItemPhotos(streamItemId); 38085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.STREAM_ITEMS, StreamItems._ID + "=?", 38093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 38103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(Uri uri, ContentValues values, String selection, 38133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 38143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream item photos to be deleted, and check that they 38153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // belong to the account. 38163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 38173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 38183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 38205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.STREAM_ITEM_PHOTOS, selection, selectionArgs); 38213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(long streamItemId) { 38243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 38255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.STREAM_ITEM_PHOTOS, 38265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro StreamItemPhotos.STREAM_ITEM_ID + "=?", 38273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 38283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 3830dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int markRawContactAsDeleted(long rawContactId, boolean callerIsSyncAdapter) { 383181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 383281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 3833cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.clear(); 3834cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DELETED, 1); 3835cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 3836cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1); 3837cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 3838cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3839dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return updateRawContact(rawContactId, mValues, callerIsSyncAdapter); 3840cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3841cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 38424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3843de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int updateInTransaction(Uri uri, ContentValues values, String selection, 3844de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov String[] selectionArgs) { 3845bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3846b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "updateInTransaction: " + uri); 3847b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3848b5a4add17815167d20a90645779df34cdf45280dFred Quintana 38495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 38505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 3851078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getWritableDatabase()); 38525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 38535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 385435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 385500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 385600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 3857b5a4add17815167d20a90645779df34cdf45280dFred Quintana if (match == SYNCSTATE_ID && selection == null) { 3858b5a4add17815167d20a90645779df34cdf45280dFred Quintana long rowId = ContentUris.parseId(uri); 38591129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Object data = values.get(ContactsContract.SyncState.DATA); 38605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().syncStateUpdated(rowId, data); 3861b5a4add17815167d20a90645779df34cdf45280dFred Quintana return 1; 3862b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3863b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3864f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3865f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 386600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 386735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 38685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 38695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().update(mActiveDb.get(), values, 3870b5a4add17815167d20a90645779df34cdf45280dFred Quintana appendAccountToSelection(uri, selection), selectionArgs); 3871b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3872b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: { 3873b5a4add17815167d20a90645779df34cdf45280dFred Quintana selection = appendAccountToSelection(uri, selection); 3874b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3875b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3876b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 38775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().update(mActiveDb.get(), values, 38785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionWithId, selectionArgs); 38795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 38805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 38815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE_ID: { 38825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection = appendAccountToSelection(uri, selection); 38835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String selectionWithId = 38845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 38855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 38865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileHelper.getSyncState().update(mActiveDb.get(), values, 3887b5a4add17815167d20a90645779df34cdf45280dFred Quintana selectionWithId, selectionArgs); 3888b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 388935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3890d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case CONTACTS: 3891d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE: { 3892dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter); 389300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 389400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 389500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3896d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3897dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(ContentUris.parseId(uri), values, callerIsSyncAdapter); 3898c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 3899c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 3900c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 39012e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP: 39022e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP_ID: { 39032e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 39042e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 39052e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 39065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 3907fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 39082e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 39092e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 39105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 3911dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(contactId, values, callerIsSyncAdapter); 39122e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey break; 39132e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 39142e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 3915d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS_DATA: 3916d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 3917d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro int segment = match == RAW_CONTACTS_DATA ? 1 : 2; 3918d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro final String rawContactId = uri.getPathSegments().get(segment); 39197d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ") 39207d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh + (selection == null ? "" : " AND " + selection); 39217d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 39227d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter); 39237d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 39247d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh break; 39257d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh } 39267d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 39270c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case DATA: 39280c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case PROFILE_DATA: { 3929944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong count = updateData(uri, values, appendAccountToSelection(uri, selection), 3930f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 393181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3932f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 393381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 393420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 393520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3936c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 393748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 393848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 393948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 394048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3941f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter); 394281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3943f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 394481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 394500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 394600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 39477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 39485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case RAW_CONTACTS: 39495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_RAW_CONTACTS: { 39505ac5c70d1165309302ebcc931f51723e37d31e0bJeff Sharkey selection = appendAccountToSelection(uri, selection); 3951dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, selection, selectionArgs, callerIsSyncAdapter); 39527e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 39537e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 39547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 39555ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 395633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 39574529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (selection != null) { 39584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 39594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov count = updateRawContacts(values, RawContacts._ID + "=?" 3960dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND(" + selection + ")", selectionArgs, 3961dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 39624529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } else { 39634da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 3964dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1, 3965dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 39664529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 39677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 39687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 39697e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 3970ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 39715aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, appendAccountToSelection(uri, selection), 3972f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 397381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3974f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 397581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3976ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3977ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3978ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3979ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3980ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 39814da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId)); 39824da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String selectionWithId = Groups._ID + "=? " 398373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov + (selection == null ? "" : " AND " + selection); 39845aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, selectionWithId, selectionArgs, 39855aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey callerIsSyncAdapter); 398681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3987f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 398881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3989ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3990ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3991ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3992127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 39935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro count = updateAggregationException(mActiveDb.get(), values); 3994b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 3995b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3996b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 3997eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 3998e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey count = updateSettings(uri, values, appendAccountToSelection(uri, selection), 3999e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey selectionArgs); 400043880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 4001eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 4002eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 4003eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 40045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 40055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 40069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori count = updateStatusUpdate(uri, values, selection, selectionArgs); 40079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori break; 40089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 40099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 40103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 40113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, selection, selectionArgs); 40123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 40133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 40143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 40153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 40169b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann count = updateStreamItems(uri, values, StreamItems._ID + "=?", 40173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 40183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 40193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 40203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 402182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro case RAW_CONTACTS_ID_STREAM_ITEMS_ID: { 402282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String rawContactId = uri.getPathSegments().get(1); 402382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String streamItemId = uri.getLastPathSegment(); 402482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro count = updateStreamItems(uri, values, 402582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems.RAW_CONTACT_ID + "=? AND " + StreamItems._ID + "=?", 402682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro new String[]{rawContactId, streamItemId}); 402782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro break; 402882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 402982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 40303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 40313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, selection, selectionArgs); 40323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 40333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 40343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 40353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 40363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 40373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 40383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{streamItemId}); 40393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 40403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 40413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 40423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 40433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 40443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 40453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 40463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " + 40473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?", 40483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 40493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 40503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 40513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 405272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov case DIRECTORIES: { 4053bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanPackagesByUid(Binder.getCallingUid()); 405472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov count = 1; 4055d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 4056d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4057d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 405846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa case DATA_USAGE_FEEDBACK_ID: { 405946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (handleDataUsageFeedback(uri)) { 406046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 1; 406146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 406246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 0; 406346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 406446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa break; 406546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 406646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 406781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 406881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 4069f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 407081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 407100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 407200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 407300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 40744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 40754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 40769705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private int updateStatusUpdate(Uri uri, ContentValues values, String selection, 40779705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori String[] selectionArgs) { 40789705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // update status_updates table, if status is provided 40799705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 40809705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori int updateCount = 0; 40819705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values); 40829705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 40835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro updateCount = mActiveDb.get().update(Tables.STATUS_UPDATES, 40849705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues, 40859705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori getWhereClauseForStatusUpdatesTable(selection), 40869705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 40879705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 40889705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 40899705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // now update the Presence table 40909705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues = getSettableColumnsForPresenceTable(values); 40919705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 40925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro updateCount = mActiveDb.get().update(Tables.PRESENCE, settableValues, 40939705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selection, selectionArgs); 40949705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 40959705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO updateCount is not entirely a valid count of updated rows because 2 tables could 40969705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // potentially get updated in this method. 40979705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return updateCount; 40989705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 40999705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 41003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItems(Uri uri, ContentValues values, String selection, 41013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 41023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream items can't be moved to a new raw contact. 41033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItems.RAW_CONTACT_ID); 41043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 41053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream items being updated belong to the account. 41063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 41073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItems(account, selection, selectionArgs); 41083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 41096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream items table. 41106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 41116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 41126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 41133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If there's been no exception, the update should be fine. 41145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().update(Tables.STREAM_ITEMS, values, selection, selectionArgs); 41153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 41163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 41173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItemPhotos(Uri uri, ContentValues values, String selection, 41183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 41193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream item photos can't be moved to a new stream item. 41203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItemPhotos.STREAM_ITEM_ID); 41213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 41223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream item photos being updated belong to the account. 41233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 41243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 41253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 41266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream item 41276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 41286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 41296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 41306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 41316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo (since we're updating, it's valid for the photo to not be present). 41326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(values, true)) { 41336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // If there's been no exception, the update should be fine. 41345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().update(Tables.STREAM_ITEM_PHOTOS, values, selection, 41355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 41366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 41376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 41383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 41393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 41409705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori /** 41419705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori * Build a where clause to select the rows to be updated in status_updates table. 41429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori */ 41439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private String getWhereClauseForStatusUpdatesTable(String selection) { 41449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.setLength(0); 41459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE); 41469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(selection); 41479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(")"); 41489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mSb.toString(); 41499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 41509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 41519705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) { 41529705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 41539705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values, 41549705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS); 41559705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values, 41569705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_TIMESTAMP); 41579705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values, 41589705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_RES_PACKAGE); 41599705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values, 41609705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_LABEL); 41619705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values, 41629705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_ICON); 41639705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 41649705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 41659705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 41669705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForPresenceTable(ContentValues values) { 41679705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 41689705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values, 41699705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.PRESENCE); 4170aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.CHAT_CAPABILITY, values, 4171aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori StatusUpdates.CHAT_CAPABILITY); 41729705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 41739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 41749705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 41755aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int updateGroups(Uri uri, ContentValues values, String selectionWithId, 4176f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 417773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 4178ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 4179ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov 418073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov ContentValues updatedValues; 4181f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter && !values.containsKey(Groups.DIRTY)) { 418273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = mValues; 418373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.clear(); 418473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.putAll(values); 418573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.put(Groups.DIRTY, 1); 418673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } else { 418773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = values; 418873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 418973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 41905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int count = mActiveDb.get().update(Tables.GROUPS, updatedValues, selectionWithId, 41915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 41921a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) { 41931a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 419494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 419543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 419643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO: This will not work for groups that have a data set specified, since the content 419743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // resolver will not be able to request a sync for the right source (unless it is updated 419843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // to key off account with data set). 41996ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi if (updatedValues.containsKey(Groups.SHOULD_SYNC) 42001129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) { 42015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.GROUPS, new String[]{Groups.ACCOUNT_NAME, 4202e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey Groups.ACCOUNT_TYPE}, selectionWithId, selectionArgs, null, 42036ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi null, null); 42046ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountName; 42056ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountType; 42066ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi try { 42076ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi while (c.moveToNext()) { 42086ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountName = c.getString(0); 42096ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountType = c.getString(1); 421024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 42116ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Account account = new Account(accountName, accountType); 4212ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov ContentResolver.requestSync(account, ContactsContract.AUTHORITY, 42136ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi new Bundle()); 42146ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi break; 42156ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 42166ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 42176ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } finally { 42186ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi c.close(); 42196ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 42206ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 422194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana return count; 422294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 422394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 4224b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private int updateSettings(Uri uri, ContentValues values, String selection, 4225b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov String[] selectionArgs) { 42265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final int count = mActiveDb.get().update(Tables.SETTINGS, values, selection, selectionArgs); 42271a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 42281a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 4229e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 4230e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 4231e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 4232e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 4233dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs, 4234dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 42354529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (values.containsKey(RawContacts.CONTACT_ID)) { 42364529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " + 42374529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov "in content values. Contact IDs are assigned automatically"); 42384529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 423973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 424097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 424197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 424297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0"); 424397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 424497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 42454529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov int count = 0; 42465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(Views.RAW_CONTACTS, 424751bf5ea9531b9da72caff607dbdf35fd6f61cbe2Jeff Sharkey new String[] { RawContacts._ID }, selection, 42484529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov selectionArgs, null, null, null); 42494529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov try { 42504529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov while (cursor.moveToNext()) { 42514529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov long rawContactId = cursor.getLong(0); 4252dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateRawContact(rawContactId, values, callerIsSyncAdapter); 42534529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov count++; 42544529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 42554529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } finally { 42564529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov cursor.close(); 42574529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 42584529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 42594529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov return count; 42604529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 42614529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 4262dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContact(long rawContactId, ContentValues values, 4263dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 426496b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker final String selection = RawContacts._ID + " = ?"; 426596b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(rawContactId); 426619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED) 426719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka && values.getAsInteger(RawContacts.DELETED) == 0); 426819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int previousDeleted = 0; 4269ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType = null; 4270ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName = null; 427143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = null; 427219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete) { 42735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, 42745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection, mSelectionArgs1, null, null, null); 427519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka try { 427619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (cursor.moveToFirst()) { 427719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka previousDeleted = cursor.getInt(RawContactsQuery.DELETED); 4278ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE); 4279ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME); 428043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro dataSet = cursor.getString(RawContactsQuery.DATA_SET); 428119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 428219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } finally { 428319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka cursor.close(); 428419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 428519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 428619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT); 428719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 4288f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 42895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int count = mActiveDb.get().update(Tables.RAW_CONTACTS, values, selection, mSelectionArgs1); 42905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count != 0) { 4291f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (values.containsKey(RawContacts.AGGREGATION_MODE)) { 4292f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = values.getAsInteger(RawContacts.AGGREGATION_MODE); 4293f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov 4294f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // As per ContactsContract documentation, changing aggregation mode 4295f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // to DEFAULT should not trigger aggregation 4296f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) { 42975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId, aggregationMode, false); 4298f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 4299f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 4300433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey if (values.containsKey(RawContacts.STARRED)) { 4301dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 4302dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 4303dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana values.getAsLong(RawContacts.STARRED) != 0); 4304dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 43055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateStarred(rawContactId); 4306dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 4307dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then update the 4308dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // favorites group membership based on whether or not this contact is starred. 4309dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // If it is starred, add a group membership, if one doesn't already exist 4310dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // otherwise delete any matching group memberships. 4311dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 43125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro boolean starred = 0 != DatabaseUtils.longForQuery(mActiveDb.get(), 4313dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana SELECTION_STARRED_FROM_RAW_CONTACTS, 4314dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}); 4315dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred); 4316dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4317dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4318dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 4319dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then add a 4320dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // group membership to the group marked as AutoAdd, if any. 4321dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 4322dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 4323433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey } 4324dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 4325285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov if (values.containsKey(RawContacts.SOURCE_ID)) { 43265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateLookupKeyForRawContact(mActiveDb.get(), rawContactId); 4327285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 4328f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.containsKey(RawContacts.NAME_VERIFIED)) { 4329f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 4330f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // If setting NAME_VERIFIED for this raw contact, reset it for all 4331f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // other raw contacts in the same aggregate 4332f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) { 43335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().resetNameVerifiedForOtherRawContacts(rawContactId); 4334f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 43355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateDisplayNameForRawContact(mActiveDb.get(), rawContactId); 4336f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 433719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete && previousDeleted == 1) { 43385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().rawContactInserted(rawContactId, 433943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new AccountWithDataSet(accountName, accountType, dataSet)); 434019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 43415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 43425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return count; 434333b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 434433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 4345321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana private int updateData(Uri uri, ContentValues values, String selection, 4346f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 434720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 434820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 434920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data._ID); 43505ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov mValues.remove(Data.RAW_CONTACT_ID); 435120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 435220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 435320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String packageName = values.getAsString(Data.RES_PACKAGE); 435420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (packageName != null) { 435520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 43565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 435720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 435820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 435997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 436097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 436197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov Data.IS_READ_ONLY + "=0"); 436297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 436397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 4364653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov int count = 0; 436520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4366653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 4367653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // so we don't need to worry about updating data we don't have permission to read. 43685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryLocal(uri, 4369f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro DataRowHandler.DataUpdateQuery.COLUMNS, 43705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection, selectionArgs, null, -1 /* directory ID */); 4371653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov try { 4372653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov while(c.moveToNext()) { 4373f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count += updateData(mValues, c, callerIsSyncAdapter); 437420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 4375653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov } finally { 4376653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov c.close(); 437720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 437820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4379653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return count; 438020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 438120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4382f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) { 4383653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov if (values.size() == 0) { 4384653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return 0; 4385321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 4386653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov 4387f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String mimeType = c.getString(DataRowHandler.DataUpdateQuery.MIMETYPE); 4388a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 4389f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean updated = 43905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro rowHandler.update(mActiveDb.get(), mTransactionContext.get(), values, c, 43915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro callerIsSyncAdapter); 4392f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) { 4393f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 4394a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov } 4395f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return updated ? 1 : 0; 4396321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 4397321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana 43988c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov private int updateContactOptions(ContentValues values, String selection, 4399dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 44008c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov int count = 0; 44015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(Views.CONTACTS, 44025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[] { Contacts._ID }, selection, selectionArgs, null, null, null); 44038c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov try { 44048c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov while (cursor.moveToNext()) { 44058c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov long contactId = cursor.getLong(0); 440624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 4407dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateContactOptions(contactId, values, callerIsSyncAdapter); 44088c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov count++; 44098c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 44108c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } finally { 44118c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov cursor.close(); 44128c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 44138c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 44148c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov return count; 44158c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 44168c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 4417dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateContactOptions(long contactId, ContentValues values, 4418dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 4419d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 44208c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 4421b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 4422d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 4423b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 4424d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 4425b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 4426d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 4427b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 4428d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 4429b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 4430d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.STARRED); 4431d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 4432d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 44338c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.size() == 0) { 4434d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 4435d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 4436d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 44378c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.containsKey(RawContacts.STARRED)) { 4438c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey // Mark dirty when changing starred to trigger sync 44398c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 4440c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey } 4441c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey 44424da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(contactId); 44435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?" 444497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov + " AND " + RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0", mSelectionArgs1); 44458c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 4446dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (mValues.containsKey(RawContacts.STARRED) && !callerIsSyncAdapter) { 44475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(Views.RAW_CONTACTS, 4448dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=?", 4449dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mSelectionArgs1, null, null, null); 4450dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 4451dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (cursor.moveToNext()) { 4452dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana long rawContactId = cursor.getLong(0); 4453dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 4454dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mValues.getAsLong(RawContacts.STARRED) != 0); 4455dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4456dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 4457dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana cursor.close(); 4458dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4459dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4460dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 44618c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // Copy changeable values to prevent automatically managed fields from 44628c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // being explicitly updated by clients. 44638c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 4464b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 44658c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 4466b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 44678c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 4468b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 44698c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 4470b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 44718c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 4472b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 44738c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.STARRED); 44748c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 44755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int rslt = mActiveDb.get().update(Tables.CONTACTS, mValues, Contacts._ID + "=?", 44765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mSelectionArgs1); 44776e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori 44789b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori if (values.containsKey(Contacts.LAST_TIME_CONTACTED) && 44799b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori !values.containsKey(Contacts.TIMES_CONTACTED)) { 44805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 44815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 44829b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori } 44839b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori return rslt; 4484f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 4485d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 4486127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 4487127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 44880c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1); 44890c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2); 449080c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 4491ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId1; 4492ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId2; 44930c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (rcId1 < rcId2) { 44940c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId1; 44950c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId2; 44960c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 44970c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId1; 44980c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId2; 4499b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4500127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 45010c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 45024da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[0] = String.valueOf(rawContactId1); 45034da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[1] = String.valueOf(rawContactId2); 45040c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, 45054da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov AggregationExceptions.RAW_CONTACT_ID1 + "=? AND " 45064da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2); 45070c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 45086bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 45096bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 45100c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 45110c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 45120c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 45130c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues); 4514127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 4515127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 45165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().invalidateAggregationExceptionCache(); 45175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId1, 451869cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 45195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId2, 452069cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 4521dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov 45225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateContact(mTransactionContext.get(), db, rawContactId1); 45235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateContact(mTransactionContext.get(), db, rawContactId2); 4524127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 4525127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 4526127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 4527127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 4528b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4529b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 453070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong public void onAccountsUpdated(Account[] accounts) { 4531bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 45323826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 45333826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4534bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected boolean updateAccountsInBackground(Account[] accounts) { 4535f8536aaa7a52b9a7a353bc54e158becdbe79ec87Bai Tao // TODO : Check the unit test. 4536e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov boolean accountsChanged = false; 45375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 45385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(db); 45395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.beginTransaction(); 454070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong try { 454143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> existingAccountsWithDataSets = 454243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro findValidAccountsWithDataSets(Tables.ACCOUNTS); 4543743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov 454443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add a row to the ACCOUNTS table (with no data set) for each new account. 4545743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov for (Account account : accounts) { 454643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = new AccountWithDataSet( 454743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro account.name, account.type, null); 454843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!existingAccountsWithDataSets.contains(accountWithDataSet)) { 4549e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 455043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 455143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add an account entry with an empty data set to match the account. 45525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 455343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ", " + RawContacts.ACCOUNT_TYPE + ", " + RawContacts.DATA_SET 455443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ") VALUES (?, ?, ?)", 455543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new String[] { 455643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 455743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 455843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 455943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }); 4560743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 4561743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 456248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 456343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Check each of the existing sub-accounts against the account list. If the owning 456443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // account no longer exists, the sub-account and all its data should be deleted. 456543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro List<AccountWithDataSet> accountsWithDataSetsToDelete = 456643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new ArrayList<AccountWithDataSet>(); 456743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro List<Account> accountList = Arrays.asList(accounts); 456843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : existingAccountsWithDataSets) { 456943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Account owningAccount = new Account( 457043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), accountWithDataSet.getAccountType()); 457143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!accountList.contains(owningAccount)) { 457243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsWithDataSetsToDelete.add(accountWithDataSet); 457343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 457470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 457570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong 457643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!accountsWithDataSetsToDelete.isEmpty()) { 4577e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 457843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : accountsWithDataSetsToDelete) { 457943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Log.d(TAG, "removing data for removed account " + accountWithDataSet); 458043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String[] accountParams = new String[] { 458143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 458243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType() 458343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }; 458443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String[] accountWithDataSetParams = accountWithDataSet.getDataSet() == null 458543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ? accountParams 458643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro : new String[] { 458743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 458843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 458943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 459043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }; 459143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String groupsDataSetClause = " AND " + Groups.DATA_SET 459243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + (accountWithDataSet.getDataSet() == null ? " IS NULL" : " = ?"); 459343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String rawContactsDataSetClause = " AND " + RawContacts.DATA_SET 459443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + (accountWithDataSet.getDataSet() == null ? " IS NULL" : " = ?"); 4595f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro String settingsDataSetClause = " AND " + Settings.DATA_SET 4596f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + (accountWithDataSet.getDataSet() == null ? " IS NULL" : " = ?"); 459743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 45985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4599e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.GROUPS + 4600e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Groups.ACCOUNT_NAME + " = ?" + 460143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Groups.ACCOUNT_TYPE + " = ?" + 460243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro groupsDataSetClause, accountWithDataSetParams); 46035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4604e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.PRESENCE + 4605e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" + 4606e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "SELECT " + RawContacts._ID + 4607e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 4608e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 460943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + " = ?" + 461043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause + ")", accountWithDataSetParams); 46115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4612c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro "DELETE FROM " + Tables.STREAM_ITEM_PHOTOS + 4613c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro " WHERE " + StreamItemPhotos.STREAM_ITEM_ID + " IN (" + 4614c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro "SELECT " + StreamItems._ID + 4615c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro " FROM " + Tables.STREAM_ITEMS + 4616c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro " WHERE " + StreamItems.RAW_CONTACT_ID + " IN (" + 4617c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro "SELECT " + RawContacts._ID + 4618c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro " FROM " + Tables.RAW_CONTACTS + 4619c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 4620c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + " = ?" + 4621c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro rawContactsDataSetClause + "))", 4622c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro accountWithDataSetParams); 4623c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro db.execSQL( 4624c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro "DELETE FROM " + Tables.STREAM_ITEMS + 4625c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro " WHERE " + StreamItems.RAW_CONTACT_ID + " IN (" + 4626c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro "SELECT " + RawContacts._ID + 4627c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro " FROM " + Tables.RAW_CONTACTS + 4628c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 4629c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + " = ?" + 4630c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro rawContactsDataSetClause + ")", 4631c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro accountWithDataSetParams); 4632c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro db.execSQL( 4633e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.RAW_CONTACTS + 4634e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 463543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + " = ?" + 463643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause, accountWithDataSetParams); 46375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4638e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.SETTINGS + 4639e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Settings.ACCOUNT_NAME + " = ?" + 4640f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro " AND " + Settings.ACCOUNT_TYPE + " = ?" + 4641f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro settingsDataSetClause, accountWithDataSetParams); 46425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4643e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.ACCOUNTS + 4644e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + "=?" + 464543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + "=?" + 464643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause, accountWithDataSetParams); 46475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4648d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov "DELETE FROM " + Tables.DIRECTORIES + 4649d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov " WHERE " + Directory.ACCOUNT_NAME + "=?" + 465043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Directory.ACCOUNT_TYPE + "=?", accountParams); 46514458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov resetDirectoryCache(); 4652e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 4653e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov 465433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // Find all aggregated contacts that used to contain the raw contacts 465533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // we have just deleted and see if they are still referencing the deleted 4656e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov // names or photos. If so, fix up those contacts. 465733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov HashSet<Long> orphanContactIds = Sets.newHashSet(); 46585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = db.rawQuery("SELECT " + Contacts._ID + 465933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " FROM " + Tables.CONTACTS + 466033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " WHERE (" + Contacts.NAME_RAW_CONTACT_ID + " NOT NULL AND " + 466169cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov Contacts.NAME_RAW_CONTACT_ID + " NOT IN " + 466269cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + RawContacts._ID + 466369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + "))" + 466433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " OR (" + Contacts.PHOTO_ID + " NOT NULL AND " + 466533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Contacts.PHOTO_ID + " NOT IN " + 466669cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + Data._ID + 466769cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.DATA + "))", null); 466833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov try { 466933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov while (cursor.moveToNext()) { 467033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov orphanContactIds.add(cursor.getLong(0)); 467133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 467233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } finally { 467333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov cursor.close(); 467433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 467533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 467633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov for (Long contactId : orphanContactIds) { 46775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateAggregateData(mTransactionContext.get(), contactId); 467833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 46795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().updateAllVisible(); 4680bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 468133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 468233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 468343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Now that we've done the account-based additions and subtractions from the Accounts 468443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // table, check for raw contacts that have been added with a data set and add Accounts 468543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // entries for those if necessary. 468643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro existingAccountsWithDataSets = findValidAccountsWithDataSets(Tables.ACCOUNTS); 468743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> rawContactAccountsWithDataSets = 468843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro findValidAccountsWithDataSets(Tables.RAW_CONTACTS); 468943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactAccountsWithDataSets.removeAll(existingAccountsWithDataSets); 469043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 469143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Any remaining raw contact sub-accounts need to be added to the Accounts table. 469243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : rawContactAccountsWithDataSets) { 469343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsChanged = true; 469443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 469543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add an account entry to match the raw contact. 46965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 469743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ", " + RawContacts.ACCOUNT_TYPE + ", " + RawContacts.DATA_SET 469843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ") VALUES (?, ?, ?)", 469943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new String[] { 470043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 470143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 470243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 470343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }); 470443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 470543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 4706e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov if (accountsChanged) { 470743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO: Should sync state take data set into consideration? 47085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getSyncState().onAccountsChanged(db, accounts); 4709e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 47105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.setTransactionSuccessful(); 471170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } finally { 47125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.endTransaction(); 471370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 471473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.clear(); 47153826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 47163826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (accountsChanged) { 47173826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateContactsAccountCount(accounts); 47183826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 47193826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 47203826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4721afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov return accountsChanged; 472270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 4723619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 47243826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateContactsAccountCount(Account[] accounts) { 47253826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov int count = 0; 47263826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov for (Account account : accounts) { 47273826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (isContactsAccount(account)) { 47283826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov count++; 47293826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 47303826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 47313826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mContactsAccountCount = count; 47323826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 47333826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 47343826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov protected boolean isContactsAccount(Account account) { 47353826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov final IContentService cs = ContentResolver.getContentService(); 47363826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov try { 47373826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0; 47383826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } catch (RemoteException e) { 47393826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov Log.e(TAG, "Cannot obtain sync flag for account: " + account, e); 47403826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return false; 47413826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 47423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 47433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 474472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void onPackageChanged(String packageName) { 4745bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_DIRECTORIES, packageName); 4746d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4747d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4748619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 474943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Finds all distinct account types and data sets present in the specified table. 4750627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov */ 475143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private Set<AccountWithDataSet> findValidAccountsWithDataSets(String table) { 475243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> accountsWithDataSets = new HashSet<AccountWithDataSet>(); 47535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().rawQuery( 475443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro "SELECT DISTINCT " + RawContacts.ACCOUNT_NAME + "," + RawContacts.ACCOUNT_TYPE + 475543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro "," + RawContacts.DATA_SET + 475643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " FROM " + table, null); 4757627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 4758627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov while (c.moveToNext()) { 475991abbc9f691297594262d1f2d79acb744a66712cDave Santoro if (!c.isNull(0) && !c.isNull(1)) { 476043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsWithDataSets.add( 476143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new AccountWithDataSet(c.getString(0), c.getString(1), c.getString(2))); 4762627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4763627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4764627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } finally { 4765627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov c.close(); 4766627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 476743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro return accountsWithDataSets; 4768627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4769627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov 47704f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 47714f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 47724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 477315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 477415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mReadAccessLatch); 477515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 477636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 477736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamReadPermission(uri); 477836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 47795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Query the profile DB if appropriate. 47805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 47815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 47825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileProvider.query(uri, projection, selection, selectionArgs, sortOrder); 47835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 47845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 47855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Otherwise proceed with a normal query against the contacts DB. 47865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 47875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(mContactsHelper.getReadableDatabase()); 4788d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY); 4789385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directory == null) { 4790b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return addSnippetExtrasToCursor(uri, 47915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1)); 4792385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directory.equals("0")) { 4793b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return addSnippetExtrasToCursor(uri, 47943716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 47955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Directory.DEFAULT)); 4796d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } else if (directory.equals("1")) { 4797b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return addSnippetExtrasToCursor(uri, 47983716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 47995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Directory.LOCAL_INVISIBLE)); 4800d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4801d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4802d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov DirectoryInfo directoryInfo = getDirectoryAuthority(directory); 4803d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo == null) { 4804a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov Log.e(TAG, "Invalid directory ID: " + uri); 4805a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov return null; 4806d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4807d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4808d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Builder builder = new Uri.Builder(); 4809d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.scheme(ContentResolver.SCHEME_CONTENT); 4810d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.authority(directoryInfo.authority); 4811d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.encodedPath(uri.getEncodedPath()); 4812d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountName != null) { 4813d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName); 4814d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4815d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountType != null) { 4816d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType); 4817d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 48182e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 48192e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limit = getLimit(uri); 48202e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov if (limit != null) { 48212e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit); 48222e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov } 48232e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 4824d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Uri directoryUri = builder.build(); 482509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 482609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov if (projection == null) { 482709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov projection = getDefaultProjection(uri); 482809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 482909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 4830332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov Cursor cursor = getContext().getContentResolver().query(directoryUri, projection, selection, 4831d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov selectionArgs, sortOrder); 48326ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 48336ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (cursor == null) { 48346ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 48356ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 48366ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 4837547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro CrossProcessCursor crossProcessCursor = getCrossProcessCursor(cursor); 4838547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (crossProcessCursor != null) { 4839b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return addSnippetExtrasToCursor(uri, cursor); 4840547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } else { 4841b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return matrixCursorFromCursor(addSnippetExtrasToCursor(uri, cursor)); 4842547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 48433716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 48443716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4845b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private Cursor addSnippetExtrasToCursor(Uri uri, Cursor cursor) { 4846547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 4847547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro // If the cursor doesn't contain a snippet column, don't bother wrapping it. 4848547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (cursor.getColumnIndex(SearchSnippetColumns.SNIPPET) < 0) { 4849b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return cursor; 4850547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 4851547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 48523716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Parse out snippet arguments for use when snippets are retrieved from the cursor. 48533716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String[] args = null; 48543716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String snippetArgs = 48553716f1447ceb21180d1301790eabd8b9453f486dDave Santoro getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 48563716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (snippetArgs != null) { 48573716f1447ceb21180d1301790eabd8b9453f486dDave Santoro args = snippetArgs.split(","); 48583716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 48593716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 48603716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String query = uri.getLastPathSegment(); 48613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String startMatch = args != null && args.length > 0 ? args[0] 48623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_START_MATCH; 48633716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String endMatch = args != null && args.length > 1 ? args[1] 48643716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_END_MATCH; 48653716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String ellipsis = args != null && args.length > 2 ? args[2] 48663716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_ELLIPSIS; 48673716f1447ceb21180d1301790eabd8b9453f486dDave Santoro int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 48683716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 48693716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4870b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson // Snippet data is needed for the snippeting on the client side, so store it in the cursor 4871b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (cursor instanceof AbstractCursor && deferredSnippetingRequested(uri)){ 4872b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle oldExtras = cursor.getExtras(); 4873b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle extras = new Bundle(); 4874b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (oldExtras != null) { 4875b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putAll(oldExtras); 4876b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 4877b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putString(ContactsContract.DEFERRED_SNIPPETING_QUERY, query); 4878b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 4879b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson ((AbstractCursor) cursor).setExtras(extras); 48805517770250b3afa4fd88b6869c3244680821d222Dave Santoro } 4881b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return cursor; 4882b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 4883b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 4884b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private Cursor addDeferredSnippetingExtra(Cursor cursor) { 4885b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (cursor instanceof AbstractCursor){ 4886b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle oldExtras = cursor.getExtras(); 4887b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle extras = new Bundle(); 4888b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (oldExtras != null) { 4889b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putAll(oldExtras); 4890b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 4891b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putBoolean(ContactsContract.DEFERRED_SNIPPETING, true); 4892b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson ((AbstractCursor) cursor).setExtras(extras); 4893b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 4894b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return cursor; 48956ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 48966ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 48976ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov private CrossProcessCursor getCrossProcessCursor(Cursor cursor) { 48986ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov Cursor c = cursor; 48996ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (c instanceof CrossProcessCursor) { 49006ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return (CrossProcessCursor) c; 49016ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else if (c instanceof CursorWindow) { 49026ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return getCrossProcessCursor(((CursorWrapper) c).getWrappedCursor()); 49036ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else { 49046ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 49056ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 49066ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 49076ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 49086ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov public MatrixCursor matrixCursorFromCursor(Cursor cursor) { 49096ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); 49106ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov int numColumns = cursor.getColumnCount(); 49116ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov String data[] = new String[numColumns]; 49126ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov cursor.moveToPosition(-1); 49136ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov while (cursor.moveToNext()) { 49146ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov for (int i = 0; i < numColumns; i++) { 49156ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov data[i] = cursor.getString(i); 49166ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 49176ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov newCursor.addRow(data); 4918332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov } 49196ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return newCursor; 4920d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4921d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4922d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final class DirectoryQuery { 4923d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final String[] COLUMNS = new String[] { 4924d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory._ID, 4925d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.DIRECTORY_AUTHORITY, 4926d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_NAME, 4927d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_TYPE 4928d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov }; 4929d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4930d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int DIRECTORY_ID = 0; 4931d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int AUTHORITY = 1; 4932d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_NAME = 2; 4933d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_TYPE = 3; 4934d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4935d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4936d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 4937d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Reads and caches directory information for the database. 4938d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 4939d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private DirectoryInfo getDirectoryAuthority(String directoryId) { 49404458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized (mDirectoryCache) { 49414458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov if (!mDirectoryCacheValid) { 49424458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.clear(); 49435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mDbHelper.get().getReadableDatabase(); 494449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Cursor cursor = db.query(Tables.DIRECTORIES, 49454458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryQuery.COLUMNS, 49464458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov null, null, null, null, null); 49474458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov try { 49484458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov while (cursor.moveToNext()) { 49494458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryInfo info = new DirectoryInfo(); 49504458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov String id = cursor.getString(DirectoryQuery.DIRECTORY_ID); 49514458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.authority = cursor.getString(DirectoryQuery.AUTHORITY); 49524458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME); 49534458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE); 49544458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.put(id, info); 49554458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 49564458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } finally { 49574458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov cursor.close(); 4958d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 49594458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = true; 4960d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4961d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 49624458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov return mDirectoryCache.get(directoryId); 49634458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 4964d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4965d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 496672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void resetDirectoryCache() { 49674458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized(mDirectoryCache) { 49684458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = false; 49694458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 497072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 497172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 49725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro protected Cursor queryLocal(Uri uri, String[] projection, String selection, 49735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String[] selectionArgs, String sortOrder, long directoryId) { 4974bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 4975bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov Log.v(TAG, "query: " + uri); 4976bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov } 49770b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov 49785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 49795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 4980078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getReadableDatabase()); 49815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 498235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4983d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 49841f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 4985c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov String limit = getLimit(uri); 4986b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson boolean snippetDeferred = false; 4987c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 49882ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // The expression used in bundleLetterCountExtras() to get count. 49892ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki String addressBookIndexerCountExpression = null; 49902ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki 4991a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 49924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 499335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 49945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 49955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().query(mActiveDb.get(), projection, selection, 49965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs, sortOrder); 499735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4998d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 4999763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 50004b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki appendLocalDirectorySelectionIfNeeded(qb, directoryId); 5001619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 5002619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 5003619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 5004d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 50054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 5006763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 50074da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 50084da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 50096bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 50106bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 50116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 50125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP: 50135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP_ID: { 50145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 50155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = pathSegments.size(); 50165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount < 3) { 50175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 5018fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 50195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 5020a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 50215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String lookupKey = pathSegments.get(2); 50225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount == 4) { 50235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 50245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 5025763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 5026a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 50275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 5028a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 5029a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 5030a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 50315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return c; 50325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 50335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 50345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 5035763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 50364da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 50375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String.valueOf(lookupContactIdByLookupKey(mActiveDb.get(), lookupKey))); 50384da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 50395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 50405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 50415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 50422149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_DATA: 5043bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_DATA: 5044bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_PHOTO: 5045bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_PHOTO: { 50462149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 50472149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov int segmentCount = pathSegments.size(); 50482149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount < 4) { 50495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 50502149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov "Missing a lookup key", uri)); 50512149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 50522149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov String lookupKey = pathSegments.get(2); 50532149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount == 5) { 50542149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 50552149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 50562149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(lookupQb, uri, projection, false); 5057bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (match == CONTACTS_LOOKUP_PHOTO || match == CONTACTS_LOOKUP_ID_PHOTO) { 5058bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 5059bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 5060a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 50615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 5062a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 5063a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Data.CONTACT_ID, contactId, Data.LOOKUP_KEY, lookupKey); 5064a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 50652149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov return c; 50662149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 50672149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 50682149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov // TODO see if the contact exists but has no data rows (rare) 50692149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 50702149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 50712149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 50732149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 507424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 5075bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (match == CONTACTS_LOOKUP_PHOTO || match == CONTACTS_LOOKUP_ID_PHOTO) { 5076bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 5077bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 50782149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov qb.appendWhere(" AND " + Data.CONTACT_ID + "=?"); 50792149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov break; 50802149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 50812149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 50823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_ID_STREAM_ITEMS: { 50833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(uri.getPathSegments().get(1)); 50843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 50853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 5086af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann qb.appendWhere(StreamItems.CONTACT_ID + "=?"); 50873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 50883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 50893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 50903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_STREAM_ITEMS: 50913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_ID_STREAM_ITEMS: { 50923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<String> pathSegments = uri.getPathSegments(); 50933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int segmentCount = pathSegments.size(); 50943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount < 4) { 50955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 50963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann "Missing a lookup key", uri)); 50973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 50983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String lookupKey = pathSegments.get(2); 50993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount == 5) { 51003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(pathSegments.get(3)); 51013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 51023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(lookupQb); 51035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 51043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann projection, selection, selectionArgs, sortOrder, groupBy, limit, 5105af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann StreamItems.CONTACT_ID, contactId, 5106af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann StreamItems.CONTACT_LOOKUP_KEY, lookupKey); 51073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c != null) { 51083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return c; 51093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 51103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 51113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 51123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 51135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 51143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 51153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContacts.CONTACT_ID + "=?"); 51163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 51173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 51183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 5119f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: { 512042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKey = Uri.encode(uri.getPathSegments().get(2)); 51215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 5122ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 5123f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey qb.setProjectionMap(sContactsVCardProjectionMap); 51244da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 512524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 51264da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 5127f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey break; 5128f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey } 5129f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey 513042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 513142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); 513242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann String currentDateString = dateFormat.format(new Date()).toString(); 51335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().rawQuery( 513442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann "SELECT" + 513542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " 'vcards_' || ? || '.vcf' AS " + OpenableColumns.DISPLAY_NAME + "," + 513642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " NULL AS " + OpenableColumns.SIZE, 513742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann new String[] { currentDateString }); 513842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 513942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 5140ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_FILTER: { 5141916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov String filterParam = ""; 5142b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson boolean deferredSnipRequested = deferredSnippetingRequested(uri); 5143ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 5144916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov filterParam = uri.getLastPathSegment(); 5145ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 51467ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov setTablesAndProjectionMapForContactsWithSnippet( 5147b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson qb, uri, projection, filterParam, directoryId, 5148b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson deferredSnipRequested); 5149b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson snippetDeferred = isSingleWordQuery(filterParam) && 5150b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson deferredSnipRequested && snippetNeeded(projection); 5151ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5152ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5153ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 5154ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT_FILTER: 5155ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT: { 51562f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Basically the resultant SQL should look like this: 51572f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing starred items) 51582f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 51592f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing frequently contacted items) 51602f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // ORDER BY ... 51612f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 51622f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final boolean phoneOnly = readBooleanQueryParameter( 51632f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa uri, ContactsContract.STREQUENT_PHONE_ONLY, false); 51642f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (match == CONTACTS_STREQUENT_FILTER && uri.getPathSegments().size() > 3) { 51654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 51664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5167e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(Contacts._ID + " IN "); 51685e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov appendContactFilterAsNestedQuery(sb, filterParam); 51692f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection = DbQueryUtils.concatenateClauses(selection, sb.toString()); 51704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 51714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 51722f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] subProjection = null; 51735e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection != null) { 51742f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa subProjection = appendProjectionArg(projection, TIMES_USED_SORT_COLUMN); 51755e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 51765e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 51774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov // Build the first query for starred 51784928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 51794928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(phoneOnly ? 51804928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa sStrequentPhoneOnlyStarredProjectionMap 51814928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa : sStrequentStarredProjectionMap); 51829dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa if (phoneOnly) { 51835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(DbQueryUtils.concatenateClauses( 51845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection, Contacts.HAS_PHONE_NUMBER + "=1")); 51859dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa } 51862f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 51872f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String starredQuery = qb.buildQuery(subProjection, 518824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Contacts.STARRED + "=1", Contacts._ID, null, null, null); 5189d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 51902f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Reset the builder. 5191d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 51922f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 51934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 51944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // Build the second query for frequent part. 51954928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final String frequentQuery; 51964928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (phoneOnly) { 51974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final StringBuilder tableBuilder = new StringBuilder(); 51984928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // In phone only mode, we need to look at view_data instead of 51994928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // contacts/raw_contacts to obtain actual phone numbers. One problem is that 52004928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data is much larger than view_contacts, so our query might become much 52014928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // slower. 52024928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // 52034928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // To avoid the possible slow down, we start from data usage table and join 52044928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data to the table, assuming data usage table is quite smaller than 52054928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // data rows (almost always it should be), and we don't want any phone 52064928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // numbers not used by the user. This way sqlite is able to drop a number of 52074928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // rows in view_data in the early stage of data lookup. 52084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa tableBuilder.append(Tables.DATA_USAGE_STAT 52094928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " INNER JOIN " + Views.DATA + " " + Tables.DATA 52104928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" 52114928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataColumns.CONCRETE_ID + " AND " 52124928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" 52134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT_CALL + ")"); 52144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactPresenceJoin(tableBuilder, projection, RawContacts.CONTACT_ID); 52154928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactStatusUpdateJoin(tableBuilder, projection, 52164928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa ContactsColumns.LAST_STATUS_UPDATE_ID); 52174928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 52184928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setTables(tableBuilder.toString()); 52194928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentPhoneOnlyFrequentProjectionMap); 52204928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 52214928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 52224928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.STARRED + "=0 OR " + Contacts.STARRED + " IS NULL", 52234928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa MimetypesColumns.MIMETYPE + " IN (" 52244928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + Phone.CONTENT_ITEM_TYPE + "', " 52254928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + SipAddress.CONTENT_ITEM_TYPE + "')")); 52264928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, null, null, null, null, null); 52274928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } else { 52284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 52294928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 52304928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 52314928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 52325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "(" + Contacts.STARRED + " =0 OR " + Contacts.STARRED + " IS NULL)")); 52334928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, 52344928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa null, Contacts._ID, null, null, null); 52354928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } 5236d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 5237d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 52382f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String unionQuery = 52392f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, 52402f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa STREQUENT_ORDER_BY, STREQUENT_LIMIT); 52412f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 52422f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Here, we need to use selection / selectionArgs (supplied from users) "twice", 52432f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // as we want them both for starred items and for frequently contacted items. 52442f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // 52452f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // e.g. if the user specify selection = "starred =?" and selectionArgs = "0", 52462f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // the resultant SQL should be like: 52472f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 52482f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 52492f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 52502f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] doubledSelectionArgs = null; 52512f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (selectionArgs != null) { 52522f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final int length = selectionArgs.length; 52532f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa doubledSelectionArgs = new String[length * 2]; 52547d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, 0, length); 52557d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, length, length); 52562f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 52572f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 52585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().rawQuery(unionQuery, doubledSelectionArgs); 52592f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (cursor != null) { 52602f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa cursor.setNotificationUri(getContext().getContentResolver(), 5261d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 5262d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 52632f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa return cursor; 5264d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 5265d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 526645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa case CONTACTS_FREQUENT: { 526745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 526845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 526945ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa groupBy = Contacts._ID; 527045ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa if (!TextUtils.isEmpty(sortOrder)) { 527145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY + ", " + sortOrder; 527245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } else { 527345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY; 527445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 527545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa break; 527645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 527745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 5278ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_GROUP: { 5279763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 5280b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 528171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 52827cf50494501938f175d288077145acf49da8f171Daniel Lehmann String groupMimeTypeId = String.valueOf( 52837cf50494501938f175d288077145acf49da8f171Daniel Lehmann mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 52844a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 52857cf50494501938f175d288077145acf49da8f171Daniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, groupMimeTypeId); 5286b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 5287b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 5288b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 5289b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 529024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 529124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 529224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 529324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 529424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 529524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: { 529624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForEntities(qb, uri, projection); 529724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 529824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 529924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 530024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: { 5301ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 530224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.setProjectionMap(sContactsVCardProjectionMap); 530324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 530424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 530524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5306a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_DATA: { 53074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 530882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 53094da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 53104da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 53116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 53126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 531300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 5314a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 53153653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 531682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 53174da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 53184da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 53193653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 53203653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov break; 53213653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov } 53223653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 5323a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_ENTITIES: { 5324a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 5325a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 5326a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 5327a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 5328a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 5329a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5330a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5331a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ENTITIES: 5332a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ID_ENTITIES: { 5333a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 5334a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov int segmentCount = pathSegments.size(); 5335a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount < 4) { 53365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 5337a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov "Missing a lookup key", uri)); 5338a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5339a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lookupKey = pathSegments.get(2); 5340a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount == 5) { 5341a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 5342a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 5343a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(lookupQb, uri, projection); 5344a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 5345a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 53465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 5347a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 5348a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.CONTACT_ID, contactId, 5349a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.LOOKUP_KEY, lookupKey); 5350a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 5351a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5352a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5353a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5354a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5355a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 5356a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 53575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String.valueOf(lookupContactIdByLookupKey(mActiveDb.get(), lookupKey))); 5358a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + Contacts.Entity.CONTACT_ID + "=?"); 5359a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 5360a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5361a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 53623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 53633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 53643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 53653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 53663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 53673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 53683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 53693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 53709b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann qb.appendWhere(StreamItems._ID + "=?"); 53713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 53723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 53733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 53743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_LIMIT: { 53756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro MatrixCursor cursor = new MatrixCursor(new String[]{StreamItems.MAX_ITEMS}, 1); 53766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro cursor.addRow(new Object[]{MAX_STREAM_ITEMS_PER_RAW_CONTACT}); 53773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return cursor; 53783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 53793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 53803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 53813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 53823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 53833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 53843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 53853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 53863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 53873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 53883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 53893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?"); 53903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 53913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 53923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 53933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 53943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 53953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 53963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 53973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemPhotoId); 53983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 53993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=? AND " + 54003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=?"); 54013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 54023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 54033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 5404f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case PHOTO_DIMENSIONS: { 5405f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro MatrixCursor cursor = new MatrixCursor( 5406f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM}, 5407f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1); 5408f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cursor.addRow(new Object[]{mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim}); 5409f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return cursor; 5410f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 5411f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 54124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case PHONES: { 541382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 54147cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + "=" + 54157cf50494501938f175d288077145acf49da8f171Daniel Lehmann mDbHelper.get().getMimeTypeIdForPhone()); 54162ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki 54172ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // Dedupe phone numbers per contact. 5418cf55cbe8932f620484a3634d13ecc116c32fdc99Daisuke Miyakawa groupBy = RawContacts.CONTACT_ID + ", " + Data.DATA1; 54192ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki 54202ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // In this case, because we dedupe phone numbers, the address book indexer needs 54212ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // to take it into account too. (Otherwise headers will appear in wrong positions.) 54222ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // So use count(distinct pair(CONTACT_ID, PHONE NUMBER)) instead of count(*). 54232ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // But because there's no such thing as pair() on sqlite, we use 54242ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // CONTACT_ID || ',' || PHONE NUMBER instead. 54252ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // This only slows down the query by 14% with 10,000 contacts. 54262ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki addressBookIndexerCountExpression = "DISTINCT " 54272ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki + RawContacts.CONTACT_ID + "||','||" + Data.DATA1; 54282815f58f72f109790585931f601a63ddc02536a5Evan Millar break; 54292815f58f72f109790585931f601a63ddc02536a5Evan Millar } 54302815f58f72f109790585931f601a63ddc02536a5Evan Millar 543148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: { 543282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 54334da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 54347cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 54357cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForPhone()); 54364da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 543748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 543848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 543948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 5440ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES_FILTER: { 544146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 544246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 544346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 544446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_CALL; 544546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 544646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 54477cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 54487cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForPhone()); 5449ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 54504a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 54514a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5452a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(" AND ("); 54535e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 545445d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov boolean hasCondition = false; 54555e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov boolean orNeeded = false; 54565e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov String normalizedName = NameNormalizer.normalize(filterParam); 54575e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (normalizedName.length() > 0) { 5458155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(Data.RAW_CONTACT_ID + " IN " + 5459155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 5460155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 5461155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 5462155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 5463155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 5464155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 54652352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 5466155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 54675e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov orNeeded = true; 546845d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 54695e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 54705e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 5471892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String number = PhoneNumberUtils.normalizeNumber(filterParam); 5472892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (!TextUtils.isEmpty(number)) { 54735e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (orNeeded) { 54745e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(" OR "); 54755e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 54765e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(Data._ID + 5477892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID 5478892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " FROM " + Tables.PHONE_LOOKUP 5479892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 5480892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append(number); 5481892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append("%')"); 548245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 548345d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov } 548445d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov 548545d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov if (!hasCondition) { 548645d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // If it is neither a phone number nor a name, the query should return 548745d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // an empty cursor. Let's ensure that. 548845d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov sb.append("0"); 54895e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 54905e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 5491a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 5492ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 549358567abca253f1efa2db5c39e17e42dca589e916Daisuke Miyakawa groupBy = "(CASE WHEN " + PhoneColumns.NORMALIZED_NUMBER 549458567abca253f1efa2db5c39e17e42dca589e916Daisuke Miyakawa + " IS NOT NULL THEN " + PhoneColumns.NORMALIZED_NUMBER 549558567abca253f1efa2db5c39e17e42dca589e916Daisuke Miyakawa + " ELSE " + Phone.NUMBER + " END), " + RawContacts.CONTACT_ID; 5496a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 549746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 549846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 549946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + PHONE_FILTER_SORT_ORDER; 550046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 550146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = PHONE_FILTER_SORT_ORDER; 550246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 5503a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 5504ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5505ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5506ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 55074a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case EMAILS: { 550882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 55097cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 55107cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForEmail()); 55114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov break; 55124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 55134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 551448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: { 551582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 55164da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 55177cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 55187cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForEmail() 55194da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + " AND " + Data._ID + "=?"); 552048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 552148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 552248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 55235e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_LOOKUP: { 552482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 55257cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 55267cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForEmail()); 55274a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov if (uri.getPathSegments().size() > 2) { 552808768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String email = uri.getLastPathSegment(); 55295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String address = mDbHelper.get().extractAddressFromEmailAddress(email); 553008768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, address); 553108768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)"); 55324a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 5533ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5534ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5535ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 55365e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_FILTER: { 553746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 553846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 553946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 554046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT; 554146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 554246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 554307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov String filterParam = null; 55447d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa 554507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 554607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = uri.getLastPathSegment(); 554707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (TextUtils.isEmpty(filterParam)) { 554807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = null; 554907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 555007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 55515e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 555207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (filterParam == null) { 555307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov // If the filter is unspecified, return nothing 555407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov qb.appendWhere(" AND 0"); 555507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } else { 555607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov StringBuilder sb = new StringBuilder(); 555707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append(" AND " + Data._ID + " IN ("); 555807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append( 555907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov "SELECT " + Data._ID + 556007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov " FROM " + Tables.DATA + 55612a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov " WHERE " + DataColumns.MIMETYPE_ID + "="); 55625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro sb.append(mDbHelper.get().getMimeTypeIdForEmail()); 55632a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(" AND " + Data.DATA1 + " LIKE "); 556407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 556520938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov if (!filterParam.contains("@")) { 5566155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append( 5567155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " UNION SELECT " + Data._ID + 5568155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.DATA + 5569155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE +" + DataColumns.MIMETYPE_ID + "="); 55705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro sb.append(mDbHelper.get().getMimeTypeIdForEmail()); 5571155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(" AND " + Data.RAW_CONTACT_ID + " IN " + 5572155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 5573155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 5574155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 5575155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 5576155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 5577155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 55782352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 5579155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 55805e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 55815e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 5582a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 55835e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 55845e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = Email.DATA + "," + RawContacts.CONTACT_ID; 5585a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 558646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 558746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 558846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + EMAIL_FILTER_SORT_ORDER; 55897d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } else { 55907d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa sortOrder = EMAIL_FILTER_SORT_ORDER; 55917d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } 5592a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 55935e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov break; 55945e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 55955e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 5596ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 559782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 55987cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 55997cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForStructuredPostal()); 5600ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5601ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5602ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 560348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 560482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 56054da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 56067cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 56077cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForStructuredPostal()); 56084da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 560948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 561048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 561148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 5612d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS: 5613d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS: { 5614763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 56154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 56164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 56174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 5618d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS_ID: 5619d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID: { 56205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 5621763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 56224da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 56234da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 56244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 56254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 56264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 5627d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS_DATA: 5628d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 5629d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro int segment = match == RAW_CONTACTS_DATA ? 1 : 2; 5630d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(segment)); 563182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 56324da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 56334da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?"); 563424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 563524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 563624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 56373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 56383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 56393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 56403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 56413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=?"); 56423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 56433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 564424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 564582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro case RAW_CONTACTS_ID_STREAM_ITEMS_ID: { 564682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 564782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro long streamItemId = Long.parseLong(uri.getPathSegments().get(3)); 564882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro setTablesAndProjectionMapForStreamItems(qb); 564982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(streamItemId)); 5650c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 565182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=? AND " + 565282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems._ID + "=?"); 565382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro break; 565482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 565582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 565624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_ENTITIES: { 565724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 565824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 565924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawEntities(qb, uri); 56605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(" AND " + RawContacts._ID + "=?"); 5661e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5662e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5663e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 5664d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case DATA: 5665d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_DATA: { 566682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 5667e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5668e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5669e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 5670d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case DATA_ID: 5671d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_DATA_ID: { 567282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 56734da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 56744da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 5675a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov break; 5676a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov } 5677a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov 567885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro case PROFILE_PHOTO: { 567985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 568085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 568185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro break; 568285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 568385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro 5684a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 56854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 5686a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton if (TextUtils.isEmpty(sortOrder)) { 5687a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Default the sort order to something reasonable so we get consistent 5688a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // results when callers don't request an ordering 5689892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sortOrder = " length(lookup.normalized_number) DESC"; 5690a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5691a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5692e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : ""; 5693e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov String numberE164 = PhoneNumberUtils.formatNumberToE164(number, 56945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getCurrentCountryIso()); 5695892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String normalizedNumber = 5696892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov PhoneNumberUtils.normalizeNumber(number); 56975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().buildPhoneLookupAndContactQuery(qb, normalizedNumber, numberE164); 5698e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov qb.setProjectionMap(sPhoneLookupProjectionMap); 5699e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov // Phone lookup cannot be combined with a selection 5700e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selection = null; 5701e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selectionArgs = null; 5702a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 5703a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5704a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5705ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 5706ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5707ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 5708f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro appendAccountFromParameter(qb, uri); 5709ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5710ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5711ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5712ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 5713ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5714ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 57154da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 57164da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Groups._ID + "=?"); 5717ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5718ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5719ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5720ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 5721f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa final boolean returnGroupCountPerAccount = 5722f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa readBooleanQueryParameter(uri, Groups.PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT, 5723f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa false); 5724f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa qb.setTables(Views.GROUPS + " AS " + Tables.GROUPS); 5725f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa qb.setProjectionMap(returnGroupCountPerAccount ? 5726f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa sGroupsSummaryProjectionMapWithGroupCountPerAccount 5727f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa : sGroupsSummaryProjectionMap); 5728f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro appendAccountFromParameter(qb, uri); 5729f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa groupBy = GroupsColumns.CONCRETE_ID; 5730ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5731ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5732ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5733b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 57340c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS); 5735b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 5736b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 5737b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 5738b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 573931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 5740d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 57412d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov String filter = null; 57422d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 57432d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov filter = uri.getPathSegments().get(3); 57442d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov } 574531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 5746d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov if (limit != null) { 5747d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov maxSuggestions = Integer.parseInt(limit); 574831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 574931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 575031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 575131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 57525b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ArrayList<AggregationSuggestionParameter> parameters = null; 57535b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov List<String> query = uri.getQueryParameters("query"); 57545b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov if (query != null && !query.isEmpty()) { 57555b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters = new ArrayList<AggregationSuggestionParameter>(query.size()); 57565b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov for (String parameter : query) { 57575b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov int offset = parameter.indexOf(':'); 57585b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters.add(offset == -1 57595b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ? new AggregationSuggestionParameter( 576076dfa406e2cde19c824983c37fc92c1c5bf63eecDaniel Lehmann AggregationSuggestions.PARAMETER_MATCH_NAME, 57615b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter) 57625b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov : new AggregationSuggestionParameter( 57635b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(0, offset), 57645b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(offset + 1))); 57655b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 57665b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 57675b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 5768763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 57697581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov 57705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mAggregator.get().queryAggregationSuggestions(qb, projection, contactId, 57715b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov maxSuggestions, filter, parameters); 577231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 577331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 5774eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 5775eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setTables(Tables.SETTINGS); 5776eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setProjectionMap(sSettingsProjectionMap); 5777f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro appendAccountFromParameter(qb, uri); 5778e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5779e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // When requesting specific columns, this query requires 5780e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // late-binding of the GroupMembership MIME-type. 57815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final String groupMembershipMimetypeId = Long.toString(mDbHelper.get() 5782e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 578382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 57845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().isInProjection(projection, Settings.UNGROUPED_COUNT)) { 5785e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5786e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 578782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 57885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().isInProjection( 57895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro projection, Settings.UNGROUPED_WITH_PHONES)) { 5790e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5791e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 5792e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5793eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 5794eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 5795eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 57965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 57975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 57980a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 57995ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 58005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 58015ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 580282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES_ID: { 58030a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 58044da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 58054da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(DataColumns.CONCRETE_ID + "=?"); 58065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 58075ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 58085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 5809c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: { 5810174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchSuggestionsQuery( 58115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get(), uri, projection, limit); 5812c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5813c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 5814c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: { 58152d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill String lookupKey = uri.getLastPathSegment(); 5816174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String filter = getQueryParameter( 5817174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov uri, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 5818174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchShortcutRefresh( 58195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get(), projection, lookupKey, filter); 5820c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5821c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 58221b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS: 5823ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 58241b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 58251b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 58261b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 58271b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_WITH_PHONES: 5828ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 58291b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 58301b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1"); 58311b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 58321b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 58331b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_FAVORITES: 5834ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 58351b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 58361b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.STARRED + "=1"); 58371b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 58381b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 58391b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_GROUP_NAME: 5840ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 58411b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 584271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 58437cf50494501938f175d288077145acf49da8f171Daniel Lehmann String groupMimeTypeId = String.valueOf( 58447cf50494501938f175d288077145acf49da8f171Daniel Lehmann mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 58451b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 58467cf50494501938f175d288077145acf49da8f171Daniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, groupMimeTypeId); 58471b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 58481b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 58493202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro case RAW_CONTACT_ENTITIES: 58503202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro case PROFILE_RAW_CONTACT_ENTITIES: { 5851a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 585246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 585346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 585446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 585546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITY_ID: { 585646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5857a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 58584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 58594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 586046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 586146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 586246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 586309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov case PROVIDER_STATUS: { 586409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return queryProviderStatus(uri, projection); 586509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 586609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5867d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES : { 5868d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5869d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5870d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5871d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5872d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 5873d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID : { 5874385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov long id = ContentUris.parseId(uri); 5875d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5876d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5877385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(id)); 5878d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.appendWhere(Directory._ID + "=?"); 5879d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5880d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5881d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 58827a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov case COMPLETE_NAME: { 58837a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return completeName(uri, projection); 58847a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 58857a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 58864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 5887f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 5888c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov sortOrder, limit); 58894f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 58904f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 589109e69522745551522c55dff27424496f255def46Daniel Lehmann qb.setStrict(true); 58927f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov 5893ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov Cursor cursor = 58945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro query(mActiveDb.get(), qb, projection, selection, selectionArgs, sortOrder, groupBy, 58955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro limit); 5896ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) { 58975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro cursor = bundleLetterCountExtras(cursor, mActiveDb.get(), qb, selection, 58982ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki selectionArgs, sortOrder, addressBookIndexerCountExpression); 5899ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5900b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (snippetDeferred) { 5901b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson cursor = addDeferredSnippetingExtra(cursor); 5902b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 5903ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov return cursor; 59045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 59055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 59065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection, 59075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String selection, String[] selectionArgs, String sortOrder, String groupBy, 59085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String limit) { 5909038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana if (projection != null && projection.length == 1 5910038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana && BaseColumns._COUNT.equals(projection[0])) { 5911038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana qb.setProjectionMap(sCountProjectionMap); 5912038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana } 59135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null, 59145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sortOrder, limit); 59154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 59164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 59174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 59184f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 59194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 59204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 592109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov /** 592209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov * Creates a single-row cursor containing the current status of the provider. 592309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov */ 592409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private Cursor queryProviderStatus(Uri uri, String[] projection) { 592509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 592609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov RowBuilder row = cursor.newRow(); 592709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov for (int i = 0; i < projection.length; i++) { 592809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov if (ProviderStatus.STATUS.equals(projection[i])) { 592909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mProviderStatus); 593009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } else if (ProviderStatus.DATA1.equals(projection[i])) { 593109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mEstimatedStorageRequirement); 593209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 593309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 593409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return cursor; 593509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 593609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5937a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** 5938a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * Runs the query with the supplied contact ID and lookup ID. If the query succeeds, 5939a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * it returns the resulting cursor, otherwise it returns null and the calling 5940a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * method needs to resolve the lookup key and rerun the query. 5941a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov */ 5942a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private Cursor queryWithContactIdAndLookupKey(SQLiteQueryBuilder lookupQb, 5943a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteDatabase db, Uri uri, 5944a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection, String selection, String[] selectionArgs, 5945a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String sortOrder, String groupBy, String limit, 5946a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn, long contactId, String lookupKeyColumn, String lookupKey) { 5947a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] args; 5948a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (selectionArgs == null) { 5949a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[2]; 5950a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } else { 5951a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[selectionArgs.length + 2]; 5952a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 5953a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5954a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[0] = String.valueOf(contactId); 5955a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[1] = Uri.encode(lookupKey); 5956a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(contactIdColumn + "=? AND " + lookupKeyColumn + "=?"); 5957a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = query(db, lookupQb, projection, selection, args, sortOrder, 5958a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov groupBy, limit); 5959a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c.getCount() != 0) { 5960a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5961a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5962a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5963a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov c.close(); 5964a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return null; 5965a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 596609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5967bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov private static final class AddressBookIndexQuery { 5968bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String LETTER = "letter"; 5969bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String TITLE = "title"; 5970bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String COUNT = "count"; 5971ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5972bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String[] COLUMNS = new String[] { 5973bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov LETTER, TITLE, COUNT 5974ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov }; 5975ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5976bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_LETTER = 0; 5977bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_TITLE = 1; 5978bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_COUNT = 2; 5979bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 59805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // The first letter of the sort key column is what is used for the index headings. 59815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public static final String SECTION_HEADING = "SUBSTR(%1$s,1,1)"; 598224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5983de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa public static final String ORDER_BY = LETTER + " COLLATE " + PHONEBOOK_COLLATOR_NAME; 5984ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5985ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5986ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov /** 5987ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * Computes counts by the address book index titles and adds the resulting tally 5988ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * to the returned cursor as a bundle of extras. 5989ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov */ 5990ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov private Cursor bundleLetterCountExtras(Cursor cursor, final SQLiteDatabase db, 59912ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki SQLiteQueryBuilder qb, String selection, String[] selectionArgs, String sortOrder, 59922ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki String countExpression) { 5993409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onuki if (!(cursor instanceof AbstractCursor)) { 5994409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onuki Log.w(TAG, "Unable to bundle extras. Cursor is not AbstractCursor."); 5995409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onuki return cursor; 5996409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onuki } 5997ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortKey; 5998ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5999ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // The sort order suffix could be something like "DESC". 6000ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // We want to preserve it in the query even though we will change 6001ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // the sort column itself. 6002ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortOrderSuffix = ""; 6003ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (sortOrder != null) { 6004ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int spaceIndex = sortOrder.indexOf(' '); 6005ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (spaceIndex != -1) { 6006ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder.substring(0, spaceIndex); 6007ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortOrderSuffix = sortOrder.substring(spaceIndex); 6008ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 6009ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder; 6010ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6011ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 6012ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = Contacts.SORT_KEY_PRIMARY; 6013ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6014ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6015bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String locale = getLocale().toString(); 6016ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov HashMap<String, String> projectionMap = Maps.newHashMap(); 60175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String sectionHeading = String.format(AddressBookIndexQuery.SECTION_HEADING, sortKey); 6018bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov projectionMap.put(AddressBookIndexQuery.LETTER, 601924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sectionHeading + " AS " + AddressBookIndexQuery.LETTER); 6020bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 60212ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // If "what to count" is not specified, we just count all records. 60222ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki if (TextUtils.isEmpty(countExpression)) { 60232ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki countExpression = "*"; 60242ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki } 60252ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki 6026bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov /** 6027bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * Use the GET_PHONEBOOK_INDEX function, which is an android extension for SQLite3, 6028bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * to map the first letter of the sort key to a character that is traditionally 6029bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * used in phonebooks to represent that letter. For example, in Korean it will 6030bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * be the first consonant in the letter; for Japanese it will be Hiragana rather 6031bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * than Katakana. 6032bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov */ 6033ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.TITLE, 603424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "GET_PHONEBOOK_INDEX(" + sectionHeading + ",'" + locale + "')" 6035bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov + " AS " + AddressBookIndexQuery.TITLE); 6036ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.COUNT, 60372ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki "COUNT(" + countExpression + ") AS " + AddressBookIndexQuery.COUNT); 6038ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov qb.setProjectionMap(projectionMap); 6039ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6040f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs, 6041ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY, null /* having */, 6042ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY + sortOrderSuffix); 6043ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6044ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov try { 6045f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov int groupCount = indexCursor.getCount(); 6046ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String titles[] = new String[groupCount]; 6047ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int counts[] = new int[groupCount]; 6048bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int indexCount = 0; 6049bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String currentTitle = null; 6050bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 6051bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // Since GET_PHONEBOOK_INDEX is a many-to-1 function, we may end up 6052bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // with multiple entries for the same title. The following code 6053bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // collapses those duplicates. 6054ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov for (int i = 0; i < groupCount; i++) { 6055f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.moveToNext(); 6056bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String title = indexCursor.getString(AddressBookIndexQuery.COLUMN_TITLE); 6057bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int count = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT); 6058bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount == 0 || !TextUtils.equals(title, currentTitle)) { 6059bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles[indexCount] = currentTitle = title; 6060bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount] = count; 6061bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov indexCount++; 6062bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } else { 6063bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount - 1] += count; 6064bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 6065bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 6066bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 6067bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount < groupCount) { 6068bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String[] newTitles = new String[indexCount]; 6069bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(titles, 0, newTitles, 0, indexCount); 6070bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles = newTitles; 6071bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 6072bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int[] newCounts = new int[indexCount]; 6073bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(counts, 0, newCounts, 0, indexCount); 6074bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts = newCounts; 6075ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6076ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6077409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onuki final Bundle bundle = new Bundle(); 6078409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onuki bundle.putStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES, titles); 6079409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onuki bundle.putIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, counts); 6080409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onuki 6081409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onuki ((AbstractCursor) cursor).setExtras(bundle); 6082409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onuki return cursor; 6083ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } finally { 6084f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.close(); 6085ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6086ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6087ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 60882d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill /** 608992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Returns the contact Id for the contact identified by the lookupKey. 609092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Robust against changes in the lookup key: if the key has changed, will 609192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * look up the contact by the raw contact IDs or name encoded in the lookup 609292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * key. 60932d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill */ 60942d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) { 60955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey key = new ContactLookupKey(); 60965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments = key.parse(lookupKey); 60975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 609892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov long contactId = -1; 60995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_PROFILE)) { 61005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // We should already be in a profile database context, so just look up a single contact. 61015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro contactId = lookupSingleContactId(db); 61025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 61035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 610492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_SOURCE_ID)) { 610592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdBySourceIds(db, segments); 610692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 610792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 610892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 610992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 611092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 611192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov boolean hasRawContactIds = 611292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID); 611392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds) { 611492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdByRawContactIds(db, segments); 611592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 611692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 611792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 611892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 611992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 612092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds 612192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME)) { 61225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = lookupContactIdByDisplayNames(db, segments); 61235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 61255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 61265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 61285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private long lookupSingleContactId(SQLiteDatabase db) { 61295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = db.query(Tables.CONTACTS, new String[] {Contacts._ID}, 61305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro null, null, null, null, null, "1"); 61315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro try { 61325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (c.moveToFirst()) { 61335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return c.getLong(0); 61345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 61355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return -1; 61365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 61375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } finally { 61385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro c.close(); 61395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 61405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 61415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 61425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private interface LookupBySourceIdQuery { 614343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 61445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 61455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 61465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 614743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 61485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 61495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.SOURCE_ID 61505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 61515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 61525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 615343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 61545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 61555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int SOURCE_ID = 3; 61565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 61585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long lookupContactIdBySourceIds(SQLiteDatabase db, 61595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments) { 61605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 61615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(RawContacts.SOURCE_ID + " IN ("); 61625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 61635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 616492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID) { 61655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 61665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 61675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 61705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 61715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 61725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS, 61735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 61745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 61755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 617643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 617743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 61785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME); 61795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 618043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 61815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID); 61825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 61835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 618492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID 618592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 61865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(sourceId)) { 61875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID); 61885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 61895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 61935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 61945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 61965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 61975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 619992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByRawContactIdQuery { 620043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 62015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 62025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 62035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 620443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 62055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 620692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts._ID, 62075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 62085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 62095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 621043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 62115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 621292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ID = 3; 62135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 621592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByRawContactIds(SQLiteDatabase db, 621692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 621792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 621892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(RawContacts._ID + " IN ("); 62195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 62205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 622192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 622292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(segment.rawContactId); 622392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(","); 62245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 622692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 622792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 62285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 622992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov Cursor c = db.query(LookupByRawContactIdQuery.TABLE, LookupByRawContactIdQuery.COLUMNS, 623092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.toString(), null, null, null, null); 623192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov try { 623292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov while (c.moveToNext()) { 623343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = c.getString( 623443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro LookupByRawContactIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 623592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountName = c.getString(LookupByRawContactIdQuery.ACCOUNT_NAME); 623692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int accountHashCode = 623743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 623892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String rawContactId = c.getString(LookupByRawContactIdQuery.ID); 623992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 624092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 624192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID 624292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 624392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && segment.rawContactId.equals(rawContactId)) { 624492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov segment.contactId = c.getLong(LookupByRawContactIdQuery.CONTACT_ID); 624592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov break; 624692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 624792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 624892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 624992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } finally { 625092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov c.close(); 62515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 625392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return getMostReferencedContactId(segments); 625492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 625592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 625692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByDisplayNameQuery { 625792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS; 625892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 625992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String COLUMNS[] = { 626092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.CONTACT_ID, 626143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 626292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 626392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov NameLookupColumns.NORMALIZED_NAME 626492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov }; 626592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 626692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int CONTACT_ID = 0; 626743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 626892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_NAME = 2; 626992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int NORMALIZED_NAME = 3; 627092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 627192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 627292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByDisplayNames(SQLiteDatabase db, 627392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 62745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 62755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(NameLookupColumns.NORMALIZED_NAME + " IN ("); 62765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 62775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 627892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 627992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 62805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 62815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 62825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 62855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY 62865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov + " AND " + RawContacts.CONTACT_ID + " NOT NULL"); 62875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 62885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS, 62895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 62905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 62915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 629243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 629343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE_AND_DATA_SET); 62945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME); 62955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 629643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 62975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME); 62985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 62995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 630092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if ((segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 630192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) 630292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 63035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(name)) { 63045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID); 63055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 63065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 63105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 63115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 63135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 63145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 631692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private boolean lookupKeyContainsType(ArrayList<LookupKeySegment> segments, int lookupType) { 631792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 631892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 631992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == lookupType) { 632092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return true; 632192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 632292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 632392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 632492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return false; 632592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 632692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 6327ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateLookupKeyForRawContact(SQLiteDatabase db, long rawContactId) { 63285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateLookupKeyForRawContact(db, rawContactId); 6329ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov } 6330ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov 63315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov /** 63325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov * Returns the contact ID that is mentioned the highest number of times. 63335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov */ 63345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) { 63355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Collections.sort(segments); 63365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 63375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long bestContactId = -1; 63385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int bestRefCount = 0; 63395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 63405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = -1; 63415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int count = 0; 63425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 63435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = segments.size(); 63445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segmentCount; i++) { 63455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 63465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId != -1) { 63475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId == contactId) { 63485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count++; 63495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 63505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 63515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestContactId = contactId; 63525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestRefCount = count; 63535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = segment.contactId; 63555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count = 1; 63565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 63605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 63615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 63625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return bestContactId; 63635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 6366763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 6367763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar String[] projection) { 63684928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 63692f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 63702f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 63712f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 63724928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * @param includeDataUsageStat true when the table should include DataUsageStat table. 63734928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Note that this uses INNER JOIN instead of LEFT OUTER JOIN, so some of data in Contacts 63744928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * may be dropped. 63752f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 63762f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 63774928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa String[] projection, boolean includeDataUsageStat) { 637882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6379ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 63802f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 63812f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Just for frequently contacted contacts in Strequent Uri handling. 63824928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (includeDataUsageStat) { 63832f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa sb.append(" INNER JOIN " + 6384ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA_USAGE_STAT + " AS " + Tables.DATA_USAGE_STAT + 63852f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa " ON (" + 63862f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DbQueryUtils.concatenateClauses( 63872f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DataUsageStatColumns.CONCRETE_TIMES_USED + " > 0", 63884928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) + 63892f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa ")"); 63902f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 63912f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 63927ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 63937ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6394916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setTables(sb.toString()); 6395916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionMap); 6396916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov } 6397916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6398916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** 6399916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * Finds name lookup records matching the supplied filter, picks one arbitrary match per 6400916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * contact and joins that with other contacts tables. 6401916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov */ 6402916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private void setTablesAndProjectionMapForContactsWithSnippet(SQLiteQueryBuilder qb, Uri uri, 6403b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson String[] projection, String filter, long directoryId, boolean deferredSnippeting) { 64047ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov 64057ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6406ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 6407916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 640803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (filter != null) { 640903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov filter = filter.trim(); 641003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 641103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 641230cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov if (TextUtils.isEmpty(filter) || (directoryId != -1 && directoryId != Directory.DEFAULT)) { 641330cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov sb.append(" JOIN (SELECT NULL AS " + SearchSnippetColumns.SNIPPET + " WHERE 0)"); 64145e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } else { 6415b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson appendSearchIndexJoin(sb, uri, projection, filter, deferredSnippeting); 64165e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 64177ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 64187ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 641903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setTables(sb.toString()); 642003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionWithSnippetMap); 642103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 6422916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 642303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private void appendSearchIndexJoin( 6424b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson StringBuilder sb, Uri uri, String[] projection, String filter, 6425b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson boolean deferredSnippeting) { 6426916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6427b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (snippetNeeded(projection)) { 642803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String[] args = null; 642903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String snippetArgs = 643003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 643103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (snippetArgs != null) { 643203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov args = snippetArgs.split(","); 643303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 643403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 64355e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String startMatch = args != null && args.length > 0 ? args[0] 64365e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_START_MATCH; 64375e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String endMatch = args != null && args.length > 1 ? args[1] 64385e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_END_MATCH; 64395e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String ellipsis = args != null && args.length > 2 ? args[2] 64405e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_ELLIPSIS; 64415e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 64425e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 64435e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 6444174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin( 6445b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson sb, filter, true, startMatch, endMatch, ellipsis, maxTokens, 6446b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson deferredSnippeting); 6447174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 6448b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson appendSearchIndexJoin(sb, filter, false, null, null, null, 0, false); 6449174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6450174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6451174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 6452174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public void appendSearchIndexJoin(StringBuilder sb, String filter, 6453174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean snippetNeeded, String startMatch, String endMatch, String ellipsis, 6454b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson int maxTokens, boolean deferredSnippeting) { 6455174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isEmailAddress = false; 6456174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String emailAddress = null; 6457174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isPhoneNumber = false; 6458174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String phoneNumber = null; 6459174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String numberE164 = null; 6460174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 64613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // If the query consists of a single word, we can do snippetizing after-the-fact for a 64623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // performance boost. 6463b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson boolean singleTokenSearch = isSingleWordQuery(filter); 64643716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 6465174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (filter.indexOf('@') != -1) { 64665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro emailAddress = mDbHelper.get().extractAddressFromEmailAddress(filter); 6467174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isEmailAddress = !TextUtils.isEmpty(emailAddress); 6468174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 6469174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isPhoneNumber = isPhoneNumber(filter); 647004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (isPhoneNumber) { 647104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann phoneNumber = PhoneNumberUtils.normalizeNumber(filter); 647204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann numberE164 = PhoneNumberUtils.formatNumberToE164(phoneNumber, 64735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getCountryIso()); 647404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 6475174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6476174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 6477174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(" JOIN (SELECT " + SearchIndexColumns.CONTACT_ID + " AS snippet_contact_id"); 6478174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (snippetNeeded) { 64795e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(", "); 64805e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 64813d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 64825e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 648304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Email.ADDRESS + ")"); 648404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + Tables.DATA_JOIN_RAW_CONTACTS); 648504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 648604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID + " AND " + Email.ADDRESS + " LIKE "); 648704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann DatabaseUtils.appendEscapedSQLString(sb, filter + "%"); 648804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 64893d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 64903d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(","); 64913716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 6492b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson // Optimization for single-token search (do only if requested). 6493b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (singleTokenSearch && deferredSnippeting) { 64943716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 64953716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 64963716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 64973716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 64983d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(")"); 64993d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 65003d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 65013d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 650204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Phone.NUMBER + ")"); 650304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + 650404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann Tables.DATA_JOIN_RAW_CONTACTS + " JOIN " + Tables.PHONE_LOOKUP); 650504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" ON " + DataColumns.CONCRETE_ID); 650604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID); 650704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 650804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID); 650904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" AND " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 651004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(phoneNumber); 651104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 651204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(numberE164)) { 651304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" OR " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 651404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(numberE164); 651504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 651604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 651704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 65185e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 65195e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 65203716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 6521b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson // Optimization for single-token search (do only if requested). 6522b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (singleTokenSearch && deferredSnippeting) { 65233716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 65243716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 65253716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 65263716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 65275e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 652803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 652904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann final String normalizedFilter = NameNormalizer.normalize(filter); 653004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(normalizedFilter)) { 6531b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson // Optimization for single-token search (do only if requested).. 6532b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (singleTokenSearch && deferredSnippeting) { 65333716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 65343716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 65353716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("(CASE WHEN EXISTS (SELECT 1 FROM "); 65363716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.RAW_CONTACTS + " AS rc INNER JOIN "); 65373716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.NAME_LOOKUP + " AS nl ON (rc." + RawContacts._ID); 65383716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=nl." + NameLookupColumns.RAW_CONTACT_ID); 65393716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") WHERE nl." + NameLookupColumns.NORMALIZED_NAME); 65403716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" GLOB '" + normalizedFilter + "*' AND "); 65413716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("nl." + NameLookupColumns.NAME_TYPE + "="); 65423716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(NameLookupType.NAME_COLLATION_KEY + " AND "); 65433716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 65443716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=rc." + RawContacts.CONTACT_ID); 65453716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") THEN NULL ELSE "); 65463716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 65473716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" END)"); 65483716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 654904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } else { 655004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("NULL"); 655104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 655203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 65535e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" AS " + SearchSnippetColumns.SNIPPET); 65545e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 655503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 65565e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" FROM " + Tables.SEARCH_INDEX); 65575e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" WHERE "); 65585e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(Tables.SEARCH_INDEX + " MATCH "); 65595e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 65602352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, "\"" + sanitizeMatch(filter) + "*\""); 65613d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 65622352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, 656304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann "\"" + sanitizeMatch(filter) + "*\" OR \"" + phoneNumber + "*\"" 65642352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov + (numberE164 != null ? " OR \"" + numberE164 + "\"" : "")); 656503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 65662352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filter) + "*"); 65679c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov } 656803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov sb.append(") ON (" + Contacts._ID + "=snippet_contact_id)"); 6569a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov } 6570a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov 65712352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov private String sanitizeMatch(String filter) { 65722352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov // TODO more robust preprocessing of match expressions 65732352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov return filter.replace('-', ' ').replace('\"', ' '); 65742352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov } 65752352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov 65765e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov private void appendSnippetFunction( 65775e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov StringBuilder sb, String startMatch, String endMatch, String ellipsis, int maxTokens) { 65785e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append("snippet(" + Tables.SEARCH_INDEX + ","); 65795e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 65805e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 65815e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 65825e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 65835e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, ellipsis); 65845e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 65855e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov // The index of the column used for the snippet, "content" 65865e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(",1,"); 65875e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(maxTokens); 65885e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 65895e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 65905e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 6591763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) { 6592763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar StringBuilder sb = new StringBuilder(); 6593ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.RAW_CONTACTS); 6594763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setTables(sb.toString()); 6595763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setProjectionMap(sRawContactsProjectionMap); 6596f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro appendAccountFromParameter(qb, uri); 6597763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar } 6598763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar 6599a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForRawEntities(SQLiteQueryBuilder qb, Uri uri) { 6600ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.RAW_ENTITIES); 6601a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sRawEntityProjectionMap); 6602f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro appendAccountFromParameter(qb, uri); 660346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 660446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 660582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 660682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String[] projection, boolean distinct) { 660746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, distinct, null); 660846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 660946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 661046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 661146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @param usageType when non-null {@link Tables#DATA_USAGE_STAT} is joined with the specified 661246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type. 661346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 661446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 661546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String[] projection, boolean distinct, Integer usageType) { 661682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6617ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 661882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov sb.append(" data"); 661982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov 6620a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID); 6621a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6622a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6623a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 66243296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey 662546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (usageType != null) { 662646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa appendDataUsageStatJoin(sb, usageType, DataColumns.CONCRETE_ID); 662746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 662846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 662982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov qb.setTables(sb.toString()); 6630f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov 6631f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov boolean useDistinct = distinct 66325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro || !mDbHelper.get().isInProjection(projection, DISTINCT_DATA_PROHIBITING_COLUMNS); 6633f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setDistinct(useDistinct); 6634f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setProjectionMap(useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap); 6635f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro appendAccountFromParameter(qb, uri); 6636ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov } 6637ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov 66380a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb, 66390a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String[] projection) { 66400a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6641ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 66420a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" data"); 6643a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6644a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 66450a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6646a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6647a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sStatusUpdatesProjectionMap); 6648a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6649a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 66503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItems(SQLiteQueryBuilder qb) { 66519b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann qb.setTables(Views.STREAM_ITEMS); 66523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemsProjectionMap); 66533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 66543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 66553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItemPhotos(SQLiteQueryBuilder qb) { 66561dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.PHOTO_FILES 66571dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.STREAM_ITEM_PHOTOS + " ON (" 66581dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_PHOTO_FILE_ID + "=" 66591dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + PhotoFilesColumns.CONCRETE_ID 66601dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.STREAM_ITEMS + " ON (" 66611dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=" 66620bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + StreamItemsColumns.CONCRETE_ID + ")" 66630bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + " JOIN " + Tables.RAW_CONTACTS + " ON (" 66640bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + StreamItemsColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 66650bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + ")"); 66663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemPhotosProjectionMap); 66673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 66683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 6669a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForEntities(SQLiteQueryBuilder qb, Uri uri, 6670a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection) { 6671a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6672ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.ENTITIES); 6673a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" data"); 6674a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6675a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts.Entity.CONTACT_ID); 6676a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6677a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, Contacts.Entity.DATA_ID); 6678a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, Contacts.Entity.DATA_ID); 6679a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6680a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6681a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sEntityProjectionMap); 6682f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro appendAccountFromParameter(qb, uri); 6683a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6684a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6685a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactStatusUpdateJoin(StringBuilder sb, String[] projection, 6686a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lastStatusUpdateIdColumn) { 66875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, 6688a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS, 6689a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_RES_PACKAGE, 6690a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_ICON, 6691a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_LABEL, 6692a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_TIMESTAMP)) { 6693a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " " 6694a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.ALIAS + 6695a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + lastStatusUpdateIdColumn + "=" 6696a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")"); 66970a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6698a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 66990a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6700a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataStatusUpdateJoin(StringBuilder sb, String[] projection, 6701a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 67025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, 67030a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS, 67040a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_RES_PACKAGE, 67050a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_ICON, 67060a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_LABEL, 67070a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_TIMESTAMP)) { 67080a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + 6709a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "=" 6710a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + dataIdColumn + ")"); 67110a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6712a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6713a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 671446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void appendDataUsageStatJoin(StringBuilder sb, int usageType, String dataIdColumn) { 671546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" LEFT OUTER JOIN " + Tables.DATA_USAGE_STAT + 671646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" + dataIdColumn + 671746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " AND " + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" + usageType + ")"); 671846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 671946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 6720a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactPresenceJoin(StringBuilder sb, String[] projection, 6721a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn) { 67225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, 6723a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_PRESENCE, Contacts.CONTACT_CHAT_CAPABILITY)) { 6724a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + 6725a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + contactIdColumn + " = " 6726a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + ")"); 6727a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6728a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6729a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6730a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataPresenceJoin(StringBuilder sb, String[] projection, 6731a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 67325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, Data.PRESENCE, Data.CHAT_CAPABILITY)) { 6733a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE + 6734a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdates.DATA_ID + "=" + dataIdColumn + ")"); 6735a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6736a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6737a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 673824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private boolean appendLocalDirectorySelectionIfNeeded(SQLiteQueryBuilder qb, long directoryId) { 6739385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directoryId == Directory.DEFAULT) { 6740385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY); 674124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 6742385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directoryId == Directory.LOCAL_INVISIBLE){ 6743385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " NOT IN " + Tables.DEFAULT_DIRECTORY); 674424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 674524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 674624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return false; 674724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 674824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 6749f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) { 6750f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6751f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 675243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 6753e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6754e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6755e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6756e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 67575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 6758fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6759e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6760e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6761e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6762e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6763e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6764e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 676543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String toAppend = RawContacts.ACCOUNT_NAME + "=" 67664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + DatabaseUtils.sqlEscapeString(accountName) + " AND " 67674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + RawContacts.ACCOUNT_TYPE + "=" 676843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + DatabaseUtils.sqlEscapeString(accountType); 6769f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (dataSet == null) { 6770f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro toAppend += " AND " + RawContacts.DATA_SET + " IS NULL"; 6771f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } else { 6772f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro toAppend += " AND " + RawContacts.DATA_SET + "=" + 6773f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro DatabaseUtils.sqlEscapeString(dataSet); 677443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 677543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro qb.appendWhere(toAppend); 67764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } else { 67774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere("1"); 67784a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 67794a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 67804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 6781e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong private String appendAccountToSelection(Uri uri, String selection) { 6782f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6783f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 678443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 6785e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6786e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6787e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6788e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 67895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 6790fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6791e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6792e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6793e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6794e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6795e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6796e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 6797e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "=" 6798e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountName) + " AND " 6799e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + RawContacts.ACCOUNT_TYPE + "=" 6800e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountType)); 6801f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (dataSet == null) { 6802f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro selectionSb.append(" AND " + RawContacts.DATA_SET + " IS NULL"); 6803f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } else { 680443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selectionSb.append(" AND " + RawContacts.DATA_SET + "=") 680543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .append(DatabaseUtils.sqlEscapeString(dataSet)); 680643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 6807e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong if (!TextUtils.isEmpty(selection)) { 6808e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(" AND ("); 6809e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(selection); 6810e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(')'); 6811e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6812e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selectionSb.toString(); 6813e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } else { 6814e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selection; 6815e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6816e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6817e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong 68187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 6819c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * Gets the value of the "limit" URI query parameter. 6820c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * 6821c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * @return A string containing a non-negative integer, or <code>null</code> if 6822c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * the parameter is not set, or is set to an invalid value. 6823c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov */ 6824f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private String getLimit(Uri uri) { 68252e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limitParam = getQueryParameter(uri, ContactsContract.LIMIT_PARAM_KEY); 6826c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (limitParam == null) { 6827c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6828c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6829c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov // make sure that the limit is a non-negative integer 6830c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov try { 6831c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov int l = Integer.parseInt(limitParam); 6832c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (l < 0) { 6833c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6834c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6835c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6836c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return String.valueOf(l); 6837c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } catch (NumberFormatException ex) { 6838c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6839c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6840c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6841c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6842c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 6843b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov @Override 6844f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 6845f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mode.equals("r")) { 6846f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mReadAccessLatch); 6847f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6848f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mWriteAccessLatch); 6849f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 68505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 68515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 68525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileProvider.openAssetFile(uri, mode); 68535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 68545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 68555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return openAssetFileLocal(uri, mode); 68565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 68575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 68585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 68595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public AssetFileDescriptor openAssetFileLocal(Uri uri, String mode) 68605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throws FileNotFoundException { 68615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 68625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 68635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 6864078f588cef389358adabc579de00747878f3c108Dave Santoro if (mode.equals("r")) { 6865078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getReadableDatabase()); 6866078f588cef389358adabc579de00747878f3c108Dave Santoro } else { 6867078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getWritableDatabase()); 6868078f588cef389358adabc579de00747878f3c108Dave Santoro } 68695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 6870415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6871b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov int match = sUriMatcher.match(uri); 6872b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov switch (match) { 6873a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 6874bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 68755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return openPhotoAssetFile(mActiveDb.get(), uri, mode, 687624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Data._ID + "=" + Contacts.PHOTO_ID + " AND " + 687724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContacts.CONTACT_ID + "=?", 6878bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro new String[]{String.valueOf(contactId)}); 6879e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6880b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6881f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: { 6882f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6883f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6884f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact ID can only be read."); 6885f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6886f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 68875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.CONTACTS, 6888f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{Contacts.PHOTO_FILE_ID}, 6889f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID + "=?", new String[]{String.valueOf(contactId)}, 6890f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, null); 6891f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 689285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro if (c.moveToFirst()) { 689385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro long photoFileId = c.getLong(0); 689485077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro return openDisplayPhotoForRead(photoFileId); 689585077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } else { 689685077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro // No contact for this ID. 689785077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro throw new FileNotFoundException(uri.toString()); 689885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 689985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } finally { 690085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro c.close(); 690185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 690285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 690385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro 690485077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro case PROFILE_DISPLAY_PHOTO: { 690585077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro if (!mode.equals("r")) { 690685077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro throw new IllegalArgumentException( 690785077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro "Display photos retrieved by contact ID can only be read."); 690885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 690985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro Cursor c = mActiveDb.get().query(Tables.CONTACTS, 691085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro new String[]{Contacts.PHOTO_FILE_ID}, null, null, null, null, null); 691185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro try { 691285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro if (c.moveToFirst()) { 691385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro long photoFileId = c.getLong(0); 691485077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro return openDisplayPhotoForRead(photoFileId); 691585077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } else { 691685077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro // No profile record. 691785077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro throw new FileNotFoundException(uri.toString()); 691885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 6919f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6920f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6921f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6922f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6923f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6924bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_PHOTO: 6925bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_PHOTO: 6926f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6927f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: { 6928f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6929f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6930bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro "Photos retrieved by contact lookup key can only be read."); 6931f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6932f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro List<String> pathSegments = uri.getPathSegments(); 6933f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int segmentCount = pathSegments.size(); 6934f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount < 4) { 69355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 6936f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Missing a lookup key", uri)); 6937f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6938bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro 6939bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro boolean forDisplayPhoto = (match == CONTACTS_LOOKUP_ID_DISPLAY_PHOTO 6940bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro || match == CONTACTS_LOOKUP_DISPLAY_PHOTO); 6941f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String lookupKey = pathSegments.get(2); 6942bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro String[] projection = new String[]{Contacts.PHOTO_ID, Contacts.PHOTO_FILE_ID}; 6943f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount == 5) { 6944f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(pathSegments.get(3)); 6945f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 6946f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 69475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 6948f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro projection, null, null, null, null, null, 6949f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 6950f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c != null) { 6951f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6952f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6953bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (forDisplayPhoto) { 6954bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoFileId = 6955bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6956bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro return openDisplayPhotoForRead(photoFileId); 6957bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } else { 6958bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoId = c.getLong(c.getColumnIndex(Contacts.PHOTO_ID)); 6959bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro return openPhotoAssetFile(mActiveDb.get(), uri, mode, 6960bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro Data._ID + "=?", new String[]{String.valueOf(photoId)}); 6961bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 6962f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6963f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6964f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6965f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6966f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6967f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6968f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6969f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 69705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 69715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = qb.query(mActiveDb.get(), projection, Contacts._ID + "=?", 6972f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(contactId)}, null, null, null); 6973f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6974f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6975bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (forDisplayPhoto) { 6976bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6977bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro return openDisplayPhotoForRead(photoFileId); 6978bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } else { 6979bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoId = c.getLong(c.getColumnIndex(Contacts.PHOTO_ID)); 6980bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro return openPhotoAssetFile(mActiveDb.get(), uri, mode, 6981bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro Data._ID + "=?", new String[]{String.valueOf(photoId)}); 6982bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 6983f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6984f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6985f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6986f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6987f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6988f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: { 6989f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6990f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean writeable = !mode.equals("r"); 6991f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6992f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Find the primary photo data record for this raw contact. 6993f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6994f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Data._ID, Photo.PHOTO_FILE_ID}; 6995f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 69967cf50494501938f175d288077145acf49da8f171Daniel Lehmann long photoMimetypeId = mDbHelper.get().getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 69975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = qb.query(mActiveDb.get(), projection, 69987cf50494501938f175d288077145acf49da8f171Daniel Lehmann Data.RAW_CONTACT_ID + "=? AND " + DataColumns.MIMETYPE_ID + "=?", 69997cf50494501938f175d288077145acf49da8f171Daniel Lehmann new String[]{String.valueOf(rawContactId), String.valueOf(photoMimetypeId)}, 7000f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, Data.IS_PRIMARY + " DESC"); 7001f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long dataId = 0; 7002f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = 0; 7003f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7004f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c.getCount() >= 1) { 7005f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 7006f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro dataId = c.getLong(0); 7007f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro photoFileId = c.getLong(1); 7008f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7009f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 7010f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 7011f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7012f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7013f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If writeable, open a writeable file descriptor that we can monitor. 7014f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // When the caller finishes writing content, we'll process the photo and 7015f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // update the data record. 7016f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (writeable) { 7017f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForWrite(rawContactId, dataId, uri, mode); 7018f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 7019f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 7020f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7021f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7022f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7023f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: { 7024f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = ContentUris.parseId(uri); 7025f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 7026f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 7027f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by key can only be read."); 7028f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7029f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 7030f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7031f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7032e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov case DATA_ID: { 703324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = Long.parseLong(uri.getPathSegments().get(1)); 70347cf50494501938f175d288077145acf49da8f171Daniel Lehmann long photoMimetypeId = mDbHelper.get().getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 70355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return openPhotoAssetFile(mActiveDb.get(), uri, mode, 70367cf50494501938f175d288077145acf49da8f171Daniel Lehmann Data._ID + "=? AND " + DataColumns.MIMETYPE_ID + "=" + photoMimetypeId, 703724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(dataId)}); 7038d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7039d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7040fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case PROFILE_AS_VCARD: { 7041fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // When opening a contact as file, we pass back contents as a 7042fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // vCard-encoded stream. We build into a local buffer first, 7043fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // then pipe into MemoryFile once the exact size is known. 7044fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 7045fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 7046fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen return buildAssetFileDescriptor(localStream); 7047fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 704842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 7049fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case CONTACTS_AS_VCARD: { 705042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // When opening a contact as file, we pass back contents as a 705142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // vCard-encoded stream. We build into a local buffer first, 705242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // then pipe into MemoryFile once the exact size is known. 705342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 7054fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 7055f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 705642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 705742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 705842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 705942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKeys = uri.getPathSegments().get(2); 706042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String[] loopupKeyList = lookupKeys.split(":"); 706142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final StringBuilder inBuilder = new StringBuilder(); 7062fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Uri queryUri = Contacts.CONTENT_URI; 706342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann int index = 0; 7064fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen 7065d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // SQLite has limits on how many parameters can be used 7066d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // so the IDs are concatenated to a query string here instead 706742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann for (String lookupKey : loopupKeyList) { 706842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann if (index == 0) { 7069d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append("("); 707042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } else { 7071d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append(","); 707242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 70735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // TODO: Figure out what to do if the profile contact is in the list. 70745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 707524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro inBuilder.append(contactId); 707642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann index++; 707742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 707842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann inBuilder.append(')'); 707942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String selection = Contacts._ID + " IN " + inBuilder.toString(); 7080d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7081d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // When opening a contact as file, we pass back contents as a 7082d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // vCard-encoded stream. We build into a local buffer first, 7083d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // then pipe into MemoryFile once the exact size is known. 7084d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 7085fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(queryUri, localStream, selection, null); 7086f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 7087d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7088b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 7089b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov default: 70905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new FileNotFoundException(mDbHelper.get().exceptionMessage( 70915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "File does not exist", uri)); 7092b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 7093b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 7094b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 7095afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private AssetFileDescriptor openPhotoAssetFile(SQLiteDatabase db, Uri uri, String mode, 7096afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro String selection, String[] selectionArgs) 7097e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throws FileNotFoundException { 7098e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov if (!"r".equals(mode)) { 70995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new FileNotFoundException(mDbHelper.get().exceptionMessage("Mode " + mode 7100e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov + " not supported.", uri)); 7101e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 7102e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 7103e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov String sql = 7104ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann "SELECT " + Photo.PHOTO + " FROM " + Views.DATA + 7105e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov " WHERE " + selection; 710608ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood try { 7107f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 7108f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert DatabaseUtils.blobFileDescriptorForQuery(db, sql, selectionArgs)); 710908ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } catch (SQLiteDoneException e) { 711008ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood // this will happen if the DB query returns no rows (i.e. contact does not exist) 711108ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood throw new FileNotFoundException(uri.toString()); 711208ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } 7113e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 7114e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 7115f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 7116f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a display photo from the photo store for reading. 7117f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoFileId The display photo file ID 7118f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor that allows the file to be read. 7119f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @throws FileNotFoundException If no photo file for the given ID exists. 7120f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 7121f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForRead(long photoFileId) 7122f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throws FileNotFoundException { 71235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore.Entry entry = mPhotoStore.get().get(photoFileId); 7124f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 7125d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro try { 7126d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro return makeAssetFileDescriptor( 7127d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro ParcelFileDescriptor.open(new File(entry.path), 7128d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro ParcelFileDescriptor.MODE_READ_ONLY), 7129d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro entry.size); 7130d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } catch (FileNotFoundException fnfe) { 7131d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 7132d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro throw fnfe; 7133d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 7134f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 7135f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 7136f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new FileNotFoundException("No photo file found for ID " + photoFileId); 7137f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7138f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7139f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7140f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 7141f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a file descriptor for a photo to be written. When the caller completes writing 7142f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to the file (closing the output stream), the image will be parsed out and processed. 7143f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If processing succeeds, the given raw contact ID's primary photo record will be 7144f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * populated with the inserted image (if no primary photo record exists, the data ID can 7145f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * be left as 0, and a new data record will be inserted). 7146f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rawContactId Raw contact ID this photo entry should be associated with. 7147f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param dataId Data ID for a photo mimetype that will be updated with the inserted 7148f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * image. May be set to 0, in which case the inserted image will trigger creation 7149f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * of a new primary photo image data row for the raw contact. 7150f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param uri The URI being used to access this file. 7151f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param mode Read/write mode string. 7152f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor the caller can use to write an image file for the 7153f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact. 7154f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 7155f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForWrite(long rawContactId, long dataId, Uri uri, 7156f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String mode) { 7157f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7158c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro ParcelFileDescriptor[] pipeFds = ParcelFileDescriptor.createPipe(); 7159c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro PipeMonitor pipeMonitor = new PipeMonitor(rawContactId, dataId, pipeFds[0]); 7160c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro pipeMonitor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[]) null); 7161c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro return new AssetFileDescriptor(pipeFds[1], 0, AssetFileDescriptor.UNKNOWN_LENGTH); 7162f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException ioe) { 7163f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Could not create temp image file in mode " + mode); 7164f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return null; 7165f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7166f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7167f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7168f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 7169c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * Async task that monitors the given file descriptor (the read end of a pipe) for 7170c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * the writer finishing. If the data from the pipe contains a valid image, the image 7171c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * is either inserted into the given raw contact or updated in the given data row. 7172f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 7173c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private class PipeMonitor extends AsyncTask<Object, Object, Object> { 7174c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private final ParcelFileDescriptor mDescriptor; 7175f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mRawContactId; 7176f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mDataId; 7177c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private PipeMonitor(long rawContactId, long dataId, ParcelFileDescriptor descriptor) { 7178f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mRawContactId = rawContactId; 7179f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDataId = dataId; 7180c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro mDescriptor = descriptor; 7181f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7182f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7183f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro @Override 7184c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro protected Object doInBackground(Object... params) { 7185c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro AutoCloseInputStream is = new AutoCloseInputStream(mDescriptor); 7186f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7187c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro Bitmap b = BitmapFactory.decodeStream(is); 7188f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (b != null) { 7189fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann waitForAccess(mWriteAccessLatch); 7190f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoProcessor processor = new PhotoProcessor(b, mMaxDisplayPhotoDim, 7191f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim); 7192f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7193f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Store the compressed photo in the photo store. 71945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore photoStore = ContactsContract.isProfileId(mRawContactId) 71955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ? mProfilePhotoStore 71965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro : mContactsPhotoStore; 71975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long photoFileId = photoStore.insert(processor); 7198f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7199c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro // Depending on whether we already had a data row to attach the photo 7200c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro // to, do an update or insert. 7201f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mDataId != 0) { 7202f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Update the data record with the new photo. 7203f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 7204f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7205f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 7206f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 7207f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7208f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 7209f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO_FILE_ID, photoFileId); 7210f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7211f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 7212c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro update(ContentUris.withAppendedId(Data.CONTENT_URI, mDataId), 7213c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro updateValues, null, null); 7214f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 7215f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Insert a new primary data record with the photo. 7216f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues insertValues = new ContentValues(); 7217f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7218f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 7219f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 7220f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7221f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 7222f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.IS_PRIMARY, 1); 7223f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 7224f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO_FILE_ID, photoFileId); 7225f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7226f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 7227f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insert(RawContacts.CONTENT_URI.buildUpon() 7228f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(String.valueOf(mRawContactId)) 7229f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(RawContacts.Data.CONTENT_DIRECTORY).build(), 7230f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues); 7231f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7232c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro 7233f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7234c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro } catch (IOException e) { 7235c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro throw new RuntimeException(e); 7236f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7237c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro return null; 7238f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7239f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7240f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7241d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile"; 7242d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7243d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 7244f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert * Returns an {@link AssetFileDescriptor} backed by the 7245d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * contents of the given {@link ByteArrayOutputStream}. 7246d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 7247f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) { 7248d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey try { 7249d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey stream.flush(); 7250d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7251d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final byte[] byteData = stream.toByteArray(); 7252d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7253f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 7254f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert ParcelFileDescriptor.fromData(byteData, CONTACT_MEMORY_FILE_NAME), 7255f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert byteData.length); 7256d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } catch (IOException e) { 7257ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert Log.w(TAG, "Problem writing stream into an ParcelFileDescriptor: " + e.toString()); 7258ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert return null; 7259d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7260d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7261d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7262f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd) { 7263f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor(fd, AssetFileDescriptor.UNKNOWN_LENGTH); 7264f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 7265f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 7266f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd, long length) { 7267f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return fd != null ? new AssetFileDescriptor(fd, 0, length) : null; 7268f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 7269f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 7270d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 7271d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * Output {@link RawContacts} matching the requested selection in the vCard 7272d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * format to the given {@link OutputStream}. This method returns silently if 7273d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * any errors encountered. 7274d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 7275fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen private void outputRawContactsAsVCard(Uri uri, OutputStream stream, 7276fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen String selection, String[] selectionArgs) { 7277d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final Context context = this.getContext(); 7278dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen int vcardconfig = VCardConfig.VCARD_TYPE_DEFAULT; 7279fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if(uri.getBooleanQueryParameter( 7280fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, false)) { 7281dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen vcardconfig |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT; 7282dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen } 72837a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa final VCardComposer composer = 7284dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen new VCardComposer(context, vcardconfig, false); 7285108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Writer writer = null; 72863711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen final Uri rawContactsUri; 72873711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen if (mapsToProfileDb(uri)) { 728882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Pre-authorize the URI, since the caller would have already gone through the 728982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // permission check to get here, but the pre-authorization at the top level wouldn't 729082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // carry over to the raw contact. 729182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro rawContactsUri = preAuthorizeUri(RawContactsEntity.PROFILE_CONTENT_URI); 72923711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen } else { 72933711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen rawContactsUri = RawContactsEntity.CONTENT_URI; 72943711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen } 7295108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 7296108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer = new BufferedWriter(new OutputStreamWriter(stream)); 72973711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen if (!composer.init(uri, selection, selectionArgs, null, rawContactsUri)) { 7298108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "Failed to init VCardComposer"); 7299108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa return; 7300108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 7301d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7302108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa while (!composer.isAfterLast()) { 7303108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.write(composer.createOneEntry()); 7304108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 7305108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 7306108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.e(TAG, "IOException: " + e); 7307108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } finally { 7308108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa composer.terminate(); 7309108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa if (writer != null) { 7310108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 7311108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.close(); 7312108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 7313108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "IOException during closing output stream: " + e); 7314108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 7315d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7316d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7317d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7318b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 73194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 73204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 7321415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 7322415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov waitForAccess(mReadAccessLatch); 7323415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 7324a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 73254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 7326b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS: 7327be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return Contacts.CONTENT_TYPE; 73282d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill case CONTACTS_LOOKUP: 7329b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_ID: 7330b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_LOOKUP_ID: 733124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 7332b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_ITEM_TYPE; 7333f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: 733442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: 733524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 7336f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey return Contacts.CONTENT_VCARD_TYPE; 7337f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov case CONTACTS_ID_PHOTO: 7338bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_PHOTO: 7339bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_PHOTO: 7340f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: 7341f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 7342f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: 7343f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: 7344f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: 7345f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return "image/jpeg"; 7346b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS: 734724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 7348be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return RawContacts.CONTENT_TYPE; 7349b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS_ID: 735024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 7351b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return RawContacts.CONTENT_ITEM_TYPE; 7352f481f22a9323fe338672f99b88b26c5f0725cd42David Brown case DATA: 735324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 7354f481f22a9323fe338672f99b88b26c5f0725cd42David Brown return Data.CONTENT_TYPE; 7355508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 73565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long id = ContentUris.parseId(uri); 73575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (ContactsContract.isProfileId(id)) { 73585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileHelper.getDataMimeType(id); 73595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 73605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mContactsHelper.getDataMimeType(id); 73615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 736248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES: 736348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_TYPE; 736448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 736548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_ITEM_TYPE; 73669005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov case PHONE_LOOKUP: 73679005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov return PhoneLookup.CONTENT_TYPE; 736848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS: 736948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_TYPE; 737048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 737148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_ITEM_TYPE; 737248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS: 737348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_TYPE; 737448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: 737548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_ITEM_TYPE; 7376b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 7377b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_TYPE; 7378b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 7379b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_ITEM_TYPE; 7380b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case SETTINGS: 7381b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Settings.CONTENT_TYPE; 7382b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 7383b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_TYPE; 7384c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: 7385c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SUGGEST_MIME_TYPE; 7386c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: 7387c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SHORTCUT_MIME_TYPE; 7388d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES: 7389d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_TYPE; 7390d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID: 7391d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_ITEM_TYPE; 7392af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS: 7393af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.CONTENT_TYPE; 7394af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID: 7395af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.CONTENT_ITEM_TYPE; 7396af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID_PHOTOS: 7397af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.StreamItemPhotos.CONTENT_TYPE; 7398af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID_PHOTOS_ID: 7399af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.StreamItemPhotos.CONTENT_ITEM_TYPE; 7400af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_PHOTOS: 7401af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki throw new UnsupportedOperationException("Not supported for write-only URI " + uri); 740261efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov default: 740361efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov return mLegacyApiSupport.getType(uri); 74044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 74054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 74067e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 740709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov public String[] getDefaultProjection(Uri uri) { 740809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov final int match = sUriMatcher.match(uri); 740909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov switch (match) { 741009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS: 741109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP: 741209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_ID: 741309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP_ID: 741409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 741524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 741609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsProjectionMap.getColumnNames(); 741709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 74188727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov case CONTACTS_ID_ENTITIES: 741924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: 74208727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov return sEntityProjectionMap.getColumnNames(); 74218727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov 742209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_VCARD: 742309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_MULTI_VCARD: 742424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 742509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsVCardProjectionMap.getColumnNames(); 742609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 742709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS: 742809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS_ID: 742924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 743024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 743109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sRawContactsProjectionMap.getColumnNames(); 743209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 743309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DATA_ID: 743409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES: 743509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES_ID: 743609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS: 743709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS_ID: 743809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS: 743909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS_ID: 744024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 744109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDataProjectionMap.getColumnNames(); 744209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 744309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONE_LOOKUP: 744409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sPhoneLookupProjectionMap.getColumnNames(); 744509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 744609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 744709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 744809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sAggregationExceptionsProjectionMap.getColumnNames(); 744909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 745009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case SETTINGS: 745109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sSettingsProjectionMap.getColumnNames(); 745209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 745309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES: 745409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES_ID: 745509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDirectoryProjectionMap.getColumnNames(); 745609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 745709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov default: 745809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return null; 745909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 746009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 746109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 7462f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private class StructuredNameLookupBuilder extends NameLookupBuilder { 7463f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 7464f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov public StructuredNameLookupBuilder(NameSplitter splitter) { 7465f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov super(splitter); 7466f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7467f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 7468f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 7469f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected void insertNameLookup(long rawContactId, long dataId, int lookupType, 7470f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov String name) { 74715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().insertNameLookup(rawContactId, dataId, lookupType, name); 7472f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7473f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 7474f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 7475f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected String[] getCommonNicknameClusters(String normalizedName) { 7476d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); 7477f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7478f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7479f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 74802d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) { 7481d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov sb.append("(" + 7482d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov "SELECT DISTINCT " + RawContacts.CONTACT_ID + 7483d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 7484d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " JOIN " + Tables.NAME_LOOKUP + 7485d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " ON(" + RawContactsColumns.CONCRETE_ID + "=" 7486d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov + NameLookupColumns.RAW_CONTACT_ID + ")" + 7487d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " WHERE normalized_name GLOB '"); 7488e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(NameNormalizer.normalize(filterParam)); 7489916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov sb.append("*' AND " + NameLookupColumns.NAME_TYPE + 7490916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov " IN(" + CONTACT_LOOKUP_NAME_TYPES + "))"); 7491e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 7492e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 74939a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov public boolean isPhoneNumber(String filter) { 74949a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean atLeastOneDigit = false; 74959a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov int len = filter.length(); 74969a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov for (int i = 0; i < len; i++) { 74979a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov char c = filter.charAt(i); 74989a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (c >= '0' && c <= '9') { 74999a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov atLeastOneDigit = true; 75009a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } else if (c != '*' && c != '#' && c != '+' && c != 'N' && c != '.' && c != ';' 75019a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov && c != '-' && c != '(' && c != ')' && c != ' ') { 75029a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return false; 75039a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 75049a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 75059a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return atLeastOneDigit; 75069a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 75079a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 75084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** 75097a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * Takes components of a name from the query parameters and returns a cursor with those 75107a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * components as well as all missing components. There is no database activity involved 75117a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * in this so the call can be made on the UI thread. 75127a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov */ 75137a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private Cursor completeName(Uri uri, String[] projection) { 75147a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (projection == null) { 75157a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov projection = sDataProjectionMap.getColumnNames(); 75167a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 75177a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 75187a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ContentValues values = new ContentValues(); 7519f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataRowHandlerForStructuredName handler = (DataRowHandlerForStructuredName) 7520f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov getDataRowHandler(StructuredName.CONTENT_ITEM_TYPE); 75217a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 75227a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov copyQueryParamsToContentValues(values, uri, 75237a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.DISPLAY_NAME, 75247a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PREFIX, 75257a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.GIVEN_NAME, 75267a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.MIDDLE_NAME, 75277a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.FAMILY_NAME, 75287a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.SUFFIX, 75297a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_NAME, 75307a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_FAMILY_NAME, 75317a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_MIDDLE_NAME, 75327a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_GIVEN_NAME 75337a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ); 75347a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 75357a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov handler.fixStructuredNameComponents(values, values); 75367a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 75377a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 75387a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov Object[] row = new Object[projection.length]; 75397a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 75407a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov row[i] = values.get(projection[i]); 75417a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 75427a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov cursor.addRow(row); 75437a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return cursor; 75447a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 75457a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 75467a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private void copyQueryParamsToContentValues(ContentValues values, Uri uri, String... columns) { 75477a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (String column : columns) { 75487a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov String param = uri.getQueryParameter(column); 75497a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (param != null) { 75507a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov values.put(column, param); 75517a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 75527a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 75537a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 75547a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 75557a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 75567a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov /** 75574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov * Inserts an argument at the beginning of the selection arg list. 75584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov */ 75594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private String[] insertSelectionArg(String[] selectionArgs, String arg) { 7560b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 7561b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 7562b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 7563b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 7564b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 75654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov newSelectionArgs[0] = arg; 75664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length); 7567b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 7568b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 7569b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 7570caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 75715e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar private String[] appendProjectionArg(String[] projection, String arg) { 75725e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection == null) { 75735e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return null; 75745e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 75755e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar final int length = projection.length; 75765e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar String[] newProjection = new String[length + 1]; 75775e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar System.arraycopy(projection, 0, newProjection, 0, length); 75785e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar newProjection[length] = arg; 75795e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return newProjection; 75805e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 75815e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 7582caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov protected Account getDefaultAccount() { 7583caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov AccountManager accountManager = AccountManager.get(getContext()); 7584caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov try { 75855f1f4a062ac34d75d2dbf586702cbeb121cf09caDmitri Plotnikov Account[] accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE); 7586caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov if (accounts != null && accounts.length > 0) { 7587caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov return accounts[0]; 7588caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 7589caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } catch (Throwable e) { 75906f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov Log.e(TAG, "Cannot determine the default account for contacts compatibility", e); 7591caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 75926f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov return null; 7593caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 7594f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 759573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov /** 759643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Returns true if the specified account type and data set is writable. 759773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov */ 759843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro protected boolean isWritableAccountWithDataSet(String accountTypeAndDataSet) { 759943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (accountTypeAndDataSet == null) { 7600bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov return true; 7601bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov } 7602bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov 760343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Boolean writable = mAccountWritability.get(accountTypeAndDataSet); 760473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable != null) { 760573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 760673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 760773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 7608627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov IContentService contentService = ContentResolver.getContentService(); 7609627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 761043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO(dsantoro): Need to update this logic to allow for sub-accounts. 7611627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) { 7612627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov if (ContactsContract.AUTHORITY.equals(sync.authority) && 761343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountTypeAndDataSet.equals(sync.accountType)) { 761473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = sync.supportsUploading(); 761573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov break; 7616627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7617627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7618627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } catch (RemoteException e) { 7619627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov Log.e(TAG, "Could not acquire sync adapter types"); 7620627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 762173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 762273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable == null) { 762373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = false; 762473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 762573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 762643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mAccountWritability.put(accountTypeAndDataSet, writable); 762773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 7628627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7629b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov 7630d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 7631f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter, 7632f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean defaultValue) { 7633f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7634f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov // Manually parse the query, which is much faster than calling uri.getQueryParameter 7635f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 7636f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 7637f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 7638f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7639f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7640f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = query.indexOf(parameter); 7641f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 7642f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 7643f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7644f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7645f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameter.length(); 7646f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7647f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return !matchQueryParameter(query, index, "=0", false) 7648f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && !matchQueryParameter(query, index, "=false", true); 7649f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7650f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7651f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private static boolean matchQueryParameter(String query, int index, String value, 7652f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean ignoreCase) { 7653f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int length = value.length(); 7654f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return query.regionMatches(ignoreCase, index, value, 0, length) 7655f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && (query.length() == index + length || query.charAt(index + length) == '&'); 7656f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7657f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7658f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /** 7659f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * A fast re-implementation of {@link Uri#getQueryParameter} 7660f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov */ 7661f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static String getQueryParameter(Uri uri, String parameter) { 7662f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 7663f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 7664f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7665f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7666f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7667f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int queryLength = query.length(); 7668f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int parameterLength = parameter.length(); 7669f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7670f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String value; 7671f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = 0; 7672f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov while (true) { 7673f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index = query.indexOf(parameter, index); 7674f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 7675f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 76765fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 76775fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa 76785fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // Should match against the whole parameter instead of its suffix. 76795fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // e.g. The parameter "param" must not be found in "some_param=val". 76805fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (index > 0) { 76815fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa char prevChar = query.charAt(index - 1); 76825fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (prevChar != '?' && prevChar != '&') { 76835fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // With "some_param=val1¶m=val2", we should find second "param" occurrence. 76845fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa index += parameterLength; 76855fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa continue; 76865fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 7687f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7688f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7689f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameterLength; 7690f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7691f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (queryLength == index) { 7692f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7693f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7694f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7695f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query.charAt(index) == '=') { 7696f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index++; 7697f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov break; 7698f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7699f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7700f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7701f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int ampIndex = query.indexOf('&', index); 7702f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (ampIndex == -1) { 7703f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index); 7704f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } else { 7705f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index, ampIndex); 7706f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7707f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7708f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return Uri.decode(value); 7709f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 77105dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 77110dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov protected boolean isAggregationUpgradeNeeded() { 77120dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov if (!mContactAggregator.isEnabled()) { 77130dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return false; 77140dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 77150dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 77165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int version = Integer.parseInt(mContactsHelper.getProperty( 77175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROPERTY_AGGREGATION_ALGORITHM, "1")); 77180dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return version < PROPERTY_AGGREGATION_ALGORITHM_VERSION; 77190dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 77200dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 7721bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void upgradeAggregationAlgorithmInBackground() { 77220dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // This upgrade will affect very few contacts, so it can be performed on the 77230dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // main thread during the initial boot after an OTA 77240dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 77250dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Upgrading aggregation algorithm"); 77260dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int count = 0; 77270dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long start = SystemClock.currentThreadTimeMillis(); 77285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = null; 77290dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 77305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 77315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db = mContactsHelper.getWritableDatabase(); 77325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(db); 77335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.beginTransaction(); 77345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = db.query(true, 77350dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Tables.RAW_CONTACTS + " r1 JOIN " + Tables.RAW_CONTACTS + " r2", 77360dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov new String[]{"r1." + RawContacts._ID}, 77370dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov "r1." + RawContacts._ID + "!=r2." + RawContacts._ID + 77380dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.CONTACT_ID + "=r2." + RawContacts.CONTACT_ID + 77390dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.ACCOUNT_NAME + "=r2." + RawContacts.ACCOUNT_NAME + 774043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND r1." + RawContacts.ACCOUNT_TYPE + "=r2." + RawContacts.ACCOUNT_TYPE + 774143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND r1." + RawContacts.DATA_SET + "=r2." + RawContacts.DATA_SET, 77420dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov null, null, null, null, null); 77430dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 77440dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov while (cursor.moveToNext()) { 77450dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long rawContactId = cursor.getLong(0); 77460dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, 77470dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 77480dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov count++; 77490dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 77500dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 77510dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov cursor.close(); 77520dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 77535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator.aggregateInTransaction(mTransactionContext.get(), db); 7754bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 77555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.setTransactionSuccessful(); 77565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.setProperty(PROPERTY_AGGREGATION_ALGORITHM, 77570dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov String.valueOf(PROPERTY_AGGREGATION_ALGORITHM_VERSION)); 77580dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 77595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (db != null) { 77605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.endTransaction(); 77615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 77620dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long end = SystemClock.currentThreadTimeMillis(); 77630dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Aggregation algorithm upgraded for " + count 77640dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov + " contacts, in " + (end - start) + "ms"); 77650dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 77660dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 77679a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 77689a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov /* Visible for testing */ 77699a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean isPhone() { 77709a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (!sIsPhoneInitialized) { 77719a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhone = new TelephonyManager(getContext()).isVoiceCapable(); 77729a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhoneInitialized = true; 77739a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 77749a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return sIsPhone; 77759a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 777646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 777746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private boolean handleDataUsageFeedback(Uri uri) { 777846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final long currentTimeMillis = System.currentTimeMillis(); 777946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 778046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] ids = uri.getLastPathSegment().trim().split(","); 778146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ArrayList<Long> dataIds = new ArrayList<Long>(); 778246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 778346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (String id : ids) { 778446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa dataIds.add(Long.valueOf(id)); 778546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 778646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final boolean successful; 778746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (TextUtils.isEmpty(usageType)) { 778846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.w(TAG, "Method for data usage feedback isn't specified. Ignoring."); 778946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = false; 779046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 779146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = updateDataUsageStat(dataIds, usageType, currentTimeMillis) > 0; 779246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 779346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 779446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Handle old API. This doesn't affect the result of this entire method. 779546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] questionMarks = new String[ids.length]; 779646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Arrays.fill(questionMarks, "?"); 779746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = Data._ID + " IN (" + TextUtils.join(",", questionMarks) + ")"; 77985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final Cursor cursor = mActiveDb.get().query( 7799ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA, 780046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { Data.CONTACT_ID }, 780146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa where, ids, null, null, null); 780246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 780346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa while (cursor.moveToNext()) { 780446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mSelectionArgs1[0] = cursor.getString(0); 780546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa ContentValues values2 = new ContentValues(); 780646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values2.put(Contacts.LAST_TIME_CONTACTED, currentTimeMillis); 78075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().update(Tables.CONTACTS, values2, Contacts._ID + "=?", 78085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mSelectionArgs1); 78095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 78105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 781146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 781246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 781346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 781446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 781546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 781646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return successful; 781746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 781846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 781946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 782046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Update {@link Tables#DATA_USAGE_STAT}. 782146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * 782246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @return the number of rows affected. 782346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 7824f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa @VisibleForTesting 7825f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa /* package */ int updateDataUsageStat( 7826f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa List<Long> dataIds, String type, long currentTimeMillis) { 782746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final int typeInt = sDataUsageTypeMap.get(type); 782846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = DataUsageStatColumns.DATA_ID + " =? AND " 782946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT + " =?"; 783046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] columns = 783146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { DataUsageStatColumns._ID, DataUsageStatColumns.TIMES_USED }; 783246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ContentValues values = new ContentValues(); 783346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (Long dataId : dataIds) { 783446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] args = new String[] { dataId.toString(), String.valueOf(typeInt) }; 78355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().beginTransaction(); 783646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 78375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final Cursor cursor = mActiveDb.get().query(Tables.DATA_USAGE_STAT, columns, where, 78385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro args, null, null, null); 783946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 784046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (cursor.getCount() > 0) { 784146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!cursor.moveToFirst()) { 784246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.e(TAG, 784346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa "moveToFirst() failed while getAccount() returned non-zero."); 784446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 784546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 784646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, cursor.getInt(1) + 1); 784746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 78485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().update(Tables.DATA_USAGE_STAT, values, 784946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns._ID + " =?", 785046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { cursor.getString(0) }); 785146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 785246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 785346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 785446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.DATA_ID, dataId); 785546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.USAGE_TYPE_INT, typeInt); 785646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, 1); 785746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 78585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().insert(Tables.DATA_USAGE_STAT, null, values); 785946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 78605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().setTransactionSuccessful(); 786146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 786246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 786346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 786446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 78655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().endTransaction(); 786646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 786746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 786846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 786946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return dataIds.size(); 787046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 787146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 787246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 787346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Returns a sort order String for promoting data rows (email addresses, phone numbers, etc.) 787446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * associated with a primary account. The primary account should be supplied from applications 787546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * with {@link ContactsContract#PRIMARY_ACCOUNT_NAME} and 787646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * {@link ContactsContract#PRIMARY_ACCOUNT_TYPE}. Null will be returned when the primary 787746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * account isn't available. 787846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 787946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private String getAccountPromotionSortOrder(Uri uri) { 788046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountName = 788146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME); 788246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountType = 788346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE); 788446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 788546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Data rows associated with primary account should be promoted. 788646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountName)) { 788746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa StringBuilder sb = new StringBuilder(); 788846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append("(CASE WHEN " + RawContacts.ACCOUNT_NAME + "="); 788946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountName); 789046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountType)) { 789146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 789246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountType); 789346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 789446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" THEN 0 ELSE 1 END)"); 789546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return sb.toString(); 789646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 789746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return null; 789846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 789946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 7900b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 7901b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson /** 7902b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * Checks the URI for a deferred snippeting request 7903b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * @return a boolean indicating if a deferred snippeting request is in the RI 7904b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson */ 7905b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private boolean deferredSnippetingRequested(Uri uri) { 7906b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson String deferredSnippeting = 7907b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson getQueryParameter(uri, SearchSnippetColumns.DEFERRED_SNIPPETING_KEY); 7908b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return !TextUtils.isEmpty(deferredSnippeting) && deferredSnippeting.equals("1"); 7909b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 7910b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 7911b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson /** 7912b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * Checks if query is a single word or not. 7913b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * @return a boolean indicating if the query is one word or not 7914b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson */ 7915b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private boolean isSingleWordQuery(String query) { 7916b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return query.split(QUERY_TOKENIZER_REGEX).length == 1; 7917b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 7918b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 7919b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson /** 7920b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * Checks the projection for a SNIPPET column indicating that a snippet is needed 7921b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * @return a boolean indicating if a snippet is needed or not. 7922b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson */ 7923b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private boolean snippetNeeded(String [] projection) { 7924b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return mDbHelper.get().isInProjection(projection, SearchSnippetColumns.SNIPPET); 7925b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 79264f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 7927