ContactsProvider2.java revision 5d0a768b56ed4bd0dfef81b8389247ba74766659
14f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/* 24f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Copyright (C) 2009 The Android Open Source Project 34f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * 44f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License"); 54f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * you may not use this file except in compliance with the License. 64f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * You may obtain a copy of the License at 74f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * 84f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * http://www.apache.org/licenses/LICENSE-2.0 94f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * 104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Unless required by applicable law or agreed to in writing, software 114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS, 124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * See the License for the specific language governing permissions and 144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * limitations under the License 154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarpackage com.android.providers.contacts; 1828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar 19d9ec58265ae59a549880ef63cdfb5d0d977cdabaDmitri Plotnikovimport com.android.common.content.SQLiteContentProvider; 2053214b3ed12b0ff9cb589b6559311f2ac142f2e3Bjorn Bringertimport com.android.common.content.SyncStateContentProviderHelper; 215b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport com.android.providers.contacts.ContactAggregator.AggregationSuggestionParameter; 2297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactLookupKey.LookupKeySegment; 2324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns; 2497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns; 2597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; 2697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Clauses; 2797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns; 2897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsStatusUpdatesColumns; 2997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; 3071340347b4862d4b1368a5d69d1667e2245952e4Daisuke Miyakawaimport com.android.providers.contacts.ContactsDatabaseHelper.DataUsageStatColumns; 3197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns; 322f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawaimport com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns; 3397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns; 3497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType; 3597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneColumns; 3697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; 371dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.PhotoFilesColumns; 3897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 3997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 4003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SearchIndexColumns; 4197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SettingsColumns; 4297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns; 433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemPhotosColumns; 44f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemsColumns; 4597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables; 46ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmannimport com.android.providers.contacts.ContactsDatabaseHelper.Views; 472f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawaimport com.android.providers.contacts.util.DbQueryUtils; 4897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardComposer; 4997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardConfig; 5097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Lists; 5197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Maps; 5297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Sets; 53f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawaimport com.google.common.annotations.VisibleForTesting; 5497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 55b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account; 56caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager; 575b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanaimport android.accounts.OnAccountsUpdateListener; 58bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.Notification; 59bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.NotificationManager; 60bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.PendingIntent; 61c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager; 62568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation; 63568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult; 646ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.content.ContentResolver; 6535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris; 6667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues; 6767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context; 68627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.IContentService; 69bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.content.Intent; 70568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException; 713d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences; 72627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.SyncAdapterType; 7367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher; 740bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.pm.PackageManager; 750bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.pm.PackageManager.NameNotFoundException; 765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoroimport android.content.pm.ProviderInfo; 77f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringertimport android.content.res.AssetFileDescriptor; 783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.content.res.Resources; 790bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.res.Resources.NotFoundException; 80e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikovimport android.database.CrossProcessCursor; 814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor; 82e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikovimport android.database.CursorWindow; 83ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.database.CursorWrapper; 84ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils; 8509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor; 8609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor.RowBuilder; 874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase; 8808ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwoodimport android.database.sqlite.SQLiteDoneException; 895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoroimport android.database.sqlite.SQLiteOpenHelper; 904f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder; 91f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.Bitmap; 92f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.BitmapFactory; 934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri; 94d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.net.Uri.Builder; 95c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoroimport android.os.AsyncTask; 96bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Binder; 976ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.os.Bundle; 98bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Handler; 99bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.HandlerThread; 100bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Message; 101ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringertimport android.os.ParcelFileDescriptor; 102c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoroimport android.os.ParcelFileDescriptor.AutoCloseInputStream; 103bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Process; 104b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException; 10515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikovimport android.os.StrictMode; 1060dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikovimport android.os.SystemClock; 1070e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport android.os.SystemProperties; 1083d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager; 109508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns; 1103de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract; 111b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions; 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; 13409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.provider.ContactsContract.ProviderStatus; 1353de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.RawContacts; 136916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikovimport android.provider.ContactsContract.SearchSnippetColumns; 1373de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Settings; 13882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikovimport android.provider.ContactsContract.StatusUpdates; 1393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.provider.ContactsContract.StreamItemPhotos; 140f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.StreamItems; 14197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.LiveFolders; 14297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.OpenableColumns; 14397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.SyncStateContract; 144a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils; 1459a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikovimport android.telephony.TelephonyManager; 146d5ef5903570e533a501abe6a8e3d533fdb5318fcFlavio Lerdaimport android.text.Html; 147d5ef5903570e533a501abe6a8e3d533fdb5318fcFlavio Lerdaimport android.text.SpannableString; 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; 1690e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.Set; 170ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch; 1714f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/** 1734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications 1744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}. 1754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 1765b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanapublic class ContactsProvider2 extends SQLiteContentProvider implements OnAccountsUpdateListener { 177caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 178bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov private static final String TAG = "ContactsProvider"; 179bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov 180bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE); 1814f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 18215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_INITIALIZE = 0; 18315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_OPEN_WRITE_ACCESS = 1; 18415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS = 2; 18515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_ACCOUNTS = 3; 18615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_LOCALE = 4; 18715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM = 5; 18805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_SEARCH_INDEX = 6; 18905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_PROVIDER_STATUS = 7; 19005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_DIRECTORIES = 8; 19105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_CHANGE_LOCALE = 9; 192f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int BACKGROUND_TASK_CLEANUP_PHOTOS = 10; 193619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** Default for the maximum number of returned aggregation suggestions. */ 1953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DEFAULT_MAX_SUGGESTIONS = 5; 1963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 1973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Limit for the maximum number of social stream items to store under a raw contact. */ 1983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int MAX_STREAM_ITEMS_PER_RAW_CONTACT = 5; 1993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 200f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Rate limit (in ms) for photo cleanup. Do it at most once per day. */ 201f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_CLEANUP_RATE_LIMIT = 24 * 60 * 60 * 1000; 202f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 2033d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /** 204b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov * Property key for the legacy contact import version. The need for a version 2053d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov * as opposed to a boolean flag is that if we discover bugs in the contact import process, 2063d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov * we can trigger re-import by incrementing the import version. 2073d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov */ 208b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov private static final String PROPERTY_CONTACTS_IMPORTED = "contacts_imported_v1"; 209b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov private static final int PROPERTY_CONTACTS_IMPORT_VERSION = 1; 21051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov private static final String PREF_LOCALE = "locale"; 2113d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2120dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final String PROPERTY_AGGREGATION_ALGORITHM = "aggregation_v2"; 2130dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final int PROPERTY_AGGREGATION_ALGORITHM_VERSION = 2; 2140dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 2150e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate"; 2160e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff 2175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final ProfileAwareUriMatcher sUriMatcher = 2185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ProfileAwareUriMatcher(UriMatcher.NO_MATCH); 2194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2202f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 2212f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * Used to insert a column into strequent results, which enables SQL to sort the list using 2222f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * the total times contacted. See also {@link #sStrequentFrequentProjectionMap}. 2232f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 2242f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private static final String TIMES_USED_SORT_COLUMN = "times_used_sort"; 2255e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 226d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, " 2272f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa + TIMES_USED_SORT_COLUMN + " DESC, " 2289b43551f1ce33b79141772737a262ce609bd0cebMegha Joshi + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 229d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar private static final String STREQUENT_LIMIT = 230d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE " 231d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov + Contacts.STARRED + "=1) + 25"; 232d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov 23345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final String FREQUENT_ORDER_BY = DataUsageStatColumns.TIMES_USED + " DESC," 23445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 23545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 2366e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE = 2379b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.CONTACTS + " SET " + Contacts.TIMES_CONTACTED + "=" + 2389b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " CASE WHEN " + Contacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " + 2399b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " (" + Contacts.TIMES_CONTACTED + " + 1) END WHERE " + Contacts._ID + "=?"; 2409b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 2416e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE = 2429b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.RAW_CONTACTS + " SET " + RawContacts.TIMES_CONTACTED + "=" + 2439b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " CASE WHEN " + RawContacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " + 2449b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori " (" + RawContacts.TIMES_CONTACTED + " + 1) END WHERE " + RawContacts.CONTACT_ID + "=?"; 2459b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 246de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK"; 247de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa 2483716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Regex for splitting query strings - we split on any group of non-alphanumeric characters, 2493716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // excluding the @ symbol. 2503716f1447ceb21180d1301790eabd8b9453f486dDave Santoro /* package */ static final String QUERY_TOKENIZER_REGEX = "[^\\w@]+"; 2513716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 252d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS = 1000; 253d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS_ID = 1001; 2545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP = 1002; 2555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP_ID = 1003; 256a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_DATA = 1004; 2575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_FILTER = 1005; 2585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT = 1006; 2595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT_FILTER = 1007; 2605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_GROUP = 1008; 261a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_PHOTO = 1009; 262f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_DISPLAY_PHOTO = 1010; 263f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_DISPLAY_PHOTO = 1011; 264f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_DISPLAY_PHOTO = 1012; 265f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_AS_VCARD = 1013; 266f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_AS_MULTI_VCARD = 1014; 267f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_DATA = 1015; 268f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_DATA = 1016; 269f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_ENTITIES = 1017; 270f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ENTITIES = 1018; 271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_ENTITIES = 1019; 272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_ID_STREAM_ITEMS = 1020; 273f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_STREAM_ITEMS = 1021; 274f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int CONTACTS_LOOKUP_ID_STREAM_ITEMS = 1022; 27545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final int CONTACTS_FREQUENT = 1023; 2764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2775ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS = 2002; 2785ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_ID = 2003; 2795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_DATA = 2004; 28046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITY_ID = 2005; 281f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_DISPLAY_PHOTO = 2006; 282f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS = 2007; 2834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2846bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 2856bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 286ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 28748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_ID = 3003; 28848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_FILTER = 3004; 28948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS = 3005; 29048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_ID = 3006; 29148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_LOOKUP = 3007; 29248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_FILTER = 3008; 29348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS = 3009; 29448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS_ID = 3010; 295a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 2976bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 298b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 299b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 300b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 30182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES = 7000; 30282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES_ID = 7001; 3031f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 30431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 30531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 306eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey private static final int SETTINGS = 9000; 307eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 308ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 309ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 310ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 311ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 31235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 313b5a4add17815167d20a90645779df34cdf45280dFred Quintana private static final int SYNCSTATE_ID = 11001; 3145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_SYNCSTATE = 11002; 3155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_SYNCSTATE_ID = 11003; 31635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 317c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SUGGESTIONS = 12001; 318c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SHORTCUT = 12002; 319c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 3201b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS = 14000; 3211b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001; 3221b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002; 3231b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003; 3241b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 32546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITIES = 15001; 32646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 32709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private static final int PROVIDER_STATUS = 16001; 32809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 329d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES = 17001; 330d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES_ID = 17002; 331d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 3327a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private static final int COMPLETE_NAME = 18000; 3337a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 33424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE = 19000; 33524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_ENTITIES = 19001; 33624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA = 19002; 33724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA_ID = 19003; 33824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_AS_VCARD = 19004; 33924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS = 19005; 34024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID = 19006; 34124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_DATA = 19007; 34224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_ENTITIES = 19008; 3435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_STATUS_UPDATES = 19009; 34424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 34546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final int DATA_USAGE_FEEDBACK_ID = 20001; 34646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 3473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS = 21000; 3483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_PHOTOS = 21001; 3493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID = 21002; 3503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS = 21003; 3513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS_ID = 21004; 3523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_LIMIT = 21005; 3533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 354f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int DISPLAY_PHOTO = 22000; 355f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_DIMENSIONS = 22001; 356f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 3575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Inserts into URIs in this map will direct to the profile database if the parent record's 3585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // value (looked up from the ContentValues object with the key specified by the value in this 3595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // map) is in the profile ID-space (see {@link ProfileDatabaseHelper#PROFILE_ID_SPACE}). 3605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final Map<Integer, String> INSERT_URI_ID_VALUE_MAP = Maps.newHashMap(); 3615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro static { 3625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(DATA, Data.RAW_CONTACT_ID); 3635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(RAW_CONTACTS_DATA, Data.RAW_CONTACT_ID); 3645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STATUS_UPDATES, StatusUpdates.DATA_ID); 3655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS, StreamItems.RAW_CONTACT_ID); 3665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(RAW_CONTACTS_ID_STREAM_ITEMS, StreamItems.RAW_CONTACT_ID); 3675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID); 3685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS_ID_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID); 3695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 3705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 371dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID = 372dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 373dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME 374dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "=" + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 375dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE 37643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + "=" + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND (" 37743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET 37843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + "=" + RawContactsColumns.CONCRETE_DATA_SET + " OR " 37943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 38043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " IS NULL)" 381dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND " + Groups.FAVORITES + " != 0"; 382dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 383dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID = 384dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 385dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 386dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND " 387dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 38843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND (" 38943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + "=" 39043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " OR " 39143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + GroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 39243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContactsColumns.CONCRETE_DATA_SET + " IS NULL)" 39343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + " AND " + Groups.AUTO_ADD + " != 0"; 394dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 395dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String[] PROJECTION_GROUP_ID 396dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana = new String[]{Tables.GROUPS + "." + Groups._ID}; 397dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 398dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_GROUPMEMBERSHIP_DATA = DataColumns.MIMETYPE_ID + "=? " 399dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.GROUP_ROW_ID + "=? " 400dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.RAW_CONTACT_ID + "=?"; 401dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 402dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_STARRED_FROM_RAW_CONTACTS = 403dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana "SELECT " + RawContacts.STARRED 404dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " FROM " + Tables.RAW_CONTACTS + " WHERE " + RawContacts._ID + "=?"; 405dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 406e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public class AddressBookCursor extends CursorWrapper implements CrossProcessCursor { 407e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov private final CrossProcessCursor mCursor; 408e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov private final Bundle mBundle; 409e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 410e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public AddressBookCursor(CrossProcessCursor cursor, String[] titles, int[] counts) { 411e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov super(cursor); 412e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mCursor = cursor; 413e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle = new Bundle(); 414e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle.putStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES, titles); 415e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mBundle.putIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, counts); 416e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 417e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 418e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 419e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public Bundle getExtras() { 420e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mBundle; 421e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 422e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 423e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 424e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public void fillWindow(int pos, CursorWindow window) { 425e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov mCursor.fillWindow(pos, window); 426e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 427e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 428e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 429e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public CursorWindow getWindow() { 430e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mCursor.getWindow(); 431e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 432e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 433e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov @Override 434e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov public boolean onMove(int oldPosition, int newPosition) { 435e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return mCursor.onMove(oldPosition, newPosition); 436e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 437e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov } 438e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov 439d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private interface DataContactsQuery { 440f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov public static final String TABLE = "data " 441f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) " 442f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)"; 44367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 44467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 4456cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov RawContactsColumns.CONCRETE_ID, 4466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_TYPE, 4476802030a777c0c3ba1dc029c534cca4784260632Dave Santoro RawContactsColumns.CONCRETE_ACCOUNT_NAME, 44843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContactsColumns.CONCRETE_DATA_SET, 4493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 450f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov ContactsColumns.CONCRETE_ID 451ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 452ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 453d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov public static final int RAW_CONTACT_ID = 0; 4546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_TYPE = 1; 4556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_NAME = 2; 45643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_SET = 3; 45743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_ID = 4; 45843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int CONTACT_ID = 5; 459ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 4601f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 461f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov interface RawContactsQuery { 46219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String TABLE = Tables.RAW_CONTACTS; 46319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 46419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String[] COLUMNS = new String[] { 465ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.DELETED, 466ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_TYPE, 467ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.ACCOUNT_NAME, 46843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.DATA_SET, 46919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka }; 47019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 47119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int DELETED = 0; 472ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_TYPE = 1; 473ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov int ACCOUNT_NAME = 2; 47443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int DATA_SET = 3; 47519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 47619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 477c76cdd0723b99f478c9ba5329d14a971cd8dfb3dCostin Manolache public static final String DEFAULT_ACCOUNT_TYPE = "com.google"; 478caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 47971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov /** Sql where statement for filtering on groups. */ 48071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov private static final String CONTACTS_IN_GROUP_SELECT = 48171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov Contacts._ID + " IN " 48271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + RawContacts.CONTACT_ID 48371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.RAW_CONTACTS 48471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN " 48571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 48671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.DATA_JOIN_MIMETYPES 48771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE 48871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "' AND " + GroupMembership.GROUP_ROW_ID + "=" 48971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + Tables.GROUPS + "." + Groups._ID 49071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.GROUPS 49171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Groups.TITLE + "=?)))"; 49271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov 493a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating DIRTY flag on multiple raw contacts */ 494a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_DIRTY_SQL = 495a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 496a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.DIRTY + "=1" + 497a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 498a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 499a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating VERSION on multiple raw contacts */ 500a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL = 501a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 502a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.VERSION + " = " + RawContacts.VERSION + " + 1" + 503a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 504a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 505c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Current contacts - those contacted within the last 3 days (in seconds) 506c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_CURRENT = 3 * 24 * 60 * 60; 507c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 508c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Recent contacts - those contacted within the last 30 days (in seconds) 509c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_RECENT = 30 * 24 * 60 * 60; 510c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 511f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa private static final String TIME_SINCE_LAST_USED = 512f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa "(strftime('%s', 'now') - " + DataUsageStatColumns.LAST_TIME_USED + "/1000)"; 513f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa 514c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov /* 515c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * Sorting order for email address suggestions: first starred, then the rest. 5162262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * second in_visible_group, then the rest. 5172262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * Within the four (starred/unstarred, in_visible_group/not-in_visible_group) groups 5182262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa * - three buckets: very recently contacted, then fairly 519c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * recently contacted, then the rest. Within each of the bucket - descending count 52046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * of times contacted (both for data row and for contact row). If all else fails, alphabetical. 52146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * (Super)primary email address is returned before other addresses for the same contact. 522c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov */ 523c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final String EMAIL_FILTER_SORT_ORDER = 5242262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa Contacts.STARRED + " DESC, " 5252262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa + Contacts.IN_VISIBLE_GROUP + " DESC, " 526f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + "(CASE WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_CURRENT 52746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 0 " 528f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + " WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_RECENT 52946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 1 " 53046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " ELSE 2 END), " 53146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.TIMES_USED + " DESC, " 53246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Contacts.DISPLAY_NAME + ", " 53346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Data.CONTACT_ID + ", " 534c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_SUPER_PRIMARY + " DESC, " 535c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_PRIMARY + " DESC"; 53646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 53746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** Currently same as {@link #EMAIL_FILTER_SORT_ORDER} */ 53846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final String PHONE_FILTER_SORT_ORDER = EMAIL_FILTER_SORT_ORDER; 539c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 540916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Name lookup types used for contact filtering */ 541916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private static final String CONTACT_LOOKUP_NAME_TYPES = 542916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.NAME_COLLATION_KEY + "," + 543916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.EMAIL_BASED_NICKNAME + "," + 54492ddc5cdc4d89ee2c6e861ae7b3a3a913ffa0100Dmitri Plotnikov NameLookupType.NICKNAME; 545916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 546f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov /** 547f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * If any of these columns are used in a Data projection, there is no point in 548f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * using the DISTINCT keyword, which can negatively affect performance. 549f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov */ 550f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov private static final String[] DISTINCT_DATA_PROHIBITING_COLUMNS = { 551f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data._ID, 552f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.RAW_CONTACT_ID, 553f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.NAME_RAW_CONTACT_ID, 554f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 555f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 55643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.DATA_SET, 55743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 558f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.DIRTY, 559f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.NAME_VERIFIED, 560f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.SOURCE_ID, 561f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.VERSION, 562f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov }; 563916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 564f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsColumns = ProjectionMap.builder() 565f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CUSTOM_RINGTONE) 566f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME) 567f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_ALTERNATIVE) 568f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_SOURCE) 569f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.IN_VISIBLE_GROUP) 570f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LAST_TIME_CONTACTED) 571f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LOOKUP_KEY) 572f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME) 573f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME_STYLE) 574f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHOTO_ID) 575f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .add(Contacts.PHOTO_FILE_ID) 5763d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_URI) 5773d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_THUMBNAIL_URI) 578f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SEND_TO_VOICEMAIL) 579f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_ALTERNATIVE) 580f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_PRIMARY) 581f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.STARRED) 582f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.TIMES_CONTACTED) 583cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 584f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 585f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 586f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsPresenceColumns = ProjectionMap.builder() 587f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 588f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE) 589f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 590f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 591f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 592f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 593f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 594f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 595f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 596f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 597f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 598f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 599f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 600f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 601f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 602f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 603f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSnippetColumns = ProjectionMap.builder() 60403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov .add(SearchSnippetColumns.SNIPPET) 605f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 606f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 607f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactColumns = ProjectionMap.builder() 608f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_NAME) 609f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_TYPE) 61043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.DATA_SET) 61143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.ACCOUNT_TYPE_AND_DATA_SET) 612f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DIRTY) 613f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.NAME_VERIFIED) 614f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SOURCE_ID) 615f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.VERSION) 616f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 617f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 618f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactSyncColumns = ProjectionMap.builder() 619f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC1) 620f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC2) 621f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC3) 622f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC4) 623f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 624f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 625f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataColumns = ProjectionMap.builder() 626f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA1) 627f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA2) 628f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA3) 629f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA4) 630f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA5) 631f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA6) 632f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA7) 633f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA8) 634f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA9) 635f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA10) 636f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA11) 637f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA12) 638f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA13) 639f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA14) 640f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA15) 641f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA_VERSION) 642f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_PRIMARY) 643f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_SUPER_PRIMARY) 644f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.MIMETYPE) 645f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RES_PACKAGE) 646f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC1) 647f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC2) 648f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC3) 649f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC4) 650f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(GroupMembership.GROUP_SOURCE_ID) 651f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 652f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 653f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactPresenceColumns = ProjectionMap.builder() 654f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 655f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.PRESENCE) 656f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 657f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.CHAT_CAPABILITY) 658f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 659f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 660f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 661f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 662f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 663f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 664f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 665f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 666f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 667f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 668f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 669f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 670f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataPresenceColumns = ProjectionMap.builder() 671f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.PRESENCE, Tables.PRESENCE + "." + StatusUpdates.PRESENCE) 672f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CHAT_CAPABILITY, Tables.PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 673f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS, StatusUpdatesColumns.CONCRETE_STATUS) 674f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_TIMESTAMP, StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 675f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_RES_PACKAGE, StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 676f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_LABEL, StatusUpdatesColumns.CONCRETE_STATUS_LABEL) 677f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_ICON, StatusUpdatesColumns.CONCRETE_STATUS_ICON) 678f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 679f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 680038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana /** Contains just BaseColumns._COUNT */ 681f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sCountProjectionMap = ProjectionMap.builder() 682f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(BaseColumns._COUNT, "COUNT(*)") 683f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 684f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 685e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov /** Contains just the contacts columns */ 686f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionMap = ProjectionMap.builder() 687f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts._ID) 688f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 689f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.NAME_RAW_CONTACT_ID) 69024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 691f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 692f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsPresenceColumns) 693f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 694f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 695916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Contains just the contacts columns */ 696f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionWithSnippetMap = ProjectionMap.builder() 697f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 698f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sSnippetColumns) 699f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 700916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 7015e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar /** Used for pushing starred contacts to the top of a times contacted list **/ 702f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentStarredProjectionMap = ProjectionMap.builder() 703f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 7042f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 705f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 706f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 707f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder() 708f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 7092f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, "SUM(" + DataUsageStatColumns.CONCRETE_TIMES_USED + ")") 710f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 711f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7124928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 7134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 7144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. Right now Starred part just returns NULL for 7154928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * those data columns (frequent part should return real ones in data table). 7164928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 7174928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyStarredProjectionMap 7184928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 7194928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 7204928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 7214928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER, "NULL") 7224928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE, "NULL") 7234928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL, "NULL") 7244928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7254928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 7264928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 7274928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 7284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. We hard-code {@link Contacts#IS_USER_PROFILE} to NULL, 7294928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * because sContactsProjectionMap specifies a field that doesn't exist in the view behind the 7304928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * query that uses this projection map. 7314928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 7324928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyFrequentProjectionMap 7334928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 7344928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 7354928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, DataUsageStatColumns.CONCRETE_TIMES_USED) 7364928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER) 7374928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE) 7384928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL) 7394928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Contacts.IS_USER_PROFILE, "NULL") 7404928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7414928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 742f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey /** Contains just the contacts vCard columns */ 743f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsVCardProjectionMap = ProjectionMap.builder() 744fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen .add(Contacts._ID) 745f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME + " || '.vcf'") 746f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.SIZE, "NULL") 747f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 748f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 749ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov /** Contains just the raw contacts columns */ 750f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactsProjectionMap = ProjectionMap.builder() 751f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 752f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 753f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 754f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_PRIMARY) 755f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_ALTERNATIVE) 756f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_SOURCE) 757f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME) 758f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME_STYLE) 759f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_PRIMARY) 760f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_ALTERNATIVE) 761f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.TIMES_CONTACTED) 762f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.LAST_TIME_CONTACTED) 763f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CUSTOM_RINGTONE) 764f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SEND_TO_VOICEMAIL) 765f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 766f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.AGGREGATION_MODE) 76724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 768f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 769f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 770f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 771f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 772a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the raw entity view*/ 773f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawEntityProjectionMap = ProjectionMap.builder() 774f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 775f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 776f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.Entity.DATA_ID) 777f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 778f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 77924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 780f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 781f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 782f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 783f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 784f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 785a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the contact entity view*/ 786f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sEntityProjectionMap = ProjectionMap.builder() 787f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity._ID) 788f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.CONTACT_ID) 789f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.RAW_CONTACT_ID) 790f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DATA_ID) 791f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.NAME_RAW_CONTACT_ID) 792f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DELETED) 79324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 794f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 795f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 796f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 797f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 798f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 799f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 800f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 801f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 8024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** Contains columns from the data view */ 803f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataProjectionMap = ProjectionMap.builder() 804f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID) 805f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RAW_CONTACT_ID) 806f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CONTACT_ID) 807f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.NAME_RAW_CONTACT_ID) 80824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 809f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 810f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 811f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 812f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 813f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 814f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 815f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 8165e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov /** Contains columns from the data view */ 817f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDistinctDataProjectionMap = ProjectionMap.builder() 818f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID, "MIN(" + Data._ID + ")") 819f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 82024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 821f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 822f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 823f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 824f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 825f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 826f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 8279261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data and contacts columns, for joined tables */ 828f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sPhoneLookupProjectionMap = ProjectionMap.builder() 829f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup._ID, "contacts_view." + Contacts._ID) 830f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LOOKUP_KEY, "contacts_view." + Contacts.LOOKUP_KEY) 831f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.DISPLAY_NAME, "contacts_view." + Contacts.DISPLAY_NAME) 832f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LAST_TIME_CONTACTED, "contacts_view." + Contacts.LAST_TIME_CONTACTED) 833f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TIMES_CONTACTED, "contacts_view." + Contacts.TIMES_CONTACTED) 834f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.STARRED, "contacts_view." + Contacts.STARRED) 835f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.IN_VISIBLE_GROUP, "contacts_view." + Contacts.IN_VISIBLE_GROUP) 836f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.PHOTO_ID, "contacts_view." + Contacts.PHOTO_ID) 8373d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_URI, "contacts_view." + Contacts.PHOTO_URI) 8383d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_THUMBNAIL_URI, "contacts_view." + Contacts.PHOTO_THUMBNAIL_URI) 839f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.CUSTOM_RINGTONE, "contacts_view." + Contacts.CUSTOM_RINGTONE) 840f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.HAS_PHONE_NUMBER, "contacts_view." + Contacts.HAS_PHONE_NUMBER) 841f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.SEND_TO_VOICEMAIL, "contacts_view." + Contacts.SEND_TO_VOICEMAIL) 842f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.NUMBER, Phone.NUMBER) 843f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TYPE, Phone.TYPE) 844f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LABEL, Phone.LABEL) 8452530512f639c4979fd7371c7dd25dd67e8118124Bai Tao .add(PhoneLookup.NORMALIZED_NUMBER, Phone.NORMALIZED_NUMBER) 846f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 847f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 848ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 849f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsProjectionMap = ProjectionMap.builder() 850f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups._ID) 851f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_NAME) 852f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_TYPE) 85343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.DATA_SET) 85443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.ACCOUNT_TYPE_AND_DATA_SET) 855f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SOURCE_ID) 856f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DIRTY) 857f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.VERSION) 858f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.RES_PACKAGE) 859f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE) 860f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE_RES) 861f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.GROUP_VISIBLE) 862f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYSTEM_ID) 863f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DELETED) 864f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.NOTES) 865f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SHOULD_SYNC) 866f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.FAVORITES) 867f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.AUTO_ADD) 868c039cfb78c40730483fd71178df63ada5826a315Dmitri Plotnikov .add(Groups.GROUP_IS_READ_ONLY) 869f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC1) 870f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC2) 871f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC3) 872f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC4) 873f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 874f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 875ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains {@link Groups} columns along with summary details */ 876f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsSummaryProjectionMap = ProjectionMap.builder() 877f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sGroupsProjectionMap) 878f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_COUNT, 879f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 880f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 881f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")") 882f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_WITH_PHONES, 883f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 884f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 885f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " WHERE " + Contacts.HAS_PHONE_NUMBER + ")") 886f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .build(); 887f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa 888f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa // This is only exposed as hidden API for the contacts app, so we can be very specific in 889f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa // the filtering 890f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa private static final ProjectionMap sGroupsSummaryProjectionMapWithGroupCountPerAccount = 891f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa ProjectionMap.builder() 892f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .addAll(sGroupsSummaryProjectionMap) 893f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa .add(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 894f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(*) FROM " + Views.GROUPS + " WHERE " 895f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + "(" + Groups.ACCOUNT_NAME + "=" 896f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + GroupsColumns.CONCRETE_ACCOUNT_NAME 897f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " AND " 898f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.ACCOUNT_TYPE + "=" + GroupsColumns.CONCRETE_ACCOUNT_TYPE 899f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " AND " 900f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.DELETED + "=0 AND " 901f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.FAVORITES + "=0 AND " 902f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.AUTO_ADD + "=0" 903f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")" 904f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " GROUP BY " 905f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Groups.ACCOUNT_NAME + ", " + Groups.ACCOUNT_TYPE 906f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + ")") 907f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 908f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 909373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov /** Contains the agg_exceptions columns */ 910f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sAggregationExceptionsProjectionMap = ProjectionMap.builder() 911f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id") 912f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.TYPE) 913f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID1) 914f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID2) 915f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 916f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 917eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey /** Contains the agg_exceptions columns */ 918f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSettingsProjectionMap = ProjectionMap.builder() 919f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_NAME) 920f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_TYPE) 921f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_VISIBLE) 922f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.SHOULD_SYNC) 923f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ANY_UNSYNCED, 924f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN MIN(" + Settings.SHOULD_SYNC 925f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ",(SELECT " 926f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "(CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL" 927f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 928f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE MIN(" + Groups.SHOULD_SYNC + ")" 929f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)" 930f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.GROUPS 931f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + GroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 932f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_NAME 933f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " AND " + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 934f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_TYPE + "))=0" 935f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 936f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE 0" 937f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)") 938f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_COUNT, 939f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 940f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 941f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 942f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 943f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 944f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 945f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_WITH_PHONES, 946f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 947f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 948f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 949f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Contacts.HAS_PHONE_NUMBER 950f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 951f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 952f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 953f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 954f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 95582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov /** Contains StatusUpdates columns */ 956f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStatusUpdatesProjectionMap = ProjectionMap.builder() 957f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PresenceColumns.RAW_CONTACT_ID) 958f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.DATA_ID, DataColumns.CONCRETE_ID) 959f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_ACCOUNT) 960f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_HANDLE) 961f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PROTOCOL) 962f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 963f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // properly enforce uniqueness of null values 964f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CUSTOM_PROTOCOL, 965f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL + "=''" 966f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN NULL" 967f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END)") 968f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PRESENCE) 969f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CHAT_CAPABILITY) 970f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS) 971f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_TIMESTAMP) 972f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_RES_PACKAGE) 973f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_ICON) 974f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_LABEL) 975f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 976f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 9773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Contains StreamItems columns */ 9783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemsProjectionMap = ProjectionMap.builder() 9799b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems._ID) 9809b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.CONTACT_ID) 981af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann .add(StreamItems.CONTACT_LOOKUP_KEY) 9829b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.ACCOUNT_NAME) 9839b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.ACCOUNT_TYPE) 9849b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.DATA_SET) 9853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9869b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.RAW_CONTACT_SOURCE_ID) 9873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_PACKAGE) 9883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_ICON) 9893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_LABEL) 9903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TEXT) 9913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TIMESTAMP) 9923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.COMMENTS) 9930bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC1) 9940bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC2) 9950bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC3) 9960bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC4) 9973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemPhotosProjectionMap = ProjectionMap.builder() 10003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos._ID, StreamItemPhotosColumns.CONCRETE_ID) 10013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 10020bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.RAW_CONTACT_SOURCE_ID, RawContactsColumns.CONCRETE_SOURCE_ID) 10033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.STREAM_ITEM_ID) 10043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.SORT_INDEX) 10056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_FILE_ID) 10066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_URI, 10076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro "'" + DisplayPhoto.CONTENT_URI + "'||'/'||" + StreamItemPhotos.PHOTO_FILE_ID) 10081dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.HEIGHT) 10091dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.WIDTH) 10101dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.FILESIZE) 10110bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC1) 10120bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC2) 10130bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC3) 10140bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC4) 10153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 10163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 10171b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov /** Contains Live Folders columns */ 1018f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sLiveFoldersProjectionMap = ProjectionMap.builder() 1019f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders._ID, Contacts._ID) 1020f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(LiveFolders.NAME, Contacts.DISPLAY_NAME) 1021f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // TODO: Put contact photo back when we have a way to display a default icon 1022f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // for contacts without a photo 1023f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // .add(LiveFolders.ICON_BITMAP, Photos.DATA) 1024f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 1025f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 1026d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** Contains {@link Directory} columns */ 1027f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDirectoryProjectionMap = ProjectionMap.builder() 1028f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory._ID) 1029f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.PACKAGE_NAME) 1030f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.TYPE_RESOURCE_ID) 1031f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DISPLAY_NAME) 1032f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DIRECTORY_AUTHORITY) 1033f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_TYPE) 1034f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_NAME) 1035f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.EXPORT_SUPPORT) 1036778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.SHORTCUT_SUPPORT) 1037778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.PHOTO_SUPPORT) 1038f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 10397e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10409705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // where clause to update the status_updates table 10419705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE = 10429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID + 10439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE + 10449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE "; 10459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 10462526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private static final String[] EMPTY_STRING_ARRAY = new String[0]; 10472526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1048bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1049bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Notification ID for failure to import contacts. 1050bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1051bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private static final int LEGACY_IMPORT_FAILED_NOTIFICATION = 1; 105251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 105303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_START_MATCH = "["; 105403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_END_MATCH = "]"; 105503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_ELLIPSIS = "..."; 105603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final int DEFAULT_SNIPPET_ARG_MAX_TOKENS = -10; 105703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 10589a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhoneInitialized; 10599a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov private boolean sIsPhone; 10609a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 1061f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov private StringBuilder mSb = new StringBuilder(); 10621129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs1 = new String[1]; 10631129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov private String[] mSelectionArgs2 = new String[2]; 10642526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private ArrayList<String> mSelectionArgs = Lists.newArrayList(); 10652526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1066f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private Account mAccount; 1067f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 106846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 106946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Stores mapping from type Strings exposed via {@link DataUsageFeedback} to 107046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type integers in {@link DataUsageStatColumns}. 107146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 107246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final Map<String, Integer> sDataUsageTypeMap; 107346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 10744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 10754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 1076a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 1077d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 1078d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 1079a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA); 1080a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES); 10813653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", 10823653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 10832d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", 10842d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov AGGREGATION_SUGGESTIONS); 1085a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO); 1086f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", 1087f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_ID_DISPLAY_PHOTO); 10883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", 10893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_ID_STREAM_ITEMS); 1090c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER); 10915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER); 10925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP); 10932149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA); 10945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID); 10952149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", 10962149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov CONTACTS_LOOKUP_ID_DATA); 1097f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", 1098f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_DISPLAY_PHOTO); 1099f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo", 1100f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_ID_DISPLAY_PHOTO); 1101a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities", 1102a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ENTITIES); 1103a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities", 1104a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ID_ENTITIES); 11053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items", 11063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_STREAM_ITEMS); 11073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items", 11083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_ID_STREAM_ITEMS); 1109f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD); 111042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*", 111142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann CONTACTS_AS_MULTI_VCARD); 11125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT); 1113ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*", 1114ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov CONTACTS_STREQUENT_FILTER); 11155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP); 111645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "contacts/frequent", CONTACTS_FREQUENT); 11173653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 11185ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); 11195ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); 11205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA); 1121f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/display_photo", 1122f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro RAW_CONTACTS_ID_DISPLAY_PHOTO); 112346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ENTITY_ID); 11243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items", 11253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RAW_CONTACTS_ID_STREAM_ITEMS); 112646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 112746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES); 1128b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 11294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 11304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 1131ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 113248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID); 11335e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER); 1134ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 11354a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS); 113648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID); 11371dac83b8fa58944acfd00f44e717a7dddc659d2dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP); 11385e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP); 11395e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER); 11404a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER); 1141ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 114248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID); 114346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** "*" is in CSV form with data ids ("123,456,789") */ 114446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/usagefeedback/*", DATA_USAGE_FEEDBACK_ID); 11451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1146ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 1147ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 1148ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 1149ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 115035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 1151b5a4add17815167d20a90645779df34cdf45280dFred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#", 1152b5a4add17815167d20a90645779df34cdf45280dFred Quintana SYNCSTATE_ID); 11535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/" + SyncStateContentProviderHelper.PATH, 11545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_SYNCSTATE); 11555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, 11565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "profile/" + SyncStateContentProviderHelper.PATH + "/#", 11575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_SYNCSTATE_ID); 115835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1159a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 1160b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 1161b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 1162b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 1163b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 11644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1165eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS); 1166eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 116782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES); 116882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID); 11691f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1170c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, 1171c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 1172c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 1173c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 11742d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 1175c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SHORTCUT); 1176c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 11771b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts", 11781b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS); 11791b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*", 11801b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_GROUP_NAME); 11811b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones", 11821b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_WITH_PHONES); 11831b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites", 11841b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov LIVE_FOLDERS_CONTACTS_FAVORITES); 118509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 118609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS); 1187d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1188d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES); 1189d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID); 11907a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 11917a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME); 119224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 119324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile", PROFILE); 119424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/entities", PROFILE_ENTITIES); 119524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data", PROFILE_DATA); 119624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data/#", PROFILE_DATA_ID); 119724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/as_vcard", PROFILE_AS_VCARD); 119824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts", PROFILE_RAW_CONTACTS); 119924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#", 120024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID); 120124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/data", 120224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_DATA); 120324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/entity", 120424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_ENTITIES); 12055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/status_updates", 12065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_STATUS_UPDATES); 120746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 12083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items", STREAM_ITEMS); 12093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/photo", STREAM_ITEMS_PHOTOS); 12103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#", STREAM_ITEMS_ID); 12113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo", STREAM_ITEMS_ID_PHOTOS); 12123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo/#", 12133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann STREAM_ITEMS_ID_PHOTOS_ID); 12143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items_limit", STREAM_ITEMS_LIMIT); 12153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 12165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "display_photo/#", DISPLAY_PHOTO); 1217f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS); 1218f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 121946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa HashMap<String, Integer> tmpTypeMap = new HashMap<String, Integer>(); 122046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_CALL, DataUsageStatColumns.USAGE_TYPE_INT_CALL); 122146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, 122246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT); 122346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa tmpTypeMap.put(DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, 122446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT); 122546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sDataUsageTypeMap = Collections.unmodifiableMap(tmpTypeMap); 122619a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov } 122719a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov 1228d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static class DirectoryInfo { 1229d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String authority; 1230d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountName; 1231d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountType; 1232d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 1233d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1234d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 1235d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Cached information about contact directories. 1236d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 12374458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private HashMap<String, DirectoryInfo> mDirectoryCache = new HashMap<String, DirectoryInfo>(); 12384458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private boolean mDirectoryCacheValid = false; 1239d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 12403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 124143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * An entry in group id cache. It maps the combination of (account type, account name, data set, 1242ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov * and source id) to group row id. 1243ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov */ 1244e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov public static class GroupIdCacheEntry { 1245ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType; 1246ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName; 124743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet; 1248ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String sourceId; 1249ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov long groupId; 1250ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov } 1251a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov 1252e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // We don't need a soft cache for groups - the assumption is that there will only 1253e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // be a small number of contact groups. The cache is keyed off source id. The value 1254e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov // is a list of groups with this group id. 1255e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap(); 1256e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov 125724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 1258f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of display photos. Larger images will be scaled 1259f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to fit. 1260f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1261f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxDisplayPhotoDim; 1262f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1263f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 1264f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Maximum dimension (height or width) of photo thumbnails. 1265f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 1266f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private int mMaxThumbnailPhotoDim; 1267f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 12695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Sub-provider for handling profile requests against the profile database. 12705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 12715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ProfileProvider mProfileProvider; 1272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12734097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 1274f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private NameLookupBuilder mNameLookupBuilder; 1275315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov 1276622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private PostalSplitter mPostalSplitter; 1277622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey 127872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov private ContactDirectoryManager mContactDirectoryManager; 12795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 12805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 12815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * The active (thread-local) database. This will be switched between a contacts-specific 12825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database and a profile-specific database, depending on what the current operation is 12835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * targeted to. 12845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 12855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<SQLiteDatabase> mActiveDb = new ThreadLocal<SQLiteDatabase>(); 12865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 12875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // This variable keeps track of whether the current operation is intended for the profile DB. 12885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<Boolean> mInProfileMode = new ThreadLocal<Boolean>(); 12895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 12905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Whether we're currently in the process of applying a batch of operations. 12915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<Boolean> mApplyingBatch = new ThreadLocal<Boolean>(); 12925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 12935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Separate data row handler instances for contact data and profile data. 12945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private HashMap<String, DataRowHandler> mDataRowHandlers; 12955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private HashMap<String, DataRowHandler> mProfileDataRowHandlers; 12965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 12975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile, we will use one of two 12985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // database helper instances. 12995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<ContactsDatabaseHelper> mDbHelper = 13005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ThreadLocal<ContactsDatabaseHelper>(); 13015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ContactsDatabaseHelper mContactsHelper; 13025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ProfileDatabaseHelper mProfileHelper; 13035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile or not, we will use one of 13055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // two aggregator instances. 13065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<ContactAggregator> mAggregator = new ThreadLocal<ContactAggregator>(); 1307622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private ContactAggregator mContactAggregator; 13085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ContactAggregator mProfileAggregator; 13095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile or not, we will use one of 13115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // two photo store instances (with their files stored in separate subdirectories). 13125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<PhotoStore> mPhotoStore = new ThreadLocal<PhotoStore>(); 13135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private PhotoStore mContactsPhotoStore; 13145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private PhotoStore mProfilePhotoStore; 13155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // The active transaction context will switch depending on the operation being performed. 13175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Both transaction contexts will be cleared out when a batch transaction is started, and 13185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // each will be processed separately when a batch transaction completes. 13195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private TransactionContext mContactTransactionContext = new TransactionContext(false); 13205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private TransactionContext mProfileTransactionContext = new TransactionContext(true); 13215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<TransactionContext> mTransactionContext = 13225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ThreadLocal<TransactionContext>(); 13235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // This database reference will only be referenced when a batch operation is in progress 13255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // that includes profile DB operations. It is used to create and handle a separate transaction 13265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // around that batch. Outside of such a batch operation, this will be null. 13275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<SQLiteDatabase> mProfileDbForBatch = 13285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ThreadLocal<SQLiteDatabase>(); 13295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // This flag is set during a batch operation that involves the profile DB to indicate that 13315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // errors occurred during processing of one of the profile operations. 13325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<Boolean> mProfileErrorsInBatch = new ThreadLocal<Boolean>(); 13335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1334f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 1335a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private GlobalSearchSupport mGlobalSearchSupport; 1336d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov private CommonNicknameCache mCommonNicknameCache; 1337f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov private SearchIndexManager mSearchIndexManager; 1338a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 133920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov private ContentValues mValues = new ContentValues(); 134073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov private HashMap<String, Boolean> mAccountWritability = Maps.newHashMap(); 134120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 134209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private int mProviderStatus = ProviderStatus.STATUS_NORMAL; 13433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private boolean mProviderStatusUpdateNeeded; 134409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private long mEstimatedStorageRequirement = 0; 134515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mReadAccessLatch; 134615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mWriteAccessLatch; 134715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private boolean mAccountUpdateListenerRegistered; 1348bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private boolean mOkToOpenAccess = true; 134973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 13501a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey private boolean mVisibleTouched = false; 13511a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 135281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov private boolean mSyncToNetwork; 135381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 13544cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao private Locale mCurrentLocale; 13553826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private int mContactsAccountCount; 1356d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov 1357bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private HandlerThread mBackgroundThread; 1358bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private Handler mBackgroundHandler; 1359bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1360f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mLastPhotoCleanup = 0; 1361f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 13624f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 13634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 1364663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) { 1365663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki Log.d(Constants.PERFORMANCE_TAG, "ContactsProvider2.onCreate start"); 1366663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } 1367de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov super.onCreate(); 1368ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov try { 1369ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return initialize(); 1370ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } catch (RuntimeException e) { 1371ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov Log.e(TAG, "Cannot start provider", e); 1372ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return false; 1373663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } finally { 1374663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) { 1375663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki Log.d(Constants.PERFORMANCE_TAG, "ContactsProvider2.onCreate finish"); 1376663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } 1377ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 1378ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 137935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1380ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov private boolean initialize() { 138115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov StrictMode.setThreadPolicy( 138215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 138315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 13843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Resources resources = getContext().getResources(); 1385f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxDisplayPhotoDim = resources.getInteger( 1386f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_display_photo_dim); 1387f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim = resources.getInteger( 1388f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro R.integer.config_max_thumbnail_photo_dim); 13893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 13905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper = (ContactsDatabaseHelper) getDatabaseHelper(); 13915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mContactsHelper); 139272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov mContactDirectoryManager = new ContactDirectoryManager(this); 1393a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov mGlobalSearchSupport = new GlobalSearchSupport(this); 139465ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov 1395bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // The provider is closed for business until fully initialized 139615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = new CountDownLatch(1); 139715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = new CountDownLatch(1); 139872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1399bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread = new HandlerThread("ContactsProviderWorker", 1400bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov Process.THREAD_PRIORITY_BACKGROUND); 1401bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread.start(); 1402bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler = new Handler(mBackgroundThread.getLooper()) { 1403bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov @Override 1404bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov public void handleMessage(Message msg) { 1405bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov performBackgroundTask(msg.what, msg.obj); 1406bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1407bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov }; 14082a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov 14095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Set up the sub-provider for handling profiles. 14105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileProvider = getProfileProvider(); 14115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ProviderInfo profileInfo = new ProviderInfo(); 14125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileInfo.readPermission = "android.permission.READ_PROFILE"; 14135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileInfo.writePermission = "android.permission.WRITE_PROFILE"; 14145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileProvider.attachInfo(getContext(), profileInfo); 14155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper = (ProfileDatabaseHelper) mProfileProvider.getDatabaseHelper(); 14165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 141715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_INITIALIZE); 1418bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 1419bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 1420bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_LOCALE); 1421bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM); 142205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_SEARCH_INDEX); 1423bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_PROVIDER_STATUS); 142415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_OPEN_WRITE_ACCESS); 1425f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 14263826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 142749d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov return true; 14284f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 14294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1430767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov /** 143151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * (Re)allocates all locale-sensitive structures. 143251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 143304b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov private void initForDefaultLocale() { 143415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 14355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mLegacyApiSupport = new LegacyApiSupport(context, mContactsHelper, this, 14365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mGlobalSearchSupport); 14374cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mCurrentLocale = getLocale(); 14385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mNameSplitter = mContactsHelper.createNameSplitter(); 14394cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter); 14404cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mPostalSplitter = new PostalSplitter(mCurrentLocale); 14415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mCommonNicknameCache = new CommonNicknameCache(mContactsHelper.getReadableDatabase()); 1442cdd03b2ba03718a7fa85663a2438136284a1557cBai Tao ContactLocaleUtils.getIntance().setLocale(mCurrentLocale); 14435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator = new ContactAggregator(this, mContactsHelper, 144415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 14455b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 14465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator = new ProfileAggregator(this, mProfileHelper, 14475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 14485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 1449f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov mSearchIndexManager = new SearchIndexManager(this); 14505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 14515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore = new PhotoStore(getContext().getFilesDir(), mContactsHelper); 14525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore = new PhotoStore(new File(getContext().getFilesDir(), "profile"), 14535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper); 14545b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 1455bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers = new HashMap<String, DataRowHandler>(); 14565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro initDataRowHandlers(mDataRowHandlers, mContactsHelper, mContactAggregator, 14575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore); 14585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDataRowHandlers = new HashMap<String, DataRowHandler>(); 14595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro initDataRowHandlers(mProfileDataRowHandlers, mProfileHelper, mProfileAggregator, 14605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore); 14615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 14625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Set initial thread-local state variables for the Contacts DB. 14635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 14645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 1465bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 14665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private void initDataRowHandlers(Map<String, DataRowHandler> handlerMap, 14675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ContactsDatabaseHelper dbHelper, ContactAggregator contactAggregator, 14685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore photoStore) { 14695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Context context = getContext(); 14705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Email.CONTENT_ITEM_TYPE, 14715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForEmail(context, dbHelper, contactAggregator)); 14725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Im.CONTENT_ITEM_TYPE, 14735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForIm(context, dbHelper, contactAggregator)); 14745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Organization.CONTENT_ITEM_TYPE, 14755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForOrganization(context, dbHelper, contactAggregator)); 14765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Phone.CONTENT_ITEM_TYPE, 14775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForPhoneNumber(context, dbHelper, contactAggregator)); 14785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Nickname.CONTENT_ITEM_TYPE, 14795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForNickname(context, dbHelper, contactAggregator)); 14805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(StructuredName.CONTENT_ITEM_TYPE, 14815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForStructuredName(context, dbHelper, contactAggregator, 1482bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mNameSplitter, mNameLookupBuilder)); 14835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(StructuredPostal.CONTENT_ITEM_TYPE, 14845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForStructuredPostal(context, dbHelper, contactAggregator, 1485bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mPostalSplitter)); 14865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(GroupMembership.CONTENT_ITEM_TYPE, 14875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForGroupMembership(context, dbHelper, contactAggregator, 1488bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mGroupIdCache)); 14895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Photo.CONTENT_ITEM_TYPE, 14905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForPhoto(context, dbHelper, contactAggregator, photoStore)); 14915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Note.CONTENT_ITEM_TYPE, 14925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForNote(context, dbHelper, contactAggregator)); 1493bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1494bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1495bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /** 1496bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Visible for testing. 1497bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov */ 1498bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov /* package */ PhotoPriorityResolver createPhotoPriorityResolver(Context context) { 1499bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov return new PhotoPriorityResolver(context); 1500bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1501bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1502bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task) { 1503bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendEmptyMessage(task); 1504bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1505bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1506bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task, Object arg) { 1507bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(task, arg)); 1508bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1509bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1510bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void performBackgroundTask(int task, Object arg) { 1511bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov switch (task) { 151215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_INITIALIZE: { 151315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov initForDefaultLocale(); 151415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch.countDown(); 151515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = null; 151615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov break; 151715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 151815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 151915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_OPEN_WRITE_ACCESS: { 1520bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (mOkToOpenAccess) { 152115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch.countDown(); 152215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = null; 1523bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1524bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1525bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1526bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1527bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS: { 1528bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isLegacyContactImportNeeded()) { 1529bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov importLegacyContactsInBackground(); 1530bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1531bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1532bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1533bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1534bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_ACCOUNTS: { 153515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 153615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (!mAccountUpdateListenerRegistered) { 153715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov AccountManager.get(context).addOnAccountsUpdatedListener(this, null, false); 153815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mAccountUpdateListenerRegistered = true; 153915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 154015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 15415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Update the accounts for both the contacts and profile DBs. 154215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Account[] accounts = AccountManager.get(context).getAccounts(); 15435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 1544bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov boolean accountsChanged = updateAccountsInBackground(accounts); 15455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 15465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro accountsChanged |= updateAccountsInBackground(accounts); 15475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1548bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateContactsAccountCount(accounts); 1549bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateDirectoriesInBackground(accountsChanged); 1550bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1551bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1552bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1553bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_LOCALE: { 1554bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateLocaleInBackground(); 1555bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1556bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1557bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1558fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov case BACKGROUND_TASK_CHANGE_LOCALE: { 1559fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov changeLocaleInBackground(); 1560fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov break; 1561fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1562fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1563bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM: { 1564bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isAggregationUpgradeNeeded()) { 1565bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov upgradeAggregationAlgorithmInBackground(); 1566bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1567bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1568bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1569bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 157005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_SEARCH_INDEX: { 157105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov updateSearchIndexInBackground(); 157205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov break; 157305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 157405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1575bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_PROVIDER_STATUS: { 1576bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateProviderStatus(); 1577bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1578bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1579bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1580bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_DIRECTORIES: { 1581bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (arg != null) { 1582bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.onPackageChanged((String) arg); 1583bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1584bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1585bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1586f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1587f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case BACKGROUND_TASK_CLEANUP_PHOTOS: { 1588f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check rate limit. 1589f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long now = System.currentTimeMillis(); 1590f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (now - mLastPhotoCleanup > PHOTO_CLEANUP_RATE_LIMIT) { 1591f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mLastPhotoCleanup = now; 15925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 15935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Clean up photo stores for both contacts and profiles. 15945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 15955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro cleanupPhotoStore(); 15965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 1597f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupPhotoStore(); 1598f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro break; 1599f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1600f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1601bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 16024cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 16034cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao 160453fac8f99f3884c372c907a76766d27fa9e1d95fDmitri Plotnikov public void onLocaleChanged() { 16053826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 16063826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 16074f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov return; 16084f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov } 16094f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov 1610fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_CHANGE_LOCALE); 16114cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 161251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 161351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov /** 161451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * Verifies that the contacts database is properly configured for the current locale. 161551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * If not, changes the database locale to the current locale using an asynchronous task. 161651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * This needs to be done asynchronously because the process involves rebuilding 161751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * large data structures (name lookup, sort keys), which can take minutes on 161851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * a large set of contacts. 161951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 1620bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateLocaleInBackground() { 1621f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 1622f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov // The process is already running - postpone the change 1623f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov if (mProviderStatus == ProviderStatus.STATUS_CHANGING_LOCALE) { 1624f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov return; 1625f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov } 1626f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 162751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 162851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final String providerLocale = prefs.getString(PREF_LOCALE, null); 162951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final Locale currentLocale = mCurrentLocale; 163051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov if (currentLocale.toString().equals(providerLocale)) { 163151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov return; 163251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 163351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 163451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov int providerStatus = mProviderStatus; 163551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_CHANGING_LOCALE); 16365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.setLocale(this, currentLocale); 16375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper.setLocale(this, currentLocale); 1638bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).apply(); 1639bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov setProviderStatus(providerStatus); 1640bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 164151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 1642fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov /** 1643fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov * Reinitializes the provider for a new locale. 1644fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov */ 1645fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov private void changeLocaleInBackground() { 1646fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Re-initializing the provider without stopping it. 1647fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Locking the database will prevent inserts/updates/deletes from 1648fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // running at the same time, but queries may still be running 1649fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // on other threads. Those queries may return inconsistent results. 16505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mContactsHelper.getWritableDatabase(); 16515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase profileDb = mProfileHelper.getWritableDatabase(); 1652fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.beginTransaction(); 16535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.beginTransaction(); 1654fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov try { 1655fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov initForDefaultLocale(); 1656fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.setTransactionSuccessful(); 16575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.setTransactionSuccessful(); 1658fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } finally { 1659fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.endTransaction(); 16605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.endTransaction(); 1661fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1662fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1663fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov updateLocaleInBackground(); 1664fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1665fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 166605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov protected void updateSearchIndexInBackground() { 166705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov mSearchIndexManager.updateIndex(); 166805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 166905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1670bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateDirectoriesInBackground(boolean rescan) { 1671bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanAllPackages(rescan); 167251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 167351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 16743826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateProviderStatus() { 16753826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 16763826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 16773826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return; 16783826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 16793826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 16803e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson // No accounts/no contacts status is true if there are no account and 16815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // there are no contacts or one profile contact 16823e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson if (mContactsAccountCount == 0) { 16835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactsNum = DatabaseUtils.queryNumEntries(mContactsHelper.getReadableDatabase(), 16843e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson Tables.CONTACTS, null); 16855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long profileNum = DatabaseUtils.queryNumEntries(mProfileHelper.getReadableDatabase(), 16865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Tables.CONTACTS, null); 16875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 16885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // TODO: Different status if there is a profile but no contacts? 16895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (contactsNum == 0 && profileNum <= 1) { 16903e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson setProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 16913e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson } else { 16923e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson setProviderStatus(ProviderStatus.STATUS_NORMAL); 16933e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson } 16943826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } else { 16953826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 16963826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 16973826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 16983826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 169931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov /* Visible for testing */ 1700f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro protected void cleanupPhotoStore() { 17015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 17026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 17036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Assemble the set of photo store file IDs that are in use, and send those to the photo 1704f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // store. Any photos that aren't in that set will be deleted, and any photos that no 1705f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // longer exist in the photo store will be returned for us to clear out in the DB. 17066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = db.query(Views.DATA, new String[]{Data._ID, Photo.PHOTO_FILE_ID}, 1707f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.MIMETYPE + "=" + Photo.MIMETYPE + " AND " 1708f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro + Photo.PHOTO_FILE_ID + " IS NOT NULL", null, null, null, null); 17096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> usedPhotoFileIds = Sets.newHashSet(); 17106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToDataId = Maps.newHashMap(); 1711f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1712f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro while (c.moveToNext()) { 17136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = c.getLong(0); 17146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(1); 17156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 17166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToDataId.put(photoFileId, dataId); 17176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 17186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 17196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 17206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 17216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 17226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Also query for all social stream item photos. 17236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c = db.query(Tables.STREAM_ITEM_PHOTOS, 17246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{ 17256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos._ID, 17266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.STREAM_ITEM_ID, 17276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItemPhotos.PHOTO_FILE_ID 17286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro }, 17296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro null, null, null, null, null); 17306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToStreamItemPhotoId = Maps.newHashMap(); 17316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> streamItemPhotoIdToStreamItemId = Maps.newHashMap(); 17326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 17336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro while (c.moveToNext()) { 17346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = c.getLong(0); 17356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = c.getLong(1); 17366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(2); 17376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 17386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToStreamItemPhotoId.put(photoFileId, streamItemPhotoId); 17396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemPhotoIdToStreamItemId.put(streamItemPhotoId, streamItemId); 1740f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1741f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 1742f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 1743f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1744f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1745f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Run the photo store cleanup. 17465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> missingPhotoIds = mPhotoStore.get().cleanup(usedPhotoFileIds); 1747f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1748f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If any of the keys we're using no longer exist, clean them up. 17496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!missingPhotoIds.isEmpty()) { 1750f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 17516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro for (long missingPhotoId : missingPhotoIds) { 17526802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToDataId.containsKey(missingPhotoId)) { 17536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = photoFileIdToDataId.get(missingPhotoId); 1754f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 1755f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.putNull(Photo.PHOTO_FILE_ID); 1756f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ops.add(ContentProviderOperation.newUpdate( 17576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentUris.withAppendedId(Data.CONTENT_URI, dataId)) 1758f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .withValues(updateValues).build()); 1759f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 17606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileIdToStreamItemPhotoId.containsKey(missingPhotoId)) { 17616802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For missing photos that were in stream item photos, just delete the stream 17626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // item photo. 17636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = photoFileIdToStreamItemPhotoId.get(missingPhotoId); 17646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = streamItemPhotoIdToStreamItemId.get(streamItemPhotoId); 17656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ops.add(ContentProviderOperation.newDelete( 17666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.CONTENT_URI.buildUpon() 17676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemId)) 17686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY) 17696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .appendPath(String.valueOf(streamItemPhotoId)) 17706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .build()).build()); 17716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 1772f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1773f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1774f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro applyBatch(ops); 1775f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (OperationApplicationException oae) { 1776f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Not a fatal problem (and we'll try again on the next cleanup). 1777f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Failed to clean up outdated photo references", oae); 1778f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1779f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1780f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1781f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1782f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* Visible for testing */ 1783de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov @Override 1784b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 1785b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return ContactsDatabaseHelper.getInstance(context); 178631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 178731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 17885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public ProfileProvider getProfileProvider() { 17895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return new ProfileProvider(this); 17905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 17915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1792524913c66ce75ca8dec127ac88e3bc2249c246d9Dave Santoro @VisibleForTesting 1793f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* package */ PhotoStore getPhotoStore() { 17945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mContactsPhotoStore; 1795f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1796f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 179787614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxDisplayPhotoDim() { 179887614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxDisplayPhotoDim; 179987614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 180087614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 180187614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro /* package */ int getMaxThumbnailPhotoDim() { 180287614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro return mMaxThumbnailPhotoDim; 180387614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 180487614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1805013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov /* package */ NameSplitter getNameSplitter() { 1806013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov return mNameSplitter; 1807013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov } 1808013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov 18095df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov /* package */ NameLookupBuilder getNameLookupBuilder() { 18105df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov return mNameLookupBuilder; 18115df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov } 18125df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov 18135dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov /* Visible for testing */ 1814ed78fd6df5e9f3a2d572162e5d374d1f4a625bddDmitri Plotnikov public ContactDirectoryManager getContactDirectoryManagerForTest() { 181572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov return mContactDirectoryManager; 181672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 181772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 181872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov /* Visible for testing */ 18195dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov protected Locale getLocale() { 18205dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov return Locale.getDefault(); 18215dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov } 18225dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 18235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean applyingBatch() { 18245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Boolean applyingBatch = mApplyingBatch.get(); 18255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return applyingBatch != null && applyingBatch; 18265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 18275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 18285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean inProfileMode() { 18295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Boolean profileMode = mInProfileMode.get(); 18305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return profileMode != null && profileMode; 18315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 18325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 18333d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov protected boolean isLegacyContactImportNeeded() { 18345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int version = Integer.parseInt( 18355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.getProperty(PROPERTY_CONTACTS_IMPORTED, "0")); 1836b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov return version < PROPERTY_CONTACTS_IMPORT_VERSION; 18373d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 18383d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1839568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov protected LegacyContactImporter getLegacyContactImporter() { 1840568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov return new LegacyContactImporter(getContext(), this); 1841568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1842568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1843568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 1844bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Imports legacy contacts as a background task. 1845568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 1846bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private void importLegacyContactsInBackground() { 1847bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Importing legacy contacts"); 1848bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADING); 1849568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1850bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 18515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.setLocale(this, mCurrentLocale); 1852bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, mCurrentLocale.toString()).commit(); 1853568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1854bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov LegacyContactImporter importer = getLegacyContactImporter(); 1855bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (importLegacyContacts(importer)) { 1856bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportSuccess(); 1857bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } else { 1858bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov onLegacyContactImportFailure(); 1859bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1860568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1861568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1862bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1863bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Unlocks the provider and declares that the import process is complete. 1864bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1865bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportSuccess() { 1866bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1867bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)getContext().getSystemService(Context.NOTIFICATION_SERVICE); 1868bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.cancel(LEGACY_IMPORT_FAILED_NOTIFICATION); 1869bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1870b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov // Store a property in the database indicating that the conversion process succeeded 18715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.setProperty(PROPERTY_CONTACTS_IMPORTED, 1872b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov String.valueOf(PROPERTY_CONTACTS_IMPORT_VERSION)); 1873bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 1874bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Completed import of legacy contacts"); 1875bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1876bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1877bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1878bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Announces the provider status and keeps the provider locked. 1879bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1880bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private void onLegacyContactImportFailure() { 1881bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Context context = getContext(); 1882bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov NotificationManager nm = 1883bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); 1884bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1885bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // Show a notification 1886bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Notification n = new Notification(android.R.drawable.stat_notify_error, 1887bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_ticker), 1888bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov System.currentTimeMillis()); 1889bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.setLatestEventInfo(context, 1890bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_title), 1891bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov context.getString(R.string.upgrade_out_of_memory_notification_text), 1892bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov PendingIntent.getActivity(context, 0, new Intent(Intents.UI.LIST_DEFAULT), 0)); 1893bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov n.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; 1894bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1895bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov nm.notify(LEGACY_IMPORT_FAILED_NOTIFICATION, n); 1896bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1897bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_UPGRADE_OUT_OF_MEMORY); 1898bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Log.v(TAG, "Failed to import legacy contacts"); 1899bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1900bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // Do not let any database changes until this issue is resolved. 1901bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mOkToOpenAccess = false; 19023d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 19033d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 19043d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /* Visible for testing */ 1905568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /* package */ boolean importLegacyContacts(LegacyContactImporter importer) { 19060e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff boolean aggregatorEnabled = mContactAggregator.isEnabled(); 19073d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov mContactAggregator.setEnabled(false); 19083d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov try { 1909bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (importer.importContacts()) { 1910bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov 1911bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // TODO aggregate all newly added raw contacts 1912bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mContactAggregator.setEnabled(aggregatorEnabled); 1913bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return true; 1914bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 19153d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } catch (Throwable e) { 19163d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov Log.e(TAG, "Legacy contact import failed", e); 19173d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 1918bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov mEstimatedStorageRequirement = importer.getEstimatedStorageRequirement(); 1919bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return false; 19203d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 19213d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 1922a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 1923a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 1924a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 1925a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /* package */ void wipeData() { 19265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.wipeData(); 19275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper.wipeData(); 19285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore.clear(); 19295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore.clear(); 19303826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS; 1931a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 1932a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1933568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 193415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov * During intialization, this content provider will 1935568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * block all attempts to change contacts data. In particular, it will hold 1936568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * up all contact syncs. As soon as the import process is complete, all 1937568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * processes waiting to write to the provider are unblocked and can proceed 1938568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * to compete for the database transaction monitor. 1939568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 194015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private void waitForAccess(CountDownLatch latch) { 194115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (latch == null) { 194215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 194315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 194415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 194515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov while (true) { 194615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov try { 194715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov latch.await(); 194815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 194915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } catch (InterruptedException e) { 195015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Thread.currentThread().interrupt(); 1951ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov } 1952568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1953568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1954568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 19555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 19565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Determines whether the given URI should be directed to the profile 19575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database rather than the contacts database. This is true under either 19585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * of three conditions: 19595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 1. The URI itself is specifically for the profile. 19605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 2. The URI contains ID references that are in the profile ID-space. 19615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 3. The URI contains lookup key references that match the special profile lookup key. 19625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param uri The URI to examine. 19635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @return Whether to direct the DB operation to the profile database. 19645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 19655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean mapsToProfileDb(Uri uri) { 19665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return sUriMatcher.mapsToProfile(uri); 19675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 19695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 19705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Determines whether the given URI with the given values being inserted 19715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * should be directed to the profile database rather than the contacts 19725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database. This is true if the URI already maps to the profile DB from 19735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a call to {@link #mapsToProfileDb} or if the URI matches a URI that 19745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * specifies parent IDs via the ContentValues, and the given ContentValues 19755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * contains an ID in the profile ID-space. 19765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param uri The URI to examine. 19775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param values The values being inserted. 19785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @return Whether to direct the DB insert to the profile database. 19795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 19805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean mapsToProfileDbWithInsertedValues(Uri uri, ContentValues values) { 19815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 19825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return true; 19835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int match = sUriMatcher.match(uri); 19855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (INSERT_URI_ID_VALUE_MAP.containsKey(match)) { 19865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String idField = INSERT_URI_ID_VALUE_MAP.get(match); 19875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (values.containsKey(idField)) { 19885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long id = values.getAsLong(idField); 19895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (ContactsContract.isProfileId(id)) { 19905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return true; 19915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return false; 19955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 19975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 19985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Switches the provider's thread-local context variables to prepare for performing 19995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a profile operation. 20005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 20015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private void switchToProfileMode() { 20025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mProfileHelper); 20035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.set(mProfileTransactionContext); 20045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.set(mProfileAggregator); 20055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mPhotoStore.set(mProfilePhotoStore); 20065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mInProfileMode.set(true); 20075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 20085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // If we're in batch mode and don't yet have a database set up for our transaction, 20095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // get one and start a transaction now. 20105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (applyingBatch() && mProfileDbForBatch.get() == null) { 20115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase profileDb = mProfileHelper.getWritableDatabase(); 20125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.beginTransactionWithListener(this); 20135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDbForBatch.set(profileDb); 20145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 20175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 20185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Switches the provider's thread-local context variables to prepare for performing 20195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a contacts operation. 20205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 20215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private void switchToContactMode() { 20225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mContactsHelper); 20235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.set(mContactTransactionContext); 20245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.set(mContactAggregator); 20255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mPhotoStore.set(mContactsPhotoStore); 20265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mInProfileMode.set(false); 20275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 20285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // If not in batch mode, clear out the active database - it will be set to the default 20295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // instance from SQLiteContentProvider if necessary. 20305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (!applyingBatch()) { 20315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(null); 20325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 2035568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 2036568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public Uri insert(Uri uri, ContentValues values) { 203715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 20385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDbWithInsertedValues(uri, values)) { 20395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 20405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileProvider.insert(uri, values); 20415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 20425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 20435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.insert(uri, values); 20445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 2045568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2046568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 2047568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 2048568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 204915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (mWriteAccessLatch != null) { 2050bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // We are stuck trying to upgrade contacts db. The only update request 2051bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // allowed in this case is an update of provider status, which will trigger 2052bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov // an attempt to upgrade contacts again. 2053bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov int match = sUriMatcher.match(uri); 2054bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (match == PROVIDER_STATUS) { 2055bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov Integer newStatus = values.getAsInteger(ProviderStatus.STATUS); 2056bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov if (newStatus != null && newStatus == ProviderStatus.STATUS_UPGRADING) { 2057bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_IMPORT_LEGACY_CONTACTS); 2058bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 1; 2059bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } else { 2060bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov return 0; 2061bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 2062bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 2063bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 206415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 20655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 20665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 20675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileProvider.update(uri, values, selection, selectionArgs); 20685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 20695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 20705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.update(uri, values, selection, selectionArgs); 20715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 2072568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2073568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 2074568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 2075568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int delete(Uri uri, String selection, String[] selectionArgs) { 207615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 20775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 20785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 20795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileProvider.delete(uri, selection, selectionArgs); 20805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 20815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 20825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.delete(uri, selection, selectionArgs); 20835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 20865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 20875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Replaces the current (thread-local) database to use for the operation with the given one. 20885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param db The database to use. 20895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 20905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /* package */ void substituteDb(SQLiteDatabase db) { 20915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(db); 2092568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2093568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 2094568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 2095568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 2096568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov throws OperationApplicationException { 209715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 20985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ContentProviderResult[] results = null; 20995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro try { 21005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro results = super.applyBatch(operations); 21015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } finally { 21025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mProfileDbForBatch.get() != null) { 21035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // A profile operation was involved, so clean up its transaction. 21045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro boolean profileErrors = mProfileErrorsInBatch.get() != null 21055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro && mProfileErrorsInBatch.get(); 21065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (!profileErrors) { 21075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDbForBatch.get().setTransactionSuccessful(); 21085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 21095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDbForBatch.get().endTransaction(); 21105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDbForBatch.set(null); 21115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileErrorsInBatch.set(false); 21125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 21135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 21145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return results; 2115568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2116568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 21174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 21187b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov public int bulkInsert(Uri uri, ContentValues[] values) { 21197b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov waitForAccess(mWriteAccessLatch); 21207b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov return super.bulkInsert(uri, values); 21217b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov } 21227b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov 21237b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov @Override 2124285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void onBeginTransaction() { 2125bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 2126b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "onBeginTransaction"); 2127b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2128285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.onBeginTransaction(); 21295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (inProfileMode()) { 21305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator.clearPendingAggregations(); 21315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileTransactionContext.clear(); 21325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 21335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator.clearPendingAggregations(); 21345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactTransactionContext.clear(); 21355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 2136b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2137b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2138285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 2139285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2140285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov protected void beforeTransactionCommit() { 21411129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 2142bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 2143b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "beforeTransactionCommit"); 2144b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2145285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov super.beforeTransactionCommit(); 2146b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 21475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateInTransaction(mTransactionContext.get(), mActiveDb.get()); 21481a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (mVisibleTouched) { 21491a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = false; 21505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().updateAllVisible(); 21511a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey } 21523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 2153bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 2154bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 21553826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatusUpdateNeeded) { 21563826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 21573826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = false; 21583826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 2159b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2160b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2161bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov private void updateSearchIndexInTransaction() { 21625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> staleContacts = mTransactionContext.get().getStaleSearchIndexContactIds(); 21635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> staleRawContacts = mTransactionContext.get().getStaleSearchIndexRawContactIds(); 2164bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov if (!staleContacts.isEmpty() || !staleRawContacts.isEmpty()) { 2165bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mSearchIndexManager.updateIndexForRawContacts(staleContacts, staleRawContacts); 21665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().clearSearchIndexUpdates(); 2167bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 2168bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 2169bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 2170b5a4add17815167d20a90645779df34cdf45280dFred Quintana private void flushTransactionalChanges() { 2171bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 2172b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "flushTransactionChanges"); 2173b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 21741129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 21755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro for (long rawContactId : mTransactionContext.get().getInsertedRawContactIds()) { 21765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().updateRawContactDisplayName(mActiveDb.get(), rawContactId); 21775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().onRawContactInsert(mTransactionContext.get(), mActiveDb.get(), 21785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro rawContactId); 217924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 218024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 21815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> dirtyRawContacts = mTransactionContext.get().getDirtyRawContactIds(); 2182d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!dirtyRawContacts.isEmpty()) { 2183a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 2184a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL); 2185d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, dirtyRawContacts); 2186a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 21875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(mSb.toString()); 2188a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov } 2189a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 21905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> updatedRawContacts = mTransactionContext.get().getUpdatedRawContactIds(); 2191d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!updatedRawContacts.isEmpty()) { 2192a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 2193a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL); 2194d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, updatedRawContacts); 2195a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 21965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(mSb.toString()); 2197b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2198b5a4add17815167d20a90645779df34cdf45280dFred Quintana 21995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Update sync states. 22005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro for (Map.Entry<Long, Object> entry : mTransactionContext.get().getUpdatedSyncStates()) { 2201b5a4add17815167d20a90645779df34cdf45280dFred Quintana long id = entry.getKey(); 22025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().getSyncState().update(mActiveDb.get(), id, entry.getValue()) <= 0) { 22039d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana throw new IllegalStateException( 22049d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana "unable to update sync state, does it still exist?"); 22059d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana } 2206b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2207b5a4add17815167d20a90645779df34cdf45280dFred Quintana 22085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().clear(); 2209b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2210b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2211a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** 2212a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * Appends comma separated ids. 2213a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * @param ids Should not be empty 2214a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov */ 2215d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private void appendIds(StringBuilder sb, Set<Long> ids) { 2216b5a4add17815167d20a90645779df34cdf45280dFred Quintana for (long id : ids) { 2217a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(id).append(','); 2218b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2219a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 2220a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.setLength(sb.length() - 1); // Yank the last comma 2221285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 2222285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 2223285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2224cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov protected void notifyChange() { 222581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov notifyChange(mSyncToNetwork); 222681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = false; 222781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 222881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 222981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov protected void notifyChange(boolean syncToNetwork) { 223081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null, 223181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov syncToNetwork); 2232cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov } 2233568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 223451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov protected void setProviderStatus(int status) { 22353826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != status) { 22363826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = status; 22373826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov getContext().getContentResolver().notifyChange(ProviderStatus.CONTENT_URI, null, false); 22383826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 223951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 224051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 2241f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public DataRowHandler getDataRowHandler(final String mimeType) { 22425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (inProfileMode()) { 22435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return getDataRowHandlerForProfile(mimeType); 22445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 22453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataRowHandler handler = mDataRowHandlers.get(mimeType); 22463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (handler == null) { 22476d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov handler = new DataRowHandlerForCustomMimetype( 22485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro getContext(), mContactsHelper, mContactAggregator, mimeType); 22493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(mimeType, handler); 22503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 22513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return handler; 22523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 22533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 22545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public DataRowHandler getDataRowHandlerForProfile(final String mimeType) { 22555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro DataRowHandler handler = mProfileDataRowHandlers.get(mimeType); 22565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (handler == null) { 22575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handler = new DataRowHandlerForCustomMimetype( 22585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro getContext(), mProfileHelper, mProfileAggregator, mimeType); 22595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDataRowHandlers.put(mimeType, handler); 22605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 22615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return handler; 22625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 22635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 22644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 2265de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected Uri insertInTransaction(Uri uri, ContentValues values) { 2266bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 22671129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Log.v(TAG, "insertInTransaction: " + uri + " " + values); 2268b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2269f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 22705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 22715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 22725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(mDb); 22735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 22745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 2275f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 2276f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 2277f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2278a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 2279a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 228035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2281a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 228235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 22835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 22845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = mDbHelper.get().getSyncState().insert(mActiveDb.get(), values); 228535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 228635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2287d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 2288d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov insertContact(values); 22896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 22906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 22916bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 229224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 229324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro throw new UnsupportedOperationException( 229424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "The profile contact is created automatically"); 229524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 229624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 22975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 22985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter); 2299f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2300a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2301a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2302a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 23035ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 23045ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 2305f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2306f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2307a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2308a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2309a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 23103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 23113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItems.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 23123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 23133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 23143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 23153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 23163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 231724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 23185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter); 231924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro mSyncToNetwork |= !callerIsSyncAdapter; 232024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 232124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 232224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2323a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case DATA: { 2324f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2325f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2326a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2327a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2328a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2329ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 2330f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov id = insertGroup(uri, values, callerIsSyncAdapter); 2331f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2332ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2333ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2334ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2335eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 23365aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey id = insertSettings(uri, values); 233743880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 2338eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 2339eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 2340eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 23415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 23425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 234382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov id = insertStatusUpdate(values); 23441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 23451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 23461f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 23473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 23483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 23493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 23503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 23513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 23523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 23533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 23543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 23553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 23563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 23573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 23583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 23593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 23603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItemPhotos.STREAM_ITEM_ID, uri.getPathSegments().get(1)); 23613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 23623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 23633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 23643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 23653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2366a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 236781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 2368f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 2369a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2370a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 23717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 23727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 23737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 23747e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2375de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return ContentUris.withAppendedId(uri, id); 2376a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2377a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2378a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2379e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * If account is non-null then store it in the values. If the account is 2380e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * already specified in the values then it must be consistent with the 2381e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * account, if it is non-null. 2382e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * 2383e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param uri Current {@link Uri} being operated on. 2384e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param values {@link ContentValues} to read and possibly update. 2385e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when only one of 2386e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_NAME} or 2387e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the 2388e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * other undefined. 2389e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME} 2390e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between 2391e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * the given {@link Uri} and {@link ContentValues}. 23927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 2393e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException { 2394f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 2395f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 2396e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 2397f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2398f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME); 2399f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 2400e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialValues = TextUtils.isEmpty(valueAccountName) 2401e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey ^ TextUtils.isEmpty(valueAccountType); 2402e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2403e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri || partialValues) { 2404e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 24055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 2406fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 2407e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2408e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2409e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 2410e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 2411e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validUri = !TextUtils.isEmpty(accountName); 2412e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validValues = !TextUtils.isEmpty(valueAccountName); 2413e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2414e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validValues && validUri) { 2415e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Check that accounts match when both present 2416e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean accountMatch = TextUtils.equals(accountName, valueAccountName) 2417e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey && TextUtils.equals(accountType, valueAccountType); 2418e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (!accountMatch) { 24195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 2420fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "When both specified, ACCOUNT_NAME and ACCOUNT_TYPE must match", uri)); 2421e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2422e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validUri) { 2423e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Fill values from Uri when not present 2424f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_NAME, accountName); 2425f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_TYPE, accountType); 2426e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validValues) { 2427f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountName = valueAccountName; 2428f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountType = valueAccountType; 2429e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else { 2430e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return null; 2431f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 2432f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2433e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Use cached Account object when matches, otherwise create 2434f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mAccount == null 2435f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.name.equals(accountName) 2436f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.type.equals(accountType)) { 2437f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mAccount = new Account(accountName, accountType); 2438035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 2439f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2440e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return mAccount; 24417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24437e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 244443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Resolves the account and builds an {@link AccountWithDataSet} based on the data set specified 244543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * in the URI or values (if any). 244643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param uri Current {@link Uri} being operated on. 244743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param values {@link ContentValues} to read and possibly update. 244843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro */ 244943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private AccountWithDataSet resolveAccountWithDataSet(Uri uri, ContentValues values) { 24503593682b8d9213fde576a0cff54458ad50563980Dave Santoro final Account account = resolveAccount(uri, values); 245143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = null; 245243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (account != null) { 245343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 245443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (dataSet == null) { 24553593682b8d9213fde576a0cff54458ad50563980Dave Santoro dataSet = values.getAsString(RawContacts.DATA_SET); 2456a71dc460ca951c7aca591f3f470c160cde70a1e3Dave Santoro } else { 24573593682b8d9213fde576a0cff54458ad50563980Dave Santoro values.put(RawContacts.DATA_SET, dataSet); 245843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 245943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet = new AccountWithDataSet(account.name, account.type, dataSet); 246043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 246143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro return accountWithDataSet; 246243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 246343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 246443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro /** 2465d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov * Inserts an item in the contacts table 24666bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 24676bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 24686bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 24696bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 2470d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private long insertContact(ContentValues values) { 2471de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new UnsupportedOperationException("Aggregate contacts are created automatically"); 24726bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 24736bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 24746bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 247524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Inserts an item in the raw contacts table 2476a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2477f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param uri the values for the new row 2478f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param values the account this contact should be associated with. may be null. 2479dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana * @param callerIsSyncAdapter 2480a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2481a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 24825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private long insertRawContact(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2483f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2484f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2485f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 2486f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 248743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = resolveAccountWithDataSet(uri, mValues); 24887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24893d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov if (values.containsKey(RawContacts.DELETED) 24903d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov && values.getAsInteger(RawContacts.DELETED) != 0) { 2491f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 24923d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 24933d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 24945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long rawContactId = mActiveDb.get().insert(Tables.RAW_CONTACTS, 24955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro RawContacts.CONTACT_ID, mValues); 2496f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = RawContacts.AGGREGATION_MODE_DEFAULT; 24975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mValues.containsKey(RawContacts.AGGREGATION_MODE)) { 2498f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov aggregationMode = mValues.getAsInteger(RawContacts.AGGREGATION_MODE); 2499f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 25005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markNewForAggregation(rawContactId, aggregationMode); 2501285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 25025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Trigger creation of a Contact based on this RawContact at the end of transaction 25035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().rawContactInserted(rawContactId, accountWithDataSet); 2504f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2505dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 2506dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 2507dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long starred = values.getAsLong(RawContacts.STARRED); 2508dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (starred != null && starred != 0) { 2509dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred != 0); 2510dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2511dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2512dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 25133826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 2514023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov return rawContactId; 2515a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2516a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2517dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void addAutoAddMembership(long rawContactId) { 2518dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID, 2519dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2520dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2521dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2522dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2523dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2524dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2525dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private Long findGroupByRawContactId(String selection, long rawContactId) { 25265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.GROUPS + "," + Tables.RAW_CONTACTS, 25275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROJECTION_GROUP_ID, selection, 2528dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}, 2529dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana null /* groupBy */, null /* having */, null /* orderBy */); 2530dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 2531dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (c.moveToNext()) { 2532dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return c.getLong(0); 2533dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2534dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return null; 2535dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 2536dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana c.close(); 2537dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2538dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2539dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2540dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void updateFavoritesMembership(long rawContactId, boolean isStarred) { 2541dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID, 2542dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2543dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2544dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (isStarred) { 2545dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2546dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2547dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana deleteDataGroupMembership(rawContactId, groupId); 2548dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2549dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2550dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2551dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2552dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void insertDataGroupMembership(long rawContactId, long groupId) { 2553dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ContentValues groupMembershipValues = new ContentValues(); 2554dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.GROUP_ROW_ID, groupId); 2555dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 2556dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(DataColumns.MIMETYPE_ID, 25575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 25585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().insert(Tables.DATA, null, groupMembershipValues); 2559dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2560dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2561dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void deleteDataGroupMembership(long rawContactId, long groupId) { 2562dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final String[] selectionArgs = { 25635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Long.toString(mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)), 2564dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(groupId), 2565dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(rawContactId)}; 25665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.DATA, SELECTION_GROUPMEMBERSHIP_DATA, selectionArgs); 2567dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2568dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2569a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2570a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 2571a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2572a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 2573a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2574a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 2575f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private long insertData(ContentValues values, boolean callerIsSyncAdapter) { 2576a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 2577de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.clear(); 2578de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.putAll(values); 257967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 2580de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID); 258120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2582de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace package with internal mapping 2583de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String packageName = mValues.getAsString(Data.RES_PACKAGE); 2584de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (packageName != null) { 25855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 2586de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 2587de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 2588508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 2589de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace mimetype with internal mapping 2590de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String mimeType = mValues.getAsString(Data.MIMETYPE); 2591de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (TextUtils.isEmpty(mimeType)) { 2592de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new IllegalArgumentException(Data.MIMETYPE + " is required"); 2593de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 25944097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 25955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.get().getMimeTypeId(mimeType)); 2596de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 2597a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2598a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 25995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = rowHandler.insert(mActiveDb.get(), mTransactionContext.get(), rawContactId, mValues); 2600f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 26015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().markRawContactDirty(rawContactId); 2602a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 26035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().rawContactUpdated(rawContactId); 2604a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 26054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 26064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 26073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_items table. The account is checked against the 26093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account in the raw contact for which the stream item is being inserted. If the 26103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * new stream item results in more stream items under this raw contact than the limit, 26113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest one will be deleted (note that if the stream item inserted was the 26123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * oldest, it will be immediately deleted, and this will return 0). 26133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 26143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 26153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 26163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return the stream item _ID of the newly created row, or 0 if it was not created 26173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItem(Uri uri, ContentValues values) { 26193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 26203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 26213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 26223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = mValues.getAsLong(StreamItems.RAW_CONTACT_ID); 26243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 26263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 26273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 26283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream items table. 26306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 26316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 26326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 26333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Insert the new stream item. 26345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = mActiveDb.get().insert(Tables.STREAM_ITEMS, null, mValues); 26356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (id == -1) { 26366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insertion failed. 26376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 26386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 26393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check to see if we're over the limit for stream items under this raw contact. 26413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // It's possible that the inserted stream item is older than the the existing 26423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // ones, in which case it may be deleted immediately (resetting the ID to 0). 26433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = cleanUpOldStreamItems(rawContactId, id); 26443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 26463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_item_photos table. The account is checked against 26503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the account in the raw contact that owns the stream item being modified. 26513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 26523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 26533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 26546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return the stream item photo _ID of the newly created row, or 0 if there was an issue 26556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * with processing the photo or creating the row 26563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItemPhoto(Uri uri, ContentValues values) { 26583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 26593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 26603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 26613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = mValues.getAsLong(StreamItemPhotos.STREAM_ITEM_ID); 26633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemId != 0) { 26643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = lookupRawContactIdForStreamId(streamItemId); 26653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Ensure that the raw contact exists and belongs to the caller's account. 26673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, mValues); 26683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, rawContactId); 26693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream item 26716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 26726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 26736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 26743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 26766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(mValues, false)) { 26776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insert the stream item photo. 26785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = mActiveDb.get().insert(Tables.STREAM_ITEM_PHOTOS, null, mValues); 26796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 26803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 26823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Processes the photo contained in the {@link ContactsContract.StreamItemPhotos#PHOTO} 26866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * field of the given values, attempting to store it in the photo store. If successful, 26876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * the resulting photo file ID will be added to the values for insert/update in the table. 26886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * <p> 26896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * If updating, it is valid for the picture to be empty or unspecified (the function will 26906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * still return true). If inserting, a valid picture must be specified. 26916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param values The content values provided by the caller. 26926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param forUpdate Whether this photo is being processed for update (vs. insert). 26936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return Whether the insert or update should proceed. 26946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 26956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro private boolean processStreamItemPhoto(ContentValues values, boolean forUpdate) { 26966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!values.containsKey(StreamItemPhotos.PHOTO)) { 26976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 26986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 26996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro byte[] photoBytes = values.getAsByteArray(StreamItemPhotos.PHOTO); 27006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoBytes == null) { 27016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 27026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 27046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 27056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 27065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long photoFileId = mPhotoStore.get().insert(new PhotoProcessor(photoBytes, 27071dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim, true), true); 27086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileId != 0) { 27096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.put(StreamItemPhotos.PHOTO_FILE_ID, photoFileId); 27106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(StreamItemPhotos.PHOTO); 27116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return true; 27126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 27136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Couldn't store the photo, return 0. 27146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert"); 27156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 27166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } catch (IOException ioe) { 27186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert", ioe); 27196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 27206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 27236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 27243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Looks up the raw contact ID that owns the specified stream item. 27253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param streamItemId The ID of the stream item. 27263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The associated raw contact ID, or -1 if no such stream item exists. 27273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 27283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long lookupRawContactIdForStreamId(long streamItemId) { 27293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = -1; 27305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.STREAM_ITEMS, 27315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{StreamItems.RAW_CONTACT_ID}, 27323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems._ID + "=?", new String[]{String.valueOf(streamItemId)}, 27333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 27343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 27353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c.moveToFirst()) { 27363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann rawContactId = c.getLong(0); 27373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 27393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 27403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return rawContactId; 27423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 27453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given raw contact ID is owned by the given account. 27463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account is null, this will return true iff the raw contact 27473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * is also associated with the "null" account. 27483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 27493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * If the resolved account does not match, this will throw a security exception. 27503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 27513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to check for. 27523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 27533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void enforceModifyingAccount(Account account, long rawContactId) { 27543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String accountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 27553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + "=? AND " 27563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + "=?"; 27573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String noAccountSelection = RawContactsColumns.CONCRETE_ID + "=? AND " 27583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " IS NULL AND " 27593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " IS NULL"; 27603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Cursor c; 27613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (account != null) { 27625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro c = mActiveDb.get().query(Tables.RAW_CONTACTS, 27635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{RawContactsColumns.CONCRETE_ID}, accountSelection, 27643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(rawContactId), mAccount.name, mAccount.type}, 27653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 27663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 27675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro c = mActiveDb.get().query(Tables.RAW_CONTACTS, 27685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{RawContactsColumns.CONCRETE_ID}, noAccountSelection, 27695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{String.valueOf(rawContactId)}, 27703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 27713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 27733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if(c.getCount() == 0) { 27743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann throw new SecurityException("Caller account does not match raw contact ID " 27753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + rawContactId); 27763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 27783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 27793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 27833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream items matches up with the given 27843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 27853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 27863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 27873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 27883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 27893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item IDs that would be included in this selection. 27903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 27913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItems(Account account, String selection, 27923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 27933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = Lists.newArrayList(); 27943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 27953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 27965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = qb.query(mActiveDb.get(), 27973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{StreamItems._ID, StreamItems.RAW_CONTACT_ID}, 27983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 27993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 28003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 28013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemIds.add(c.getLong(0)); 28023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 28043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 28053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 28073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 28083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds; 28103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 28133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Checks whether the given selection of stream item photos matches up with the given 28143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account. If any of the raw contacts fail the account check, this will throw a 28153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * security exception. 28163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param account The resolved account (may be null). 28173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selection The selection. 28183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param selectionArgs The selection arguments. 28193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The list of stream item photo IDs that would be included in this selection. 28203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 28213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private List<Long> enforceModifyingAccountForStreamItemPhotos(Account account, String selection, 28223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 28233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemPhotoIds = Lists.newArrayList(); 28243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 28253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 28265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = qb.query(mActiveDb.get(), 28275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{StreamItemPhotos._ID, StreamItems.RAW_CONTACT_ID}, 28283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selection, selectionArgs, null, null, null); 28293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 28303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.moveToNext()) { 28313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann streamItemPhotoIds.add(c.getLong(0)); 28323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Throw a security exception if the account doesn't match the raw contact's. 28343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccount(account, c.getLong(1)); 28353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 28373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 28383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemPhotoIds; 28403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 28433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Queries the database for stream items under the given raw contact. If there are 28443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * more entries than {@link ContactsProvider2#MAX_STREAM_ITEMS_PER_RAW_CONTACT}, 28453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest entries (as determined by timestamp) will be deleted. 28463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to examine for stream items. 28473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param insertedStreamItemId The ID of the stream item that was just inserted, 28483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * prompting this cleanup. Callers may pass 0 if no insertion prompted the 28493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * cleanup. 28503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The ID of the inserted stream item if it still exists after cleanup; 28513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 0 otherwise. 28523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 28533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long cleanUpOldStreamItems(long rawContactId, long insertedStreamItemId) { 28543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long postCleanupInsertedStreamId = insertedStreamItemId; 28555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.STREAM_ITEMS, new String[]{StreamItems._ID}, 28563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 28573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, StreamItems.TIMESTAMP + " DESC, " + StreamItems._ID + " DESC"); 28583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 28593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int streamItemCount = c.getCount(); 28603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemCount <= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 28613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Still under the limit - nothing to clean up! 28623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return insertedStreamItemId; 28633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 28643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToLast(); 28653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.getPosition() >= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 28663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = c.getLong(0); 28673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (insertedStreamItemId == streamItemId) { 28683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // The stream item just inserted is being deleted. 28693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann postCleanupInsertedStreamId = 0; 28703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(c.getLong(0)); 28723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToPrevious(); 28733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 28763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 28773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return postCleanupInsertedStreamId; 28793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28819261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 288220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov * Delete data row by row so that fixing of primaries etc work correctly. 288320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov */ 2884f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) { 288520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 288620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2887de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 2888de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 2889f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, 2890f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov selection, selectionArgs, null); 2891de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov try { 2892de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov while(c.moveToNext()) { 2893f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 2894f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 2895a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 28965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro count += rowHandler.delete(mActiveDb.get(), mTransactionContext.get(), c); 2897f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 28985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().markRawContactDirty(rawContactId); 289988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov } 290020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 290120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 2902de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov c.close(); 290320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 290420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 290520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 290620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 290720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 290888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov /** 290988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov * Delete a data row provided that it is one of the allowed mime types. 291088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov */ 291120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov public int deleteData(long dataId, String[] allowedMimeTypes) { 2912f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 291388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 291488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 29154da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 2916f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, Data._ID + "=?", 29174da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1, null); 2918f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 291920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 292020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!c.moveToFirst()) { 292120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 292220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 292320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2924f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 292520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean valid = false; 292620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov for (int i = 0; i < allowedMimeTypes.length; i++) { 292720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.equals(mimeType, allowedMimeTypes[i])) { 292820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov valid = true; 292920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 293020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 293120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 293220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 293320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!valid) { 29347a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana throw new IllegalArgumentException("Data type mismatch: expected " 293520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov + Lists.newArrayList(allowedMimeTypes)); 293620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 2937a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 29385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return rowHandler.delete(mActiveDb.get(), mTransactionContext.get(), c); 293920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 294020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 294120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 294220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 294320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 294420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov /** 2945ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 2946ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 2947f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2948f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2949f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2950f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 29513593682b8d9213fde576a0cff54458ad50563980Dave Santoro final AccountWithDataSet accountWithDataSet = resolveAccountWithDataSet(uri, mValues); 2952ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2953ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 2954f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String packageName = mValues.getAsString(Groups.RES_PACKAGE); 295567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 29565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 295767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 2958f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.remove(Groups.RES_PACKAGE); 2959ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2960dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final boolean isFavoritesGroup = mValues.getAsLong(Groups.FAVORITES) != null 2961dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ? mValues.getAsLong(Groups.FAVORITES) != 0 2962dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana : false; 2963dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2964f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2965f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(Groups.DIRTY, 1); 296673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 296773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 29685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long result = mActiveDb.get().insert(Tables.GROUPS, Groups.TITLE, mValues); 2969ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2970dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && isFavoritesGroup) { 2971dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // add all starred raw contacts to this group 2972dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String selection; 2973dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs; 29743593682b8d9213fde576a0cff54458ad50563980Dave Santoro if (accountWithDataSet == null) { 2975dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + " IS NULL AND " 297643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.ACCOUNT_TYPE + " IS NULL AND " 297743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.DATA_SET + " IS NULL"; 2978dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selectionArgs = null; 29793593682b8d9213fde576a0cff54458ad50563980Dave Santoro } else if (accountWithDataSet.getDataSet() == null) { 2980dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection = RawContacts.ACCOUNT_NAME + "=? AND " 29813593682b8d9213fde576a0cff54458ad50563980Dave Santoro + RawContacts.ACCOUNT_TYPE + "=? AND " 29823593682b8d9213fde576a0cff54458ad50563980Dave Santoro + RawContacts.DATA_SET + " IS NULL"; 29833593682b8d9213fde576a0cff54458ad50563980Dave Santoro selectionArgs = new String[] { 29843593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountName(), 29853593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountType() 29863593682b8d9213fde576a0cff54458ad50563980Dave Santoro }; 298743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } else { 298843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selection = RawContacts.ACCOUNT_NAME + "=? AND " 298943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.ACCOUNT_TYPE + "=? AND " 299043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + RawContacts.DATA_SET + "=?"; 29913593682b8d9213fde576a0cff54458ad50563980Dave Santoro selectionArgs = new String[] { 29923593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountName(), 29933593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getAccountType(), 29943593682b8d9213fde576a0cff54458ad50563980Dave Santoro accountWithDataSet.getDataSet() 29953593682b8d9213fde576a0cff54458ad50563980Dave Santoro }; 2996dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 29975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.RAW_CONTACTS, 2998dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{RawContacts._ID, RawContacts.STARRED}, 2999dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana selection, selectionArgs, null, null, null); 3000892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov try { 3001892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov while (c.moveToNext()) { 3002892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (c.getLong(1) != 0) { 3003892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov final long rawContactId = c.getLong(0); 3004892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov insertDataGroupMembership(rawContactId, result); 30055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().markRawContactDirty(rawContactId); 3006892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } 3007dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3008892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } finally { 3009892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov c.close(); 3010dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3011dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3012dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3013f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mValues.containsKey(Groups.GROUP_VISIBLE)) { 30141a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3015ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey } 3016ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 3017ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey return result; 3018ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3019ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 30205aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private long insertSettings(Uri uri, ContentValues values) { 30215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long id = mActiveDb.get().insert(Tables.SETTINGS, null, values); 30225aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey 30231a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 30241a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3025e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 30261a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 3027e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return id; 3028e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3029e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3030ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 303182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov * Inserts a status update. 30321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 303382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov public long insertStatusUpdate(ContentValues values) { 303482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov final String handle = values.getAsString(StatusUpdates.IM_HANDLE); 30350a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL); 30364dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov String customProtocol = null; 30374dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov 30380a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) { 303982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL); 30404dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov if (TextUtils.isEmpty(customProtocol)) { 30414dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov throw new IllegalArgumentException( 30424dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM"); 30434dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov } 30441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 30451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3046dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long rawContactId = -1; 3047dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long contactId = -1; 304882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov Long dataId = values.getAsLong(StatusUpdates.DATA_ID); 30496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountType = null; 30506802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountName = null; 3051f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov mSb.setLength(0); 30522526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.clear(); 3053dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (dataId != null) { 3054dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the contact info for the given data row. 3055dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 30562526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(Tables.DATA + "." + Data._ID + "=?"); 30572526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(dataId)); 30581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 3059dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the data row to attach this presence update to 3060dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 30610a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(handle) || protocol == null) { 30620a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required"); 30630a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 30640a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 3065dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // TODO: generalize to allow other providers to match against email 3066dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol; 3067dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 30685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String mimeTypeIdIm = String.valueOf(mDbHelper.get().getMimeTypeIdForIm()); 3069dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (matchEmail) { 30705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String mimeTypeIdEmail = String.valueOf(mDbHelper.get().getMimeTypeIdForEmail()); 3071f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 3072f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise 3073f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the "OR" conjunction confuses it and it switches to a full scan of 3074f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the raw_contacts table. 3075f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 3076f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // This code relies on the fact that Im.DATA and Email.DATA are in fact the same 3077f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // column - Data.DATA1 30782526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + " IN (?,?)" + 30792526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Data.DATA1 + "=?" + 30802526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND ((" + DataColumns.MIMETYPE_ID + "=? AND " + Im.PROTOCOL + "=?"); 30812526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 30822526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 30832526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 30842526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 30852526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 3086dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 30872526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 30882526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 3089dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 30902526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=?))"); 30912526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 3092dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } else { 30932526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + "=?" + 30942526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.PROTOCOL + "=?" + 30952526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.DATA + "=?"); 30962526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 30972526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 30982526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 3099dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 31002526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 31012526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 3102dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 3103dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 31041f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 310582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.DATA_ID)) { 31062526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + DataColumns.CONCRETE_ID + "=?"); 31072526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(values.getAsString(StatusUpdates.DATA_ID)); 3108dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 310970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 311070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 31111f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 31121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 31135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro cursor = mActiveDb.get().query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 31142526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null, 31154394086494fe7909aaca70f56fb4bb08beebf303Dmitri Plotnikov Clauses.CONTACT_VISIBLE + " DESC, " + Data.RAW_CONTACT_ID); 31161f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 311767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataId = cursor.getLong(DataContactsQuery.DATA_ID); 31185ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID); 31196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountType = cursor.getString(DataContactsQuery.ACCOUNT_TYPE); 31206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountName = cursor.getString(DataContactsQuery.ACCOUNT_NAME); 3121e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 31221f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 31231f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 31241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 31251f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 31261f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 312731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 312831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 312931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 31301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 31311f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 313282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.PRESENCE)) { 3133a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (customProtocol == null) { 3134a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 3135a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // properly enforce uniqueness of null values 3136a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov customProtocol = ""; 3137a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3138a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3139a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.clear(); 314082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.DATA_ID, dataId); 3141a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId); 3142a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.CONTACT_ID, contactId); 314382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PROTOCOL, protocol); 314482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 314582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_HANDLE, handle); 314682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.IM_ACCOUNT)) { 314782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT)); 3148a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 314982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PRESENCE, 315082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov values.getAsString(StatusUpdates.PRESENCE)); 3151aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori mValues.put(StatusUpdates.CHAT_CAPABILITY, 3152aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori values.getAsString(StatusUpdates.CHAT_CAPABILITY)); 31531f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3154a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // Insert the presence update 31555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().replace(Tables.PRESENCE, null, mValues); 3156a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3157e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 31580a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 315982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.STATUS)) { 316082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String status = values.getAsString(StatusUpdates.STATUS); 31610a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE); 31620bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Resources resources = getContext().getResources(); 31630bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (!TextUtils.isEmpty(resPackage)) { 31640bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann PackageManager pm = getContext().getPackageManager(); 31650bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann try { 31660bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann resources = pm.getResourcesForApplication(resPackage); 31670bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } catch (NameNotFoundException e) { 31680bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Log.w(TAG, "Contact status update resource package not found: " 31690bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + resPackage); 31700bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 31710bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 31720bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Integer labelResourceId = values.getAsInteger(StatusUpdates.STATUS_LABEL); 31730a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 31740bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if ((labelResourceId == null || labelResourceId == 0) && protocol != null) { 31750bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann labelResourceId = Im.getProtocolLabelResource(protocol); 31760a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 31770bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann String labelResource = getResourceName(resources, "string", labelResourceId); 31780a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 31790bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Integer iconResourceId = values.getAsInteger(StatusUpdates.STATUS_ICON); 31800a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov // TODO compute the default icon based on the protocol 31810a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 31820bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann String iconResource = getResourceName(resources, "drawable", iconResourceId); 31830bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 3184a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (TextUtils.isEmpty(status)) { 31855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().deleteStatusUpdate(dataId); 3186a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } else { 31876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP); 31886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (timestamp != null) { 31895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().replaceStatusUpdate(dataId, timestamp, status, resPackage, 31900bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann iconResourceId, labelResourceId); 31916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 31925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().insertStatusUpdate(dataId, status, resPackage, iconResourceId, 31930bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann labelResourceId); 31946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 31956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 31966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For forward compatibility with the new stream item API, insert this status update 31976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // there as well. If we already have a stream item from this source, update that 31986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // one instead of inserting a new one (since the semantics of the old status update 31996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // API is to only have a single record). 32006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (rawContactId != -1 && !TextUtils.isEmpty(status)) { 32016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentValues streamItemValues = new ContentValues(); 32026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 3203d5ef5903570e533a501abe6a8e3d533fdb5318fcFlavio Lerda // Status updates are text only but stream items are HTML. 3204e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda streamItemValues.put(StreamItems.TEXT, statusUpdateToHtml(status)); 32056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.COMMENTS, ""); 32066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_PACKAGE, resPackage); 32076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_ICON, iconResource); 32086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_LABEL, labelResource); 32096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TIMESTAMP, 32106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro timestamp == null ? System.currentTimeMillis() : timestamp); 32116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 32126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Note: The following is basically a workaround for the fact that status 32136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates didn't do any sort of account enforcement, while social stream item 32146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates do. We can't expect callers of the old API to start passing account 32156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // information along, so we just populate the account params appropriately for 321643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // the raw contact. Data set is not relevant here, as we only check account 321743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // name and type. 32186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (accountName != null && accountType != null) { 32196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_NAME, accountName); 32206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_TYPE, accountType); 32216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 32226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 32236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Check for an existing stream item from this source, and insert or update. 32246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Uri streamUri = StreamItems.CONTENT_URI; 32256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = query(streamUri, new String[]{StreamItems._ID}, 32266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", 32276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{String.valueOf(rawContactId)}, null); 32286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 32296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (c.getCount() > 0) { 32306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.moveToFirst(); 32316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro update(ContentUris.withAppendedId(streamUri, c.getLong(0)), 32326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues, null, null); 32336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 32346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro insert(streamUri, streamItemValues); 32356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 32366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 32376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 32386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 32396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 3240e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3241e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3242bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov 3243a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (contactId != -1) { 32445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateLastStatusUpdateId(contactId); 3245a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3246a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3247a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov return dataId; 32481f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 32491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3250e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda /** Converts a status update to HTML. */ 3251e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda private String statusUpdateToHtml(String status) { 3252e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda String html = Html.toHtml(new SpannableString(status)); 3253e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda if (html.endsWith("\n")) { 3254fe6c9b5240b1b26a72358dbb80bdda9c3f5c080dFlavio Lerda html = html.substring(0, html.length() - 1); 3255e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda } 3256e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda return html; 3257e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda } 3258e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda 32590bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann private String getResourceName(Resources resources, String expectedType, Integer resourceId) { 32600bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann try { 32610bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (resourceId == null || resourceId == 0) return null; 32620bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 32630bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann // Resource has an invalid type (e.g. a string as icon)? ignore 32640bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann final String resourceEntryName = resources.getResourceEntryName(resourceId); 32650bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann final String resourceTypeName = resources.getResourceTypeName(resourceId); 32660bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (!expectedType.equals(resourceTypeName)) { 32670bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Log.w(TAG, "Resource " + resourceId + " (" + resourceEntryName + ") is of type " + 32680bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann resourceTypeName + " but " + expectedType + " is required."); 32690bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return null; 32700bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 32710bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 32720bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return resourceEntryName; 32730bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } catch (NotFoundException e) { 32740bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return null; 32750bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 32760bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 32770bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 32784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3279de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 3280bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3281b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "deleteInTransaction: " + uri); 3282b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 32835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 32845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 32855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 32865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(mDb); 32875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 32885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 3289b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3290f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3291f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 3292508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 3293508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 329435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 32955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 32965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().delete(mActiveDb.get(), selection, 32975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 32985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 32995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case SYNCSTATE_ID: { 33005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String selectionWithId = 33015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 33025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 33035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().delete(mActiveDb.get(), selectionWithId, 33045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 33055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 330635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 33075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE_ID: { 3308b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3309b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3310b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 33115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileHelper.getSyncState().delete(mActiveDb.get(), selectionWithId, 33125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 33135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 3314b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3315cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov case CONTACTS: { 3316cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov // TODO 3317cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return 0; 3318cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3319cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3320d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3321d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 3322dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 33236bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 33246bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 33259fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP: { 33262e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 33272e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 33282e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 33295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 3330fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 33312e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 33322e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 33335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 3334dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 33352e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 33362e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 33379fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP_ID: { 33389fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // lookup contact by id and lookup key to see if they still match the actual record 33399fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final List<String> pathSegments = uri.getPathSegments(); 33409fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final String lookupKey = pathSegments.get(2); 33419fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 33429fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann setTablesAndProjectionMapForContacts(lookupQb, uri, null); 3343a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 33449fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann String[] args; 33459fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (selectionArgs == null) { 33469fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[2]; 33479fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 33489fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[selectionArgs.length + 2]; 33499fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 33509fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 33519fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args[0] = String.valueOf(contactId); 335260de6f6c3c70e53b603a47b0efc80993353a8368Daniel Lehmann args[1] = Uri.encode(lookupKey); 33539fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?"); 33545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = query(mActiveDb.get(), lookupQb, null, selection, args, null, null, 33555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro null); 33569fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann try { 33579fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (c.getCount() == 1) { 33589fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // contact was unmodified so go ahead and delete it 3359dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 33609fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 33619fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // row was changed (e.g. the merging might have changed), we got multiple 33629fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // rows or the supplied selection filtered the record out 33639fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann return 0; 33649fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 33659fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } finally { 33669fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann c.close(); 33679fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 33689fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 33699fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann 33702971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case RAW_CONTACTS: { 33712971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 33725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.RAW_CONTACTS, 3373fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov new String[]{RawContacts._ID, RawContacts.CONTACT_ID}, 3374e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 33752971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 33762971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 33772971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = c.getLong(0); 3378fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov long contactId = c.getLong(1); 3379fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov numDeletes += deleteRawContact(rawContactId, contactId, 3380fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 33812971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 33822971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 33832971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 33842971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 33852971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 33862971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 33872971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 33885ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 33892971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = ContentUris.parseId(uri); 33905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return deleteRawContact(rawContactId, mDbHelper.get().getContactId(rawContactId), 3391fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 3392508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3393508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 339420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3395f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 3396944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong return deleteData(appendAccountToSelection(uri, selection), selectionArgs, 3397f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana callerIsSyncAdapter); 339820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 339920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 340048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 340148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 340248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 340348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3404508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 3405f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 34064da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 34074da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter); 3408ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3409ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3410ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3411f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 34125aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter); 34132971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 34142971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 34152971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case GROUPS: { 34162971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 34175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.GROUPS, new String[]{Groups._ID}, 3418e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong appendAccountToSelection(uri, selection), selectionArgs, null, null, null); 34192971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 34202971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 34215aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter); 34222971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 34232971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 34242971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 34252971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 342681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (numDeletes > 0) { 3427f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 342881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 34292971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 3430508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3431508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 3432eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 343343880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3434e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs); 3435eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3436eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 34375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 34385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 34390a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov return deleteStatusUpdates(selection, selectionArgs); 34401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 34411f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 34423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 34433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 34443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), selection, selectionArgs); 34453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 34483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 34493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), 34509b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann StreamItems._ID + "=?", 34513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 34523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 34553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 34563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), selection, selectionArgs); 34573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 34603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 34613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 34623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 34633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), 34643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " 34653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + StreamItemPhotos.STREAM_ITEM_ID + "=?", 34663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 34673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 346981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 347081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 34713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return mLegacyApiSupport.delete(uri, selection, selectionArgs); 347281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3473508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 34744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 34754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 34761c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) { 3477ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 34785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long groupMembershipMimetypeId = mDbHelper.get() 347994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 34805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 348194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 348294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupId, null); 348394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 348494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana try { 3485f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 34865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 348794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } else { 348894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.clear(); 348994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.put(Groups.DELETED, 1); 3490f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mValues.put(Groups.DIRTY, 1); 34915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, 34925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro null); 349394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 349494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } finally { 34951a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 349694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 349794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 349894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 34995aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int deleteSettings(Uri uri, String selection, String[] selectionArgs) { 35005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final int count = mActiveDb.get().delete(Tables.SETTINGS, selection, selectionArgs); 35011a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3502e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3503e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3504e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3505dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int deleteContact(long contactId, boolean callerIsSyncAdapter) { 350696b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(contactId); 35075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, 350896b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker RawContacts.CONTACT_ID + "=?", mSelectionArgs1, 350996b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker null, null, null); 3510cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov try { 3511cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov while (c.moveToNext()) { 3512cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov long rawContactId = c.getLong(0); 3513dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 3514cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3515cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } finally { 3516cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov c.close(); 3517cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3518cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 35193826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 35203826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 35215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 3522cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3523cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3524fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) { 35255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().invalidateAggregationExceptionCache(); 35263826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 35273826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3528f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 35295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.PRESENCE, 35305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null); 35315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int count = mActiveDb.get().delete(Tables.RAW_CONTACTS, 35325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro RawContacts._ID + "=" + rawContactId, null); 35335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateDisplayNameForContact(mActiveDb.get(), contactId); 3534fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return count; 353533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } else { 35365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().removeContactIfSingleton(rawContactId); 3537dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 353833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 353933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 354033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 35410a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private int deleteStatusUpdates(String selection, String[] selectionArgs) { 35429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // delete from both tables: presence and status_updates 35439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 35449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (VERBOSE_LOGGING) { 35459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori Log.v(TAG, "deleting data from status_updates for " + selection); 35469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection), 35489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 35495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.PRESENCE, selection, selectionArgs); 35500a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 35510a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 35523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItems(Uri uri, ContentValues values, String selection, 35533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 35543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream items to be deleted, and check that they belong 35553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // to the account. 35563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 35573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<Long> streamItemIds = enforceModifyingAccountForStreamItems( 35583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann account, selection, selectionArgs); 35593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 35613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann for (long streamItemId : streamItemIds) { 35623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(streamItemId); 35633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mVisibleTouched = true; 35663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return streamItemIds.size(); 35673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItem(long streamItemId) { 35703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 35713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItemPhotos(streamItemId); 35725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.STREAM_ITEMS, StreamItems._ID + "=?", 35733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 35743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(Uri uri, ContentValues values, String selection, 35773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 35783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // First query for the stream item photos to be deleted, and check that they 35793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // belong to the account. 35803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 35813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 35823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If no security exception has been thrown, we're fine to delete. 35845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.STREAM_ITEM_PHOTOS, selection, selectionArgs); 35853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(long streamItemId) { 35883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 35895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.STREAM_ITEM_PHOTOS, 35905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro StreamItemPhotos.STREAM_ITEM_ID + "=?", 35913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 35923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 3594dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int markRawContactAsDeleted(long rawContactId, boolean callerIsSyncAdapter) { 359581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 359681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 3597cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.clear(); 3598cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DELETED, 1); 3599cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 3600cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1); 3601cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 3602cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3603dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return updateRawContact(rawContactId, mValues, callerIsSyncAdapter); 3604cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3605cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 36064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3607de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int updateInTransaction(Uri uri, ContentValues values, String selection, 3608de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov String[] selectionArgs) { 3609bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3610b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "updateInTransaction: " + uri); 3611b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3612b5a4add17815167d20a90645779df34cdf45280dFred Quintana 36135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 36145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 36155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(mDb); 36165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 36175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 361835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 361900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 362000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 3621b5a4add17815167d20a90645779df34cdf45280dFred Quintana if (match == SYNCSTATE_ID && selection == null) { 3622b5a4add17815167d20a90645779df34cdf45280dFred Quintana long rowId = ContentUris.parseId(uri); 36231129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Object data = values.get(ContactsContract.SyncState.DATA); 36245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().syncStateUpdated(rowId, data); 3625b5a4add17815167d20a90645779df34cdf45280dFred Quintana return 1; 3626b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3627b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3628f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3629f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 363000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 363135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 36325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 36335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().update(mActiveDb.get(), values, 3634b5a4add17815167d20a90645779df34cdf45280dFred Quintana appendAccountToSelection(uri, selection), selectionArgs); 3635b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3636b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: { 3637b5a4add17815167d20a90645779df34cdf45280dFred Quintana selection = appendAccountToSelection(uri, selection); 3638b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3639b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3640b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 36415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().update(mActiveDb.get(), values, 36425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionWithId, selectionArgs); 36435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 36445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 36455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE_ID: { 36465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection = appendAccountToSelection(uri, selection); 36475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String selectionWithId = 36485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 36495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 36505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileHelper.getSyncState().update(mActiveDb.get(), values, 3651b5a4add17815167d20a90645779df34cdf45280dFred Quintana selectionWithId, selectionArgs); 3652b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 365335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3654d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 3655dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter); 365600d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 365700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 365800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3659d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 3660dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(ContentUris.parseId(uri), values, callerIsSyncAdapter); 3661c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 3662c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 3663c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 366424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 36655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter); 366624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 366724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 366824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 36692e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP: 36702e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP_ID: { 36712e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 36722e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 36732e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 36745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 3675fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 36762e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 36772e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 36785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 3679dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(contactId, values, callerIsSyncAdapter); 36802e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey break; 36812e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 36822e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 36837d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh case RAW_CONTACTS_DATA: { 36847d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh final String rawContactId = uri.getPathSegments().get(1); 36857d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ") 36867d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh + (selection == null ? "" : " AND " + selection); 36877d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 36887d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter); 36897d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 36907d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh break; 36917d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh } 36927d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 369320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov case DATA: { 3694944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong count = updateData(uri, values, appendAccountToSelection(uri, selection), 3695f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 369681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3697f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 369881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 369920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 370020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3701c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 370248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 370348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 370448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 370548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 3706f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter); 370781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3708f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 370981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 371000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 371100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 37127e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 37135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case RAW_CONTACTS: 37145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_RAW_CONTACTS: { 37155ac5c70d1165309302ebcc931f51723e37d31e0bJeff Sharkey selection = appendAccountToSelection(uri, selection); 3716dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, selection, selectionArgs, callerIsSyncAdapter); 37177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 37187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 37197e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 37205ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 372133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 37224529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (selection != null) { 37234da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 37244da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov count = updateRawContacts(values, RawContacts._ID + "=?" 3725dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND(" + selection + ")", selectionArgs, 3726dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 37274529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } else { 37284da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 3729dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1, 3730dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 37314529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37327e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 37337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 37347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 3735ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 37365aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, appendAccountToSelection(uri, selection), 3737f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 373881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3739f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 374081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3741ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3742ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3743ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3744ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3745ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 37464da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId)); 37474da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String selectionWithId = Groups._ID + "=? " 374873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov + (selection == null ? "" : " AND " + selection); 37495aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, selectionWithId, selectionArgs, 37505aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey callerIsSyncAdapter); 375181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3752f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 375381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3754ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3755ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3756ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3757127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 37585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro count = updateAggregationException(mActiveDb.get(), values); 3759b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 3760b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3761b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 3762eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 3763e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey count = updateSettings(uri, values, appendAccountToSelection(uri, selection), 3764e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey selectionArgs); 376543880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3766eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 3767eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3768eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 37695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 37705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 37719705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori count = updateStatusUpdate(uri, values, selection, selectionArgs); 37729705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori break; 37739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 37749705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 37753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 37763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, selection, selectionArgs); 37773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 37783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 37793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 37803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 37819b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann count = updateStreamItems(uri, values, StreamItems._ID + "=?", 37823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 37833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 37843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 37853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 37863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 37873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, selection, selectionArgs); 37883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 37893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 37903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 37913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 37923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 37933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 37943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{streamItemId}); 37953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 37963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 37973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 37983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 37993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 38003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 38013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 38023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " + 38033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?", 38043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 38053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 38063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 380872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov case DIRECTORIES: { 3809bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanPackagesByUid(Binder.getCallingUid()); 381072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov count = 1; 3811d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 3812d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 3813d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 381446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa case DATA_USAGE_FEEDBACK_ID: { 381546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (handleDataUsageFeedback(uri)) { 381646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 1; 381746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 381846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 0; 381946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 382046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa break; 382146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 382246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 382381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 382481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 3825f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 382681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 382700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 382800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 382900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 38304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 38314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 38329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private int updateStatusUpdate(Uri uri, ContentValues values, String selection, 38339705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori String[] selectionArgs) { 38349705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // update status_updates table, if status is provided 38359705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 38369705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori int updateCount = 0; 38379705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values); 38389705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 38395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro updateCount = mActiveDb.get().update(Tables.STATUS_UPDATES, 38409705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues, 38419705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori getWhereClauseForStatusUpdatesTable(selection), 38429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 38439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 38449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 38459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // now update the Presence table 38469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues = getSettableColumnsForPresenceTable(values); 38479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 38485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro updateCount = mActiveDb.get().update(Tables.PRESENCE, settableValues, 38499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selection, selectionArgs); 38509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 38519705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO updateCount is not entirely a valid count of updated rows because 2 tables could 38529705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // potentially get updated in this method. 38539705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return updateCount; 38549705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 38559705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 38563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItems(Uri uri, ContentValues values, String selection, 38573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 38583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream items can't be moved to a new raw contact. 38593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItems.RAW_CONTACT_ID); 38603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream items being updated belong to the account. 38623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 38633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItems(account, selection, selectionArgs); 38643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream items table. 38666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 38676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 38686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 38693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If there's been no exception, the update should be fine. 38705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().update(Tables.STREAM_ITEMS, values, selection, selectionArgs); 38713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItemPhotos(Uri uri, ContentValues values, String selection, 38743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 38753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream item photos can't be moved to a new stream item. 38763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItemPhotos.STREAM_ITEM_ID); 38773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check that the stream item photos being updated belong to the account. 38793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann Account account = resolveAccount(uri, values); 38803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann enforceModifyingAccountForStreamItemPhotos(account, selection, selectionArgs); 38813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream item 38836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 38846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 38856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 38866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 38876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo (since we're updating, it's valid for the photo to not be present). 38886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(values, true)) { 38896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // If there's been no exception, the update should be fine. 38905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().update(Tables.STREAM_ITEM_PHOTOS, values, selection, 38915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 38926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 38936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 38943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38969705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori /** 38979705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori * Build a where clause to select the rows to be updated in status_updates table. 38989705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori */ 38999705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private String getWhereClauseForStatusUpdatesTable(String selection) { 39009705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.setLength(0); 39019705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE); 39029705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(selection); 39039705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(")"); 39049705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mSb.toString(); 39059705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 39069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 39079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) { 39089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 39099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values, 39109705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS); 39119705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values, 39129705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_TIMESTAMP); 39139705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values, 39149705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_RES_PACKAGE); 39159705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values, 39169705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_LABEL); 39179705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values, 39189705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_ICON); 39199705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 39209705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 39219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 39229705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForPresenceTable(ContentValues values) { 39239705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 39249705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values, 39259705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.PRESENCE); 3926aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.CHAT_CAPABILITY, values, 3927aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori StatusUpdates.CHAT_CAPABILITY); 39289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 39299705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 39309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 39315aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int updateGroups(Uri uri, ContentValues values, String selectionWithId, 3932f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 393373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3934ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3935ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov 393673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov ContentValues updatedValues; 3937f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter && !values.containsKey(Groups.DIRTY)) { 393873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = mValues; 393973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.clear(); 394073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.putAll(values); 394173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.put(Groups.DIRTY, 1); 394273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } else { 394373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues = values; 394473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 394573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 39465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int count = mActiveDb.get().update(Tables.GROUPS, updatedValues, selectionWithId, 39475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 39481a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) { 39491a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 395094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 395143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 395243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO: This will not work for groups that have a data set specified, since the content 395343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // resolver will not be able to request a sync for the right source (unless it is updated 395443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // to key off account with data set). 39556ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi if (updatedValues.containsKey(Groups.SHOULD_SYNC) 39561129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) { 39575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.GROUPS, new String[]{Groups.ACCOUNT_NAME, 3958e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey Groups.ACCOUNT_TYPE}, selectionWithId, selectionArgs, null, 39596ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi null, null); 39606ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountName; 39616ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi String accountType; 39626ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi try { 39636ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi while (c.moveToNext()) { 39646ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountName = c.getString(0); 39656ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi accountType = c.getString(1); 396624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 39676ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi Account account = new Account(accountName, accountType); 3968ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov ContentResolver.requestSync(account, ContactsContract.AUTHORITY, 39696ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi new Bundle()); 39706ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi break; 39716ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 39726ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 39736ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } finally { 39746ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi c.close(); 39756ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 39766ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 397794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana return count; 397894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 397994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 3980b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private int updateSettings(Uri uri, ContentValues values, String selection, 3981b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov String[] selectionArgs) { 39825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final int count = mActiveDb.get().update(Tables.SETTINGS, values, selection, selectionArgs); 39831a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 39841a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3985e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3986e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3987e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3988e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3989dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs, 3990dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 39914529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (values.containsKey(RawContacts.CONTACT_ID)) { 39924529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " + 39934529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov "in content values. Contact IDs are assigned automatically"); 39944529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 399573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 399697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 399797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 399897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0"); 399997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 400097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 40014529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov int count = 0; 40025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(Views.RAW_CONTACTS, 400351bf5ea9531b9da72caff607dbdf35fd6f61cbe2Jeff Sharkey new String[] { RawContacts._ID }, selection, 40044529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov selectionArgs, null, null, null); 40054529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov try { 40064529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov while (cursor.moveToNext()) { 40074529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov long rawContactId = cursor.getLong(0); 4008dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateRawContact(rawContactId, values, callerIsSyncAdapter); 40094529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov count++; 40104529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 40114529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } finally { 40124529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov cursor.close(); 40134529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 40144529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 40154529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov return count; 40164529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 40174529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 4018dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContact(long rawContactId, ContentValues values, 4019dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 402096b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker final String selection = RawContacts._ID + " = ?"; 402196b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(rawContactId); 402219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED) 402319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka && values.getAsInteger(RawContacts.DELETED) == 0); 402419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int previousDeleted = 0; 4025ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountType = null; 4026ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String accountName = null; 402743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = null; 402819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete) { 40295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, 40305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection, mSelectionArgs1, null, null, null); 403119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka try { 403219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (cursor.moveToFirst()) { 403319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka previousDeleted = cursor.getInt(RawContactsQuery.DELETED); 4034ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE); 4035ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov accountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME); 403643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro dataSet = cursor.getString(RawContactsQuery.DATA_SET); 403719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 403819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } finally { 403919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka cursor.close(); 404019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 404119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 404219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT); 404319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 4044f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 40455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int count = mActiveDb.get().update(Tables.RAW_CONTACTS, values, selection, mSelectionArgs1); 40465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count != 0) { 4047f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (values.containsKey(RawContacts.AGGREGATION_MODE)) { 4048f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = values.getAsInteger(RawContacts.AGGREGATION_MODE); 4049f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov 4050f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // As per ContactsContract documentation, changing aggregation mode 4051f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // to DEFAULT should not trigger aggregation 4052f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) { 40535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId, aggregationMode, false); 4054f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 4055f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 4056433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey if (values.containsKey(RawContacts.STARRED)) { 4057dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 4058dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 4059dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana values.getAsLong(RawContacts.STARRED) != 0); 4060dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 40615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateStarred(rawContactId); 4062dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 4063dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then update the 4064dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // favorites group membership based on whether or not this contact is starred. 4065dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // If it is starred, add a group membership, if one doesn't already exist 4066dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // otherwise delete any matching group memberships. 4067dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 40685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro boolean starred = 0 != DatabaseUtils.longForQuery(mActiveDb.get(), 4069dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana SELECTION_STARRED_FROM_RAW_CONTACTS, 4070dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}); 4071dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred); 4072dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4073dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4074dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 4075dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then add a 4076dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // group membership to the group marked as AutoAdd, if any. 4077dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) { 4078dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 4079433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey } 4080dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 4081285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov if (values.containsKey(RawContacts.SOURCE_ID)) { 40825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateLookupKeyForRawContact(mActiveDb.get(), rawContactId); 4083285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 4084f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.containsKey(RawContacts.NAME_VERIFIED)) { 4085f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 4086f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // If setting NAME_VERIFIED for this raw contact, reset it for all 4087f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // other raw contacts in the same aggregate 4088f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) { 40895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().resetNameVerifiedForOtherRawContacts(rawContactId); 4090f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 40915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateDisplayNameForRawContact(mActiveDb.get(), rawContactId); 4092f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 409319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete && previousDeleted == 1) { 40945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().rawContactInserted(rawContactId, 409543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new AccountWithDataSet(accountName, accountType, dataSet)); 409619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 40975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 40985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return count; 409933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 410033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 4101321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana private int updateData(Uri uri, ContentValues values, String selection, 4102f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 410320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 410420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 410520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data._ID); 41065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov mValues.remove(Data.RAW_CONTACT_ID); 410720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 410820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 410920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String packageName = values.getAsString(Data.RES_PACKAGE); 411020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (packageName != null) { 411120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 41125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 411320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 411420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 411597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 411697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 411797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov Data.IS_READ_ONLY + "=0"); 411897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 411997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 4120653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov int count = 0; 412120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4122653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 4123653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // so we don't need to worry about updating data we don't have permission to read. 41245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryLocal(uri, 4125f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro DataRowHandler.DataUpdateQuery.COLUMNS, 41265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection, selectionArgs, null, -1 /* directory ID */); 4127653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov try { 4128653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov while(c.moveToNext()) { 4129f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count += updateData(mValues, c, callerIsSyncAdapter); 413020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 4131653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov } finally { 4132653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov c.close(); 413320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 413420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4135653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return count; 413620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 413720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4138f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) { 4139653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov if (values.size() == 0) { 4140653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return 0; 4141321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 4142653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov 4143f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String mimeType = c.getString(DataRowHandler.DataUpdateQuery.MIMETYPE); 4144a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 4145f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean updated = 41465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro rowHandler.update(mActiveDb.get(), mTransactionContext.get(), values, c, 41475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro callerIsSyncAdapter); 4148f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) { 4149f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 4150a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov } 4151f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return updated ? 1 : 0; 4152321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 4153321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana 41548c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov private int updateContactOptions(ContentValues values, String selection, 4155dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 41568c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov int count = 0; 41575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(Views.CONTACTS, 41585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[] { Contacts._ID }, selection, selectionArgs, null, null, null); 41598c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov try { 41608c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov while (cursor.moveToNext()) { 41618c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov long contactId = cursor.getLong(0); 416224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 4163dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateContactOptions(contactId, values, callerIsSyncAdapter); 41648c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov count++; 41658c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 41668c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } finally { 41678c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov cursor.close(); 41688c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 41698c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 41708c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov return count; 41718c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 41728c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 4173dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateContactOptions(long contactId, ContentValues values, 4174dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 4175d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 41768c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 4177b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 4178d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 4179b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 4180d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 4181b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 4182d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 4183b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 4184d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 4185b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 4186d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.STARRED); 4187d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 4188d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 41898c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.size() == 0) { 4190d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 4191d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 4192d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 41938c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.containsKey(RawContacts.STARRED)) { 4194c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey // Mark dirty when changing starred to trigger sync 41958c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 4196c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey } 4197c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey 41984da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(contactId); 41995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?" 420097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov + " AND " + RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0", mSelectionArgs1); 42018c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 4202dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (mValues.containsKey(RawContacts.STARRED) && !callerIsSyncAdapter) { 42035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(Views.RAW_CONTACTS, 4204dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=?", 4205dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mSelectionArgs1, null, null, null); 4206dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 4207dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (cursor.moveToNext()) { 4208dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana long rawContactId = cursor.getLong(0); 4209dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 4210dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mValues.getAsLong(RawContacts.STARRED) != 0); 4211dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4212dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 4213dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana cursor.close(); 4214dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4215dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4216dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 42178c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // Copy changeable values to prevent automatically managed fields from 42188c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // being explicitly updated by clients. 42198c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 4220b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 42218c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 4222b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 42238c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 4224b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 42258c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 4226b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 42278c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 4228b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 42298c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.STARRED); 42308c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 42315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int rslt = mActiveDb.get().update(Tables.CONTACTS, mValues, Contacts._ID + "=?", 42325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mSelectionArgs1); 42336e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori 42349b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori if (values.containsKey(Contacts.LAST_TIME_CONTACTED) && 42359b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori !values.containsKey(Contacts.TIMES_CONTACTED)) { 42365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 42375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 42389b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori } 42399b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori return rslt; 4240f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 4241d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 4242127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 4243127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 42440c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1); 42450c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2); 424680c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 4247ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId1; 4248ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId2; 42490c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (rcId1 < rcId2) { 42500c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId1; 42510c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId2; 42520c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 42530c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId1; 42540c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId2; 4255b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4256127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 42570c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 42584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[0] = String.valueOf(rawContactId1); 42594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[1] = String.valueOf(rawContactId2); 42600c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, 42614da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov AggregationExceptions.RAW_CONTACT_ID1 + "=? AND " 42624da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2); 42630c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 42646bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 42656bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 42660c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 42670c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 42680c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 42690c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues); 4270127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 4271127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 42725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().invalidateAggregationExceptionCache(); 42735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId1, 427469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 42755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId2, 427669cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 4277dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov 42785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateContact(mTransactionContext.get(), db, rawContactId1); 42795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateContact(mTransactionContext.get(), db, rawContactId2); 4280127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 4281127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 4282127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 4283127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 4284b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4285b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 428670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong public void onAccountsUpdated(Account[] accounts) { 4287bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 42883826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 42893826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4290bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected boolean updateAccountsInBackground(Account[] accounts) { 4291f8536aaa7a52b9a7a353bc54e158becdbe79ec87Bai Tao // TODO : Check the unit test. 4292e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov boolean accountsChanged = false; 42935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 42945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(db); 42955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.beginTransaction(); 429670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong try { 429743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> existingAccountsWithDataSets = 429843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro findValidAccountsWithDataSets(Tables.ACCOUNTS); 4299743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov 430043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add a row to the ACCOUNTS table (with no data set) for each new account. 4301743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov for (Account account : accounts) { 430243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = new AccountWithDataSet( 430343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro account.name, account.type, null); 430443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!existingAccountsWithDataSets.contains(accountWithDataSet)) { 4305e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 430643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 430743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add an account entry with an empty data set to match the account. 43085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 430943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ", " + RawContacts.ACCOUNT_TYPE + ", " + RawContacts.DATA_SET 431043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ") VALUES (?, ?, ?)", 431143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new String[] { 431243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 431343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 431443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 431543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }); 4316743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 4317743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov } 431848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 431943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Check each of the existing sub-accounts against the account list. If the owning 432043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // account no longer exists, the sub-account and all its data should be deleted. 432143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro List<AccountWithDataSet> accountsWithDataSetsToDelete = 432243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new ArrayList<AccountWithDataSet>(); 432343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro List<Account> accountList = Arrays.asList(accounts); 432443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : existingAccountsWithDataSets) { 432543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Account owningAccount = new Account( 432643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), accountWithDataSet.getAccountType()); 432743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!accountList.contains(owningAccount)) { 432843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsWithDataSetsToDelete.add(accountWithDataSet); 432943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 433070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 433170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong 433243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!accountsWithDataSetsToDelete.isEmpty()) { 4333e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov accountsChanged = true; 433443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : accountsWithDataSetsToDelete) { 433543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Log.d(TAG, "removing data for removed account " + accountWithDataSet); 433643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String[] accountParams = new String[] { 433743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 433843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType() 433943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }; 434043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String[] accountWithDataSetParams = accountWithDataSet.getDataSet() == null 434143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ? accountParams 434243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro : new String[] { 434343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 434443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 434543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 434643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }; 434743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String groupsDataSetClause = " AND " + Groups.DATA_SET 434843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + (accountWithDataSet.getDataSet() == null ? " IS NULL" : " = ?"); 434943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String rawContactsDataSetClause = " AND " + RawContacts.DATA_SET 435043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + (accountWithDataSet.getDataSet() == null ? " IS NULL" : " = ?"); 435143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 43525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4353e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.GROUPS + 4354e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Groups.ACCOUNT_NAME + " = ?" + 435543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Groups.ACCOUNT_TYPE + " = ?" + 435643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro groupsDataSetClause, accountWithDataSetParams); 43575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4358e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.PRESENCE + 4359e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" + 4360e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "SELECT " + RawContacts._ID + 4361e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 4362e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 436343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + " = ?" + 436443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause + ")", accountWithDataSetParams); 43655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4366e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.RAW_CONTACTS + 4367e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" + 436843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + " = ?" + 436943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause, accountWithDataSetParams); 43705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4371e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.SETTINGS + 4372e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + Settings.ACCOUNT_NAME + " = ?" + 437343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Settings.ACCOUNT_TYPE + " = ?", accountParams); 43745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4375e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov "DELETE FROM " + Tables.ACCOUNTS + 4376e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov " WHERE " + RawContacts.ACCOUNT_NAME + "=?" + 437743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + RawContacts.ACCOUNT_TYPE + "=?" + 437843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactsDataSetClause, accountWithDataSetParams); 43795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL( 4380d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov "DELETE FROM " + Tables.DIRECTORIES + 4381d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov " WHERE " + Directory.ACCOUNT_NAME + "=?" + 438243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND " + Directory.ACCOUNT_TYPE + "=?", accountParams); 43834458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov resetDirectoryCache(); 4384e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 4385e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov 438633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // Find all aggregated contacts that used to contain the raw contacts 438733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // we have just deleted and see if they are still referencing the deleted 4388e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov // names or photos. If so, fix up those contacts. 438933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov HashSet<Long> orphanContactIds = Sets.newHashSet(); 43905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = db.rawQuery("SELECT " + Contacts._ID + 439133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " FROM " + Tables.CONTACTS + 439233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " WHERE (" + Contacts.NAME_RAW_CONTACT_ID + " NOT NULL AND " + 439369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov Contacts.NAME_RAW_CONTACT_ID + " NOT IN " + 439469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + RawContacts._ID + 439569cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + "))" + 439633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " OR (" + Contacts.PHOTO_ID + " NOT NULL AND " + 439733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Contacts.PHOTO_ID + " NOT IN " + 439869cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + Data._ID + 439969cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.DATA + "))", null); 440033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov try { 440133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov while (cursor.moveToNext()) { 440233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov orphanContactIds.add(cursor.getLong(0)); 440333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 440433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } finally { 440533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov cursor.close(); 440633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 440733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 440833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov for (Long contactId : orphanContactIds) { 44095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateAggregateData(mTransactionContext.get(), contactId); 441033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 44115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().updateAllVisible(); 4412bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 441333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 441433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 441543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Now that we've done the account-based additions and subtractions from the Accounts 441643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // table, check for raw contacts that have been added with a data set and add Accounts 441743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // entries for those if necessary. 441843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro existingAccountsWithDataSets = findValidAccountsWithDataSets(Tables.ACCOUNTS); 441943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> rawContactAccountsWithDataSets = 442043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro findValidAccountsWithDataSets(Tables.RAW_CONTACTS); 442143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro rawContactAccountsWithDataSets.removeAll(existingAccountsWithDataSets); 442243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 442343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Any remaining raw contact sub-accounts need to be added to the Accounts table. 442443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : rawContactAccountsWithDataSets) { 442543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsChanged = true; 442643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 442743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // Add an account entry to match the raw contact. 44285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME 442943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ", " + RawContacts.ACCOUNT_TYPE + ", " + RawContacts.DATA_SET 443043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + ") VALUES (?, ?, ?)", 443143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new String[] { 443243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountName(), 443343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getAccountType(), 443443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountWithDataSet.getDataSet() 443543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro }); 443643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 443743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 4438e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov if (accountsChanged) { 443943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO: Should sync state take data set into consideration? 44405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getSyncState().onAccountsChanged(db, accounts); 4441e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 44425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.setTransactionSuccessful(); 444370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } finally { 44445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.endTransaction(); 444570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 444673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.clear(); 44473826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 44483826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (accountsChanged) { 44493826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateContactsAccountCount(accounts); 44503826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 44513826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 44523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 4453afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov return accountsChanged; 445470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 4455619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 44563826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateContactsAccountCount(Account[] accounts) { 44573826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov int count = 0; 44583826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov for (Account account : accounts) { 44593826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (isContactsAccount(account)) { 44603826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov count++; 44613826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 44623826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 44633826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mContactsAccountCount = count; 44643826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 44653826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 44663826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov protected boolean isContactsAccount(Account account) { 44673826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov final IContentService cs = ContentResolver.getContentService(); 44683826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov try { 44693826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0; 44703826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } catch (RemoteException e) { 44713826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov Log.e(TAG, "Cannot obtain sync flag for account: " + account, e); 44723826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return false; 44733826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 44743826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 44753826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 447672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void onPackageChanged(String packageName) { 4477bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_DIRECTORIES, packageName); 4478d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4479d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4480619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey /** 448143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Finds all distinct account types and data sets present in the specified table. 4482627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov */ 448343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private Set<AccountWithDataSet> findValidAccountsWithDataSets(String table) { 448443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Set<AccountWithDataSet> accountsWithDataSets = new HashSet<AccountWithDataSet>(); 44855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().rawQuery( 448643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro "SELECT DISTINCT " + RawContacts.ACCOUNT_NAME + "," + RawContacts.ACCOUNT_TYPE + 448743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro "," + RawContacts.DATA_SET + 448843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " FROM " + table, null); 4489627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 4490627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov while (c.moveToNext()) { 4491dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!c.isNull(0) || !c.isNull(1)) { 449243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountsWithDataSets.add( 449343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro new AccountWithDataSet(c.getString(0), c.getString(1), c.getString(2))); 4494627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4495627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4496627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } finally { 4497627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov c.close(); 4498627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 449943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro return accountsWithDataSets; 4500627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4501627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov 45024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 45034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 45044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 450515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 450615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mReadAccessLatch); 450715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 45085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Query the profile DB if appropriate. 45095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 45105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 45115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileProvider.query(uri, projection, selection, selectionArgs, sortOrder); 45125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 45135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 45145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Otherwise proceed with a normal query against the contacts DB. 45155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 45165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(mContactsHelper.getReadableDatabase()); 4517d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY); 4518385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directory == null) { 45193716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 45205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1)); 4521385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directory.equals("0")) { 45223716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 45233716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 45245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Directory.DEFAULT)); 4525d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } else if (directory.equals("1")) { 45263716f1447ceb21180d1301790eabd8b9453f486dDave Santoro return wrapCursor(uri, 45273716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 45285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Directory.LOCAL_INVISIBLE)); 4529d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4530d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4531d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov DirectoryInfo directoryInfo = getDirectoryAuthority(directory); 4532d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo == null) { 4533a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov Log.e(TAG, "Invalid directory ID: " + uri); 4534a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov return null; 4535d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4536d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4537d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Builder builder = new Uri.Builder(); 4538d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.scheme(ContentResolver.SCHEME_CONTENT); 4539d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.authority(directoryInfo.authority); 4540d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.encodedPath(uri.getEncodedPath()); 4541d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountName != null) { 4542d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName); 4543d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4544d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountType != null) { 4545d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType); 4546d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 45472e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 45482e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limit = getLimit(uri); 45492e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov if (limit != null) { 45502e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit); 45512e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov } 45522e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 4553d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Uri directoryUri = builder.build(); 455409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 455509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov if (projection == null) { 455609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov projection = getDefaultProjection(uri); 455709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 455809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 4559332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov Cursor cursor = getContext().getContentResolver().query(directoryUri, projection, selection, 4560d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov selectionArgs, sortOrder); 45616ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 45626ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (cursor == null) { 45636ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 45646ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 45656ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 4566547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro CrossProcessCursor crossProcessCursor = getCrossProcessCursor(cursor); 4567547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (crossProcessCursor != null) { 4568547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return wrapCursor(uri, cursor); 4569547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } else { 4570547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro return matrixCursorFromCursor(wrapCursor(uri, cursor)); 4571547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 45723716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 45733716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4574547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro private Cursor wrapCursor(Uri uri, Cursor cursor) { 4575547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 4576547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro // If the cursor doesn't contain a snippet column, don't bother wrapping it. 4577547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (cursor.getColumnIndex(SearchSnippetColumns.SNIPPET) < 0) { 45785517770250b3afa4fd88b6869c3244680821d222Dave Santoro if (VERBOSE_LOGGING) { 45795517770250b3afa4fd88b6869c3244680821d222Dave Santoro return new InstrumentedCursorWrapper(cursor, uri, TAG); 45805517770250b3afa4fd88b6869c3244680821d222Dave Santoro } else { 45815517770250b3afa4fd88b6869c3244680821d222Dave Santoro return cursor; 45825517770250b3afa4fd88b6869c3244680821d222Dave Santoro } 4583547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 4584547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 45853716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Parse out snippet arguments for use when snippets are retrieved from the cursor. 45863716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String[] args = null; 45873716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String snippetArgs = 45883716f1447ceb21180d1301790eabd8b9453f486dDave Santoro getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 45893716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (snippetArgs != null) { 45903716f1447ceb21180d1301790eabd8b9453f486dDave Santoro args = snippetArgs.split(","); 45913716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 45923716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 45933716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String query = uri.getLastPathSegment(); 45943716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String startMatch = args != null && args.length > 0 ? args[0] 45953716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_START_MATCH; 45963716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String endMatch = args != null && args.length > 1 ? args[1] 45973716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_END_MATCH; 45983716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String ellipsis = args != null && args.length > 2 ? args[2] 45993716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_ELLIPSIS; 46003716f1447ceb21180d1301790eabd8b9453f486dDave Santoro int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 46013716f1447ceb21180d1301790eabd8b9453f486dDave Santoro : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 46023716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 46035517770250b3afa4fd88b6869c3244680821d222Dave Santoro if (VERBOSE_LOGGING) { 46045517770250b3afa4fd88b6869c3244680821d222Dave Santoro return new InstrumentedCursorWrapper(new SnippetizingCursorWrapper( 46055517770250b3afa4fd88b6869c3244680821d222Dave Santoro cursor, query, startMatch, endMatch, ellipsis, maxTokens), uri, TAG); 46065517770250b3afa4fd88b6869c3244680821d222Dave Santoro } else { 46075517770250b3afa4fd88b6869c3244680821d222Dave Santoro return new SnippetizingCursorWrapper(cursor, query, startMatch, endMatch, ellipsis, 46085517770250b3afa4fd88b6869c3244680821d222Dave Santoro maxTokens); 46095517770250b3afa4fd88b6869c3244680821d222Dave Santoro } 46106ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 46116ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 46126ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov private CrossProcessCursor getCrossProcessCursor(Cursor cursor) { 46136ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov Cursor c = cursor; 46146ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (c instanceof CrossProcessCursor) { 46156ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return (CrossProcessCursor) c; 46166ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else if (c instanceof CursorWindow) { 46176ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return getCrossProcessCursor(((CursorWrapper) c).getWrappedCursor()); 46186ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } else { 46196ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 46206ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 46216ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 46226ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 46236ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov public MatrixCursor matrixCursorFromCursor(Cursor cursor) { 46246ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); 46256ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov int numColumns = cursor.getColumnCount(); 46266ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov String data[] = new String[numColumns]; 46276ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov cursor.moveToPosition(-1); 46286ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov while (cursor.moveToNext()) { 46296ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov for (int i = 0; i < numColumns; i++) { 46306ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov data[i] = cursor.getString(i); 46316ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 46326ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov newCursor.addRow(data); 4633332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov } 46346ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return newCursor; 4635d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4636d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4637d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final class DirectoryQuery { 4638d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final String[] COLUMNS = new String[] { 4639d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory._ID, 4640d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.DIRECTORY_AUTHORITY, 4641d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_NAME, 4642d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_TYPE 4643d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov }; 4644d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4645d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int DIRECTORY_ID = 0; 4646d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int AUTHORITY = 1; 4647d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_NAME = 2; 4648d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_TYPE = 3; 4649d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4650d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4651d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 4652d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Reads and caches directory information for the database. 4653d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 4654d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private DirectoryInfo getDirectoryAuthority(String directoryId) { 46554458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized (mDirectoryCache) { 46564458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov if (!mDirectoryCacheValid) { 46574458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.clear(); 46585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mDbHelper.get().getReadableDatabase(); 465949d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Cursor cursor = db.query(Tables.DIRECTORIES, 46604458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryQuery.COLUMNS, 46614458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov null, null, null, null, null); 46624458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov try { 46634458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov while (cursor.moveToNext()) { 46644458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryInfo info = new DirectoryInfo(); 46654458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov String id = cursor.getString(DirectoryQuery.DIRECTORY_ID); 46664458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.authority = cursor.getString(DirectoryQuery.AUTHORITY); 46674458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME); 46684458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE); 46694458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.put(id, info); 46704458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 46714458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } finally { 46724458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov cursor.close(); 4673d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 46744458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = true; 4675d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4676d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 46774458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov return mDirectoryCache.get(directoryId); 46784458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 4679d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4680d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 468172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void resetDirectoryCache() { 46824458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized(mDirectoryCache) { 46834458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = false; 46844458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 468572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 468672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 46875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro protected Cursor queryLocal(Uri uri, String[] projection, String selection, 46885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String[] selectionArgs, String sortOrder, long directoryId) { 4689bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 4690bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov Log.v(TAG, "query: " + uri); 4691bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov } 46920b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov 46935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 46945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 46955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(mDb); 46965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 469735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4698d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 46991f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 4700c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov String limit = getLimit(uri); 4701c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 4702a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 47034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 470435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 47055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 47065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().query(mActiveDb.get(), projection, selection, 47075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs, sortOrder); 470835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4709d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 4710763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 47114b64b6e8f448938434cb1e022a4e7dfaae8f9c8cMakoto Onuki appendLocalDirectorySelectionIfNeeded(qb, directoryId); 4712619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 4713619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 4714619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 4715d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 47164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 4717763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 47184da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 47194da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 47206bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 47216bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 47226bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 47235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP: 47245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP_ID: { 47255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 47265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = pathSegments.size(); 47275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount < 3) { 47285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 4729fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 47305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 4731a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 47325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String lookupKey = pathSegments.get(2); 47335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount == 4) { 47345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 47355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4736763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 4737a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 47385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 4739a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4740a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 4741a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 47425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return c; 47435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 47445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 47455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 4746763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 47474da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 47485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String.valueOf(lookupContactIdByLookupKey(mActiveDb.get(), lookupKey))); 47494da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 47505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 47515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 47525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 47532149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_DATA: 47542149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_ID_DATA: { 47552149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 47562149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov int segmentCount = pathSegments.size(); 47572149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount < 4) { 47585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 47592149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov "Missing a lookup key", uri)); 47602149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 47612149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov String lookupKey = pathSegments.get(2); 47622149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount == 5) { 47632149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 47642149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 47652149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(lookupQb, uri, projection, false); 4766a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 47675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 4768a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 4769a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Data.CONTACT_ID, contactId, Data.LOOKUP_KEY, lookupKey); 4770a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 47712149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov return c; 47722149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 47732149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 47742149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov // TODO see if the contact exists but has no data rows (rare) 47752149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 47762149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 47772149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 47785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 47792149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 478024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 47812149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov qb.appendWhere(" AND " + Data.CONTACT_ID + "=?"); 47822149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov break; 47832149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 47842149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 47853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_ID_STREAM_ITEMS: { 47863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(uri.getPathSegments().get(1)); 47873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 47883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 4789af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann qb.appendWhere(StreamItems.CONTACT_ID + "=?"); 47903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 47913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 47923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 47933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_STREAM_ITEMS: 47943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_ID_STREAM_ITEMS: { 47953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<String> pathSegments = uri.getPathSegments(); 47963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int segmentCount = pathSegments.size(); 47973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount < 4) { 47985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 47993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann "Missing a lookup key", uri)); 48003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String lookupKey = pathSegments.get(2); 48023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount == 5) { 48033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(pathSegments.get(3)); 48043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 48053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(lookupQb); 48065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 48073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann projection, selection, selectionArgs, sortOrder, groupBy, limit, 4808af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann StreamItems.CONTACT_ID, contactId, 4809af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann StreamItems.CONTACT_LOOKUP_KEY, lookupKey); 48103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c != null) { 48113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return c; 48123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 48153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 48165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 48173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 48183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContacts.CONTACT_ID + "=?"); 48193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 48203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 48213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 4822f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: { 482342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKey = Uri.encode(uri.getPathSegments().get(2)); 48245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 4825ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 4826f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey qb.setProjectionMap(sContactsVCardProjectionMap); 48274da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 482824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 48294da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 4830f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey break; 4831f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey } 4832f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey 483342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 483442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); 483542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann String currentDateString = dateFormat.format(new Date()).toString(); 48365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().rawQuery( 483742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann "SELECT" + 483842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " 'vcards_' || ? || '.vcf' AS " + OpenableColumns.DISPLAY_NAME + "," + 483942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " NULL AS " + OpenableColumns.SIZE, 484042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann new String[] { currentDateString }); 484142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 484242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 4843ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_FILTER: { 4844916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov String filterParam = ""; 4845ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 4846916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov filterParam = uri.getLastPathSegment(); 4847ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 48487ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov setTablesAndProjectionMapForContactsWithSnippet( 48497ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov qb, uri, projection, filterParam, directoryId); 4850ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 4851ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 4852ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 4853ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT_FILTER: 4854ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT: { 48552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Basically the resultant SQL should look like this: 48562f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing starred items) 48572f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 48582f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing frequently contacted items) 48592f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // ORDER BY ... 48602f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 48612f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final boolean phoneOnly = readBooleanQueryParameter( 48622f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa uri, ContactsContract.STREQUENT_PHONE_ONLY, false); 48632f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (match == CONTACTS_STREQUENT_FILTER && uri.getPathSegments().size() > 3) { 48644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 48654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 4866e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(Contacts._ID + " IN "); 48675e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov appendContactFilterAsNestedQuery(sb, filterParam); 48682f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection = DbQueryUtils.concatenateClauses(selection, sb.toString()); 48694a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 48704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 48712f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] subProjection = null; 48725e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection != null) { 48732f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa subProjection = appendProjectionArg(projection, TIMES_USED_SORT_COLUMN); 48745e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 48755e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 48764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov // Build the first query for starred 48774928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 48784928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(phoneOnly ? 48794928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa sStrequentPhoneOnlyStarredProjectionMap 48804928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa : sStrequentStarredProjectionMap); 48819dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa if (phoneOnly) { 48825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(DbQueryUtils.concatenateClauses( 48835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection, Contacts.HAS_PHONE_NUMBER + "=1")); 48849dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa } 48852f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 48862f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String starredQuery = qb.buildQuery(subProjection, 488724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Contacts.STARRED + "=1", Contacts._ID, null, null, null); 4888d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 48892f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Reset the builder. 4890d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 48912f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 48924928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 48934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // Build the second query for frequent part. 48944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final String frequentQuery; 48954928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (phoneOnly) { 48964928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final StringBuilder tableBuilder = new StringBuilder(); 48974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // In phone only mode, we need to look at view_data instead of 48984928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // contacts/raw_contacts to obtain actual phone numbers. One problem is that 48994928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data is much larger than view_contacts, so our query might become much 49004928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // slower. 49014928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // 49024928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // To avoid the possible slow down, we start from data usage table and join 49034928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data to the table, assuming data usage table is quite smaller than 49044928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // data rows (almost always it should be), and we don't want any phone 49054928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // numbers not used by the user. This way sqlite is able to drop a number of 49064928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // rows in view_data in the early stage of data lookup. 49074928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa tableBuilder.append(Tables.DATA_USAGE_STAT 49084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " INNER JOIN " + Views.DATA + " " + Tables.DATA 49094928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" 49104928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataColumns.CONCRETE_ID + " AND " 49114928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" 49124928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT_CALL + ")"); 49134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactPresenceJoin(tableBuilder, projection, RawContacts.CONTACT_ID); 49144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactStatusUpdateJoin(tableBuilder, projection, 49154928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa ContactsColumns.LAST_STATUS_UPDATE_ID); 49164928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 49174928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setTables(tableBuilder.toString()); 49184928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentPhoneOnlyFrequentProjectionMap); 49194928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 49204928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 49214928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa Contacts.STARRED + "=0 OR " + Contacts.STARRED + " IS NULL", 49224928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa MimetypesColumns.MIMETYPE + " IN (" 49234928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + Phone.CONTENT_ITEM_TYPE + "', " 49244928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + "'" + SipAddress.CONTENT_ITEM_TYPE + "')")); 49254928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, null, null, null, null, null); 49264928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } else { 49274928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 49284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 49294928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 49304928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 49315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "(" + Contacts.STARRED + " =0 OR " + Contacts.STARRED + " IS NULL)")); 49324928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa frequentQuery = qb.buildQuery(subProjection, 49334928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa null, Contacts._ID, null, null, null); 49344928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } 4935d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 4936d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 49372f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String unionQuery = 49382f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, 49392f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa STREQUENT_ORDER_BY, STREQUENT_LIMIT); 49402f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 49412f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Here, we need to use selection / selectionArgs (supplied from users) "twice", 49422f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // as we want them both for starred items and for frequently contacted items. 49432f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // 49442f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // e.g. if the user specify selection = "starred =?" and selectionArgs = "0", 49452f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // the resultant SQL should be like: 49462f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 49472f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 49482f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 49492f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] doubledSelectionArgs = null; 49502f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (selectionArgs != null) { 49512f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final int length = selectionArgs.length; 49522f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa doubledSelectionArgs = new String[length * 2]; 49537d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, 0, length); 49547d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, length, length); 49552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 49562f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 49575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().rawQuery(unionQuery, doubledSelectionArgs); 49582f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (cursor != null) { 49592f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa cursor.setNotificationUri(getContext().getContentResolver(), 4960d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 4961d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 49622f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa return cursor; 4963d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 4964d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 496545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa case CONTACTS_FREQUENT: { 496645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 496745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 496845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa groupBy = Contacts._ID; 496945ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa if (!TextUtils.isEmpty(sortOrder)) { 497045ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY + ", " + sortOrder; 497145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } else { 497245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY; 497345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 497445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa break; 497545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 497645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 4977ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_GROUP: { 4978763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 4979b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 498071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 49814a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 4982b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4983b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 4984b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 4985b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 498624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 498724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 498824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 498924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 499024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 499124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: { 499224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForEntities(qb, uri, projection); 499324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 499424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 499524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 499624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: { 499724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 499824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 499924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 500024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 500124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA_ID: { 500224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 500324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 50045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(" AND " + Data._ID + "=?"); 500524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 500624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 500724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 500824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: { 5009ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 501024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.setProjectionMap(sContactsVCardProjectionMap); 501124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 501224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 501324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5014a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_DATA: { 50154a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 501682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50174da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 50184da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 50196bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 50206bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 502100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 5022a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 50233653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 502482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 50254da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 50264da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 50273653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 50283653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov break; 50293653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov } 50303653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 5031a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_ENTITIES: { 5032a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 5033a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 5034a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 5035a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 5036a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 5037a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5038a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5039a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ENTITIES: 5040a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ID_ENTITIES: { 5041a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 5042a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov int segmentCount = pathSegments.size(); 5043a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount < 4) { 50445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 5045a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov "Missing a lookup key", uri)); 5046a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5047a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lookupKey = pathSegments.get(2); 5048a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount == 5) { 5049a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 5050a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 5051a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(lookupQb, uri, projection); 5052a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 5053a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 50545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 5055a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 5056a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.CONTACT_ID, contactId, 5057a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.LOOKUP_KEY, lookupKey); 5058a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 5059a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5060a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5061a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5062a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5063a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 5064a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 50655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String.valueOf(lookupContactIdByLookupKey(mActiveDb.get(), lookupKey))); 5066a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + Contacts.Entity.CONTACT_ID + "=?"); 5067a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 5068a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5069a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 50703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 50713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 50723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 50733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 50743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 50753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 50763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 50773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 50789b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann qb.appendWhere(StreamItems._ID + "=?"); 50793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 50803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 50813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 50823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_LIMIT: { 50836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro MatrixCursor cursor = new MatrixCursor(new String[]{StreamItems.MAX_ITEMS}, 1); 50846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro cursor.addRow(new Object[]{MAX_STREAM_ITEMS_PER_RAW_CONTACT}); 50853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return cursor; 50863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 50873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 50883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 50893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 50903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 50913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 50923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 50933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 50943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 50953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 50963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 50973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?"); 50983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 50993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 51003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 51013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 51023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 51033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 51043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 51053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemPhotoId); 51063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 51073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=? AND " + 51083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=?"); 51093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 51103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 51113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 5112f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case PHOTO_DIMENSIONS: { 5113f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro MatrixCursor cursor = new MatrixCursor( 5114f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM}, 5115f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1); 5116f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cursor.addRow(new Object[]{mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim}); 5117f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return cursor; 5118f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 5119f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 51204a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case PHONES: { 512182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 512289c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 5123cf55cbe8932f620484a3634d13ecc116c32fdc99Daisuke Miyakawa groupBy = RawContacts.CONTACT_ID + ", " + Data.DATA1; 51242815f58f72f109790585931f601a63ddc02536a5Evan Millar break; 51252815f58f72f109790585931f601a63ddc02536a5Evan Millar } 51262815f58f72f109790585931f601a63ddc02536a5Evan Millar 512748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: { 512882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 51294da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 513048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 51314da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 513248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 513348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 513448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 5135ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case PHONES_FILTER: { 513646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 513746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 513846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 513946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_CALL; 514046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 514146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 514289c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'"); 5143ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 51444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 51454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5146a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(" AND ("); 51475e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 514845d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov boolean hasCondition = false; 51495e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov boolean orNeeded = false; 51505e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov String normalizedName = NameNormalizer.normalize(filterParam); 51515e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (normalizedName.length() > 0) { 5152155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(Data.RAW_CONTACT_ID + " IN " + 5153155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 5154155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 5155155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 5156155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 5157155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 5158155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 51592352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 5160155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 51615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov orNeeded = true; 516245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 51635e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 51645e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 5165892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String number = PhoneNumberUtils.normalizeNumber(filterParam); 5166892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (!TextUtils.isEmpty(number)) { 51675e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov if (orNeeded) { 51685e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(" OR "); 51695e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 51705e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(Data._ID + 5171892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID 5172892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " FROM " + Tables.PHONE_LOOKUP 5173892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 5174892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append(number); 5175892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append("%')"); 517645d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 517745d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov } 517845d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov 517945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov if (!hasCondition) { 518045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // If it is neither a phone number nor a name, the query should return 518145d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // an empty cursor. Let's ensure that. 518245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov sb.append("0"); 51835e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 51845e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 5185a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 5186ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 518758567abca253f1efa2db5c39e17e42dca589e916Daisuke Miyakawa groupBy = "(CASE WHEN " + PhoneColumns.NORMALIZED_NUMBER 518858567abca253f1efa2db5c39e17e42dca589e916Daisuke Miyakawa + " IS NOT NULL THEN " + PhoneColumns.NORMALIZED_NUMBER 518958567abca253f1efa2db5c39e17e42dca589e916Daisuke Miyakawa + " ELSE " + Phone.NUMBER + " END), " + RawContacts.CONTACT_ID; 5190a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 519146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 519246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 519346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + PHONE_FILTER_SORT_ORDER; 519446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 519546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = PHONE_FILTER_SORT_ORDER; 519646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 5197a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 5198ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5199ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5200ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 52014a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case EMAILS: { 520282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 520389c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 52044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov break; 52054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 52064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 520748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: { 520882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 52094da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 52104da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'" 52114da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + " AND " + Data._ID + "=?"); 521248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 521348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 521448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 52155e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_LOOKUP: { 521682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 521789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"); 52184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov if (uri.getPathSegments().size() > 2) { 521908768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String email = uri.getLastPathSegment(); 52205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String address = mDbHelper.get().extractAddressFromEmailAddress(email); 522108768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, address); 522208768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)"); 52234a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 5224ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5225ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5226ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 52275e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_FILTER: { 522846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 522946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Integer typeInt = sDataUsageTypeMap.get(typeParam); 523046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (typeInt == null) { 523146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa typeInt = DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT; 523246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 523346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 523407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov String filterParam = null; 52357d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa 523607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 523707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = uri.getLastPathSegment(); 523807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (TextUtils.isEmpty(filterParam)) { 523907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = null; 524007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 524107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 52425e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 524307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (filterParam == null) { 524407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov // If the filter is unspecified, return nothing 524507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov qb.appendWhere(" AND 0"); 524607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } else { 524707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov StringBuilder sb = new StringBuilder(); 524807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append(" AND " + Data._ID + " IN ("); 524907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append( 525007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov "SELECT " + Data._ID + 525107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov " FROM " + Tables.DATA + 52522a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov " WHERE " + DataColumns.MIMETYPE_ID + "="); 52535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro sb.append(mDbHelper.get().getMimeTypeIdForEmail()); 52542a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(" AND " + Data.DATA1 + " LIKE "); 525507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 525620938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov if (!filterParam.contains("@")) { 5257155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append( 5258155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " UNION SELECT " + Data._ID + 5259155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.DATA + 5260155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE +" + DataColumns.MIMETYPE_ID + "="); 52615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro sb.append(mDbHelper.get().getMimeTypeIdForEmail()); 5262155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(" AND " + Data.RAW_CONTACT_ID + " IN " + 5263155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 5264155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 5265155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 5266155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 5267155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 5268155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE " + SearchIndexColumns.NAME + " MATCH "); 52692352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filterParam) + "*"); 5270155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(")"); 52715e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 52725e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 5273a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 52745e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 52755e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = Email.DATA + "," + RawContacts.CONTACT_ID; 5276a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 527746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 527846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 527946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + EMAIL_FILTER_SORT_ORDER; 52807d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } else { 52817d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa sortOrder = EMAIL_FILTER_SORT_ORDER; 52827d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } 5283a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 52845e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov break; 52855e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 52865e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 5287ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 528882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 528989c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 529089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 5291ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5292ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5293ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 529448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 529582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 52964da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 529748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov qb.appendWhere(" AND " + Data.MIMETYPE + " = '" 529848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov + StructuredPostal.CONTENT_ITEM_TYPE + "'"); 52994da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 530048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 530148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 530248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 53035ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS: { 5304763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 53054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 53064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 53074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 53085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 53095ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 5310763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 53114da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 53124da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 53134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 53144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 53154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 53165ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_DATA: { 53175ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 531882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 53194da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 53204da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?"); 532124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 532224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 532324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 53243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 53253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 53263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 53273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 53283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=?"); 53293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 53303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 533124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 533224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: { 533324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 533424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 533524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 533624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 533724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: { 533824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = ContentUris.parseId(uri); 533924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 534024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawContacts(qb, uri); 53415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(" AND " + RawContacts._ID + "=?"); 534224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 534324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 534424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 534524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 534624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 534724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 534824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 53495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?"); 535024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 535124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 535224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 535324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_ENTITIES: { 535424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 535524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 535624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawEntities(qb, uri); 53575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(" AND " + RawContacts._ID + "=?"); 5358e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5359e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5360e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 5361e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey case DATA: { 536282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 5363e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5364e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5365e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 53664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton case DATA_ID: { 536724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = ContentUris.parseId(uri); 536882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 53694da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 53704da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 5371a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov break; 5372a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov } 5373a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov 5374a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 53754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 5376a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton if (TextUtils.isEmpty(sortOrder)) { 5377a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // Default the sort order to something reasonable so we get consistent 5378a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton // results when callers don't request an ordering 5379892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sortOrder = " length(lookup.normalized_number) DESC"; 5380a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5381a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5382e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : ""; 5383e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov String numberE164 = PhoneNumberUtils.formatNumberToE164(number, 53845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getCurrentCountryIso()); 5385892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String normalizedNumber = 5386892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov PhoneNumberUtils.normalizeNumber(number); 53875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().buildPhoneLookupAndContactQuery(qb, normalizedNumber, numberE164); 5388e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov qb.setProjectionMap(sPhoneLookupProjectionMap); 5389e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov // Phone lookup cannot be combined with a selection 5390e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selection = null; 5391e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selectionArgs = null; 5392a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 5393a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5394a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5395ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 5396ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5397ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 539843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 5399ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5400ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5401ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5402ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 5403ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5404ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 54054da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 54064da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Groups._ID + "=?"); 5407ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5408ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5409ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5410ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 5411f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa final boolean returnGroupCountPerAccount = 5412f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa readBooleanQueryParameter(uri, Groups.PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT, 5413f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa false); 5414f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa qb.setTables(Views.GROUPS + " AS " + Tables.GROUPS); 5415f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa qb.setProjectionMap(returnGroupCountPerAccount ? 5416f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa sGroupsSummaryProjectionMapWithGroupCountPerAccount 5417f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa : sGroupsSummaryProjectionMap); 541843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 5419f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa groupBy = GroupsColumns.CONCRETE_ID; 5420ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5421ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5422ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5423b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 54240c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS); 5425b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 5426b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 5427b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 5428b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 542931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 5430d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 54312d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov String filter = null; 54322d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 54332d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov filter = uri.getPathSegments().get(3); 54342d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov } 543531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 5436d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov if (limit != null) { 5437d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov maxSuggestions = Integer.parseInt(limit); 543831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 543931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 544031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 544131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 54425b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ArrayList<AggregationSuggestionParameter> parameters = null; 54435b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov List<String> query = uri.getQueryParameters("query"); 54445b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov if (query != null && !query.isEmpty()) { 54455b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters = new ArrayList<AggregationSuggestionParameter>(query.size()); 54465b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov for (String parameter : query) { 54475b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov int offset = parameter.indexOf(':'); 54485b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters.add(offset == -1 54495b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ? new AggregationSuggestionParameter( 545076dfa406e2cde19c824983c37fc92c1c5bf63eecDaniel Lehmann AggregationSuggestions.PARAMETER_MATCH_NAME, 54515b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter) 54525b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov : new AggregationSuggestionParameter( 54535b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(0, offset), 54545b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(offset + 1))); 54555b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 54565b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 54575b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 5458763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 54597581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov 54605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mAggregator.get().queryAggregationSuggestions(qb, projection, contactId, 54615b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov maxSuggestions, filter, parameters); 546231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 546331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 5464eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 5465eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setTables(Tables.SETTINGS); 5466eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setProjectionMap(sSettingsProjectionMap); 546743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, false); 5468e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5469e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // When requesting specific columns, this query requires 5470e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // late-binding of the GroupMembership MIME-type. 54715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final String groupMembershipMimetypeId = Long.toString(mDbHelper.get() 5472e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 547382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 54745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().isInProjection(projection, Settings.UNGROUPED_COUNT)) { 5475e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5476e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 547782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 54785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().isInProjection( 54795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro projection, Settings.UNGROUPED_WITH_PHONES)) { 5480e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5481e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 5482e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5483eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 5484eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 5485eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 54865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 54875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 54880a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 54895ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 54905ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 54915ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 549282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES_ID: { 54930a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 54944da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 54954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(DataColumns.CONCRETE_ID + "=?"); 54965ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 54975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 54985ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 5499c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: { 5500174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchSuggestionsQuery( 55015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get(), uri, projection, limit); 5502c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5503c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 5504c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: { 55052d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill String lookupKey = uri.getLastPathSegment(); 5506174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String filter = getQueryParameter( 5507174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov uri, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 5508174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchShortcutRefresh( 55095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get(), projection, lookupKey, filter); 5510c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5511c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 55121b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS: 5513ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 55141b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 55151b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 55161b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 55171b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_WITH_PHONES: 5518ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 55191b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 55201b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1"); 55211b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 55221b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 55231b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_FAVORITES: 5524ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 55251b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 55261b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.appendWhere(Contacts.STARRED + "=1"); 55271b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 55281b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 55291b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov case LIVE_FOLDERS_CONTACTS_GROUP_NAME: 5530ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 55311b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov qb.setProjectionMap(sLiveFoldersProjectionMap); 553271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 55331b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 55341b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov break; 55351b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov 553646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITIES: { 5537a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 553846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 553946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 554046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 554146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana case RAW_CONTACT_ENTITY_ID: { 554246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5543a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 55444da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 55454da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 554646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 554746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 554846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 554909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov case PROVIDER_STATUS: { 555009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return queryProviderStatus(uri, projection); 555109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 555209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5553d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES : { 5554d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5555d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5556d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5557d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5558d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 5559d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID : { 5560385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov long id = ContentUris.parseId(uri); 5561d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5562d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5563385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(id)); 5564d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.appendWhere(Directory._ID + "=?"); 5565d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5566d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5567d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 55687a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov case COMPLETE_NAME: { 55697a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return completeName(uri, projection); 55707a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 55717a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 55724f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 5573f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 5574c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov sortOrder, limit); 55754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 55764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 557709e69522745551522c55dff27424496f255def46Daniel Lehmann qb.setStrict(true); 55787f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov 5579ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov Cursor cursor = 55805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro query(mActiveDb.get(), qb, projection, selection, selectionArgs, sortOrder, groupBy, 55815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro limit); 5582ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) { 55835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro cursor = bundleLetterCountExtras(cursor, mActiveDb.get(), qb, selection, 55845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs, sortOrder); 5585ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5586ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov return cursor; 55875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 55885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 55895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection, 55905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String selection, String[] selectionArgs, String sortOrder, String groupBy, 55915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String limit) { 5592038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana if (projection != null && projection.length == 1 5593038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana && BaseColumns._COUNT.equals(projection[0])) { 5594038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana qb.setProjectionMap(sCountProjectionMap); 5595038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana } 55965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null, 55975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sortOrder, limit); 55984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 55994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 56004f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 56014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 56024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 56034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 560409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov /** 560509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov * Creates a single-row cursor containing the current status of the provider. 560609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov */ 560709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private Cursor queryProviderStatus(Uri uri, String[] projection) { 560809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 560909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov RowBuilder row = cursor.newRow(); 561009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov for (int i = 0; i < projection.length; i++) { 561109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov if (ProviderStatus.STATUS.equals(projection[i])) { 561209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mProviderStatus); 561309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } else if (ProviderStatus.DATA1.equals(projection[i])) { 561409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov row.add(mEstimatedStorageRequirement); 561509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 561609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 561709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov return cursor; 561809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 561909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5620a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** 5621a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * Runs the query with the supplied contact ID and lookup ID. If the query succeeds, 5622a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * it returns the resulting cursor, otherwise it returns null and the calling 5623a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * method needs to resolve the lookup key and rerun the query. 5624a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov */ 5625a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private Cursor queryWithContactIdAndLookupKey(SQLiteQueryBuilder lookupQb, 5626a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteDatabase db, Uri uri, 5627a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection, String selection, String[] selectionArgs, 5628a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String sortOrder, String groupBy, String limit, 5629a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn, long contactId, String lookupKeyColumn, String lookupKey) { 5630a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] args; 5631a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (selectionArgs == null) { 5632a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[2]; 5633a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } else { 5634a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[selectionArgs.length + 2]; 5635a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 5636a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5637a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[0] = String.valueOf(contactId); 5638a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[1] = Uri.encode(lookupKey); 5639a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(contactIdColumn + "=? AND " + lookupKeyColumn + "=?"); 5640a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = query(db, lookupQb, projection, selection, args, sortOrder, 5641a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov groupBy, limit); 5642a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c.getCount() != 0) { 5643a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5644a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5645a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5646a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov c.close(); 5647a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return null; 5648a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 564909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5650bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov private static final class AddressBookIndexQuery { 5651bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String LETTER = "letter"; 5652bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String TITLE = "title"; 5653bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String COUNT = "count"; 5654ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5655bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String[] COLUMNS = new String[] { 5656bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov LETTER, TITLE, COUNT 5657ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov }; 5658ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5659bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_LETTER = 0; 5660bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_TITLE = 1; 5661bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_COUNT = 2; 5662bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 56635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // The first letter of the sort key column is what is used for the index headings. 56645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public static final String SECTION_HEADING = "SUBSTR(%1$s,1,1)"; 566524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5666de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa public static final String ORDER_BY = LETTER + " COLLATE " + PHONEBOOK_COLLATOR_NAME; 5667ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5668ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5669ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov /** 5670ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * Computes counts by the address book index titles and adds the resulting tally 5671ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov * to the returned cursor as a bundle of extras. 5672ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov */ 5673ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov private Cursor bundleLetterCountExtras(Cursor cursor, final SQLiteDatabase db, 5674ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov SQLiteQueryBuilder qb, String selection, String[] selectionArgs, String sortOrder) { 5675ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortKey; 5676ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5677ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // The sort order suffix could be something like "DESC". 5678ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // We want to preserve it in the query even though we will change 5679ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // the sort column itself. 5680ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortOrderSuffix = ""; 5681ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (sortOrder != null) { 5682ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int spaceIndex = sortOrder.indexOf(' '); 5683ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (spaceIndex != -1) { 5684ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder.substring(0, spaceIndex); 5685ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortOrderSuffix = sortOrder.substring(spaceIndex); 5686ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5687ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder; 5688ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5689ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 5690ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = Contacts.SORT_KEY_PRIMARY; 5691ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5692ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5693bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String locale = getLocale().toString(); 5694ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov HashMap<String, String> projectionMap = Maps.newHashMap(); 56955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String sectionHeading = String.format(AddressBookIndexQuery.SECTION_HEADING, sortKey); 5696bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov projectionMap.put(AddressBookIndexQuery.LETTER, 569724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sectionHeading + " AS " + AddressBookIndexQuery.LETTER); 5698bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5699bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov /** 5700bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * Use the GET_PHONEBOOK_INDEX function, which is an android extension for SQLite3, 5701bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * to map the first letter of the sort key to a character that is traditionally 5702bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * used in phonebooks to represent that letter. For example, in Korean it will 5703bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * be the first consonant in the letter; for Japanese it will be Hiragana rather 5704bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * than Katakana. 5705bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov */ 5706ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.TITLE, 570724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "GET_PHONEBOOK_INDEX(" + sectionHeading + ",'" + locale + "')" 5708bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov + " AS " + AddressBookIndexQuery.TITLE); 5709ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.COUNT, 5710ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov "COUNT(" + Contacts._ID + ") AS " + AddressBookIndexQuery.COUNT); 5711ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov qb.setProjectionMap(projectionMap); 5712ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5713f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs, 5714ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY, null /* having */, 5715ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY + sortOrderSuffix); 5716ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5717ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov try { 5718f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov int groupCount = indexCursor.getCount(); 5719ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String titles[] = new String[groupCount]; 5720ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int counts[] = new int[groupCount]; 5721bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int indexCount = 0; 5722bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String currentTitle = null; 5723bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5724bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // Since GET_PHONEBOOK_INDEX is a many-to-1 function, we may end up 5725bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // with multiple entries for the same title. The following code 5726bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // collapses those duplicates. 5727ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov for (int i = 0; i < groupCount; i++) { 5728f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.moveToNext(); 5729bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String title = indexCursor.getString(AddressBookIndexQuery.COLUMN_TITLE); 5730bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int count = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT); 5731bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount == 0 || !TextUtils.equals(title, currentTitle)) { 5732bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles[indexCount] = currentTitle = title; 5733bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount] = count; 5734bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov indexCount++; 5735bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } else { 5736bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount - 1] += count; 5737bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5738bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 5739bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5740bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount < groupCount) { 5741bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String[] newTitles = new String[indexCount]; 5742bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(titles, 0, newTitles, 0, indexCount); 5743bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles = newTitles; 5744bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 5745bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int[] newCounts = new int[indexCount]; 5746bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(counts, 0, newCounts, 0, indexCount); 5747bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts = newCounts; 5748ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5749ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 5750e2adda196b19047bc5243d2bffe9e5650e17e39dDmitri Plotnikov return new AddressBookCursor((CrossProcessCursor) cursor, titles, counts); 5751ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } finally { 5752f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.close(); 5753ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5754ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5755ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 57562d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill /** 575792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Returns the contact Id for the contact identified by the lookupKey. 575892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Robust against changes in the lookup key: if the key has changed, will 575992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * look up the contact by the raw contact IDs or name encoded in the lookup 576092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * key. 57612d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill */ 57622d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) { 57635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey key = new ContactLookupKey(); 57645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments = key.parse(lookupKey); 57655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 576692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov long contactId = -1; 57675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_PROFILE)) { 57685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // We should already be in a profile database context, so just look up a single contact. 57695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro contactId = lookupSingleContactId(db); 57705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 57715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 577292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_SOURCE_ID)) { 577392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdBySourceIds(db, segments); 577492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 577592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 577692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 577792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 577892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 577992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov boolean hasRawContactIds = 578092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID); 578192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds) { 578292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdByRawContactIds(db, segments); 578392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 578492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 578592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 578692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 578792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 578892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds 578992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME)) { 57905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = lookupContactIdByDisplayNames(db, segments); 57915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 57935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 57945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 57955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 57965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private long lookupSingleContactId(SQLiteDatabase db) { 57975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = db.query(Tables.CONTACTS, new String[] {Contacts._ID}, 57985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro null, null, null, null, null, "1"); 57995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro try { 58005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (c.moveToFirst()) { 58015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return c.getLong(0); 58025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 58035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return -1; 58045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 58055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } finally { 58065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro c.close(); 58075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 58085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 58095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 58105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private interface LookupBySourceIdQuery { 581143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 58125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 58145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 581543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 58165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 58175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.SOURCE_ID 58185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 58195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 582143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 58225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 58235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int SOURCE_ID = 3; 58245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long lookupContactIdBySourceIds(SQLiteDatabase db, 58275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments) { 58285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 58295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(RawContacts.SOURCE_ID + " IN ("); 58305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 58315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 583292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID) { 58335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 58345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 58355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 58385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 58395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS, 58415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 58425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 58435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 584443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 584543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 58465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME); 58475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 584843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 58495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID); 58505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 58515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 585292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID 585392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 58545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(sourceId)) { 58555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID); 58565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 58575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 58615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 58625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 58655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 586792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByRawContactIdQuery { 586843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 58695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 58715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 587243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 58735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 587492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts._ID, 58755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 58765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 58775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 587843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 58795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 588092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ID = 3; 58815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 588392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByRawContactIds(SQLiteDatabase db, 588492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 588592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 588692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(RawContacts._ID + " IN ("); 58875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 58885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 588992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 589092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(segment.rawContactId); 589192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(","); 58925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 58935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 589492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 589592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 58965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 589792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov Cursor c = db.query(LookupByRawContactIdQuery.TABLE, LookupByRawContactIdQuery.COLUMNS, 589892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.toString(), null, null, null, null); 589992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov try { 590092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov while (c.moveToNext()) { 590143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = c.getString( 590243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro LookupByRawContactIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 590392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountName = c.getString(LookupByRawContactIdQuery.ACCOUNT_NAME); 590492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int accountHashCode = 590543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 590692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String rawContactId = c.getString(LookupByRawContactIdQuery.ID); 590792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 590892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 590992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID 591092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 591192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && segment.rawContactId.equals(rawContactId)) { 591292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov segment.contactId = c.getLong(LookupByRawContactIdQuery.CONTACT_ID); 591392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov break; 591492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 591592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 591692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 591792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } finally { 591892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov c.close(); 59195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 59205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 592192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return getMostReferencedContactId(segments); 592292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 592392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 592492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByDisplayNameQuery { 592592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS; 592692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 592792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String COLUMNS[] = { 592892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.CONTACT_ID, 592943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 593092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 593192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov NameLookupColumns.NORMALIZED_NAME 593292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov }; 593392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 593492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int CONTACT_ID = 0; 593543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 593692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_NAME = 2; 593792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int NORMALIZED_NAME = 3; 593892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 593992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 594092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByDisplayNames(SQLiteDatabase db, 594192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 59425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 59435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(NameLookupColumns.NORMALIZED_NAME + " IN ("); 59445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 59455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 594692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 594792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 59485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 59495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 59505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 59515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 59525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 59535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY 59545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov + " AND " + RawContacts.CONTACT_ID + " NOT NULL"); 59555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 59565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS, 59575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 59585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 59595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 596043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 596143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE_AND_DATA_SET); 59625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME); 59635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 596443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 59655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME); 59665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 59675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 596892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if ((segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 596992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) 597092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 59715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(name)) { 59725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID); 59735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 59745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 59755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 59765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 59775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 59785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 59795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 59805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 59815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 59825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 59835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 598492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private boolean lookupKeyContainsType(ArrayList<LookupKeySegment> segments, int lookupType) { 598592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 598692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 598792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == lookupType) { 598892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return true; 598992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 599092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 599192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 599292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return false; 599392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 599492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 5995ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov public void updateLookupKeyForRawContact(SQLiteDatabase db, long rawContactId) { 59965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateLookupKeyForRawContact(db, rawContactId); 5997ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov } 5998ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov 59995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov /** 60005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov * Returns the contact ID that is mentioned the highest number of times. 60015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov */ 60025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) { 60035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Collections.sort(segments); 60045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 60055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long bestContactId = -1; 60065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int bestRefCount = 0; 60075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 60085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = -1; 60095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int count = 0; 60105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 60115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = segments.size(); 60125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segmentCount; i++) { 60135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 60145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId != -1) { 60155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId == contactId) { 60165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count++; 60175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 60185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 60195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestContactId = contactId; 60205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestRefCount = count; 60215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 60225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = segment.contactId; 60235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count = 1; 60245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 60255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 60265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 60275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 60285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 60295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 60305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return bestContactId; 60315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 60325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 60335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 6034763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 6035763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar String[] projection) { 60364928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 60372f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 60382f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 60392f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 60404928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * @param includeDataUsageStat true when the table should include DataUsageStat table. 60414928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Note that this uses INNER JOIN instead of LEFT OUTER JOIN, so some of data in Contacts 60424928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * may be dropped. 60432f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 60442f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 60454928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa String[] projection, boolean includeDataUsageStat) { 604682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6047ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 60482f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 60492f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Just for frequently contacted contacts in Strequent Uri handling. 60504928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (includeDataUsageStat) { 60512f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa sb.append(" INNER JOIN " + 6052ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA_USAGE_STAT + " AS " + Tables.DATA_USAGE_STAT + 60532f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa " ON (" + 60542f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DbQueryUtils.concatenateClauses( 60552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DataUsageStatColumns.CONCRETE_TIMES_USED + " > 0", 60564928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) + 60572f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa ")"); 60582f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 60592f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 60607ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 60617ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6062916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setTables(sb.toString()); 6063916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionMap); 6064916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov } 6065916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6066916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** 6067916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * Finds name lookup records matching the supplied filter, picks one arbitrary match per 6068916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * contact and joins that with other contacts tables. 6069916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov */ 6070916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private void setTablesAndProjectionMapForContactsWithSnippet(SQLiteQueryBuilder qb, Uri uri, 60717ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov String[] projection, String filter, long directoryId) { 60727ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov 60737ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6074ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 6075916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 607603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (filter != null) { 607703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov filter = filter.trim(); 607803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 607903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 608030cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov if (TextUtils.isEmpty(filter) || (directoryId != -1 && directoryId != Directory.DEFAULT)) { 608130cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov sb.append(" JOIN (SELECT NULL AS " + SearchSnippetColumns.SNIPPET + " WHERE 0)"); 60825e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } else { 60835e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov appendSearchIndexJoin(sb, uri, projection, filter); 60845e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 60857ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 60867ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 608703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setTables(sb.toString()); 608803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionWithSnippetMap); 608903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 6090916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 609103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private void appendSearchIndexJoin( 609203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov StringBuilder sb, Uri uri, String[] projection, String filter) { 6093916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 60945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, SearchSnippetColumns.SNIPPET)) { 609503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String[] args = null; 609603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String snippetArgs = 609703197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 609803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (snippetArgs != null) { 609903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov args = snippetArgs.split(","); 610003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 610103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 61025e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String startMatch = args != null && args.length > 0 ? args[0] 61035e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_START_MATCH; 61045e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String endMatch = args != null && args.length > 1 ? args[1] 61055e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_END_MATCH; 61065e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String ellipsis = args != null && args.length > 2 ? args[2] 61075e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_ELLIPSIS; 61085e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 61095e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 61105e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 6111174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin( 6112174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb, filter, true, startMatch, endMatch, ellipsis, maxTokens); 6113174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 6114174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin(sb, filter, false, null, null, null, 0); 6115174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6116174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6117174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 6118174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public void appendSearchIndexJoin(StringBuilder sb, String filter, 6119174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean snippetNeeded, String startMatch, String endMatch, String ellipsis, 6120174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int maxTokens) { 6121174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isEmailAddress = false; 6122174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String emailAddress = null; 6123174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isPhoneNumber = false; 6124174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String phoneNumber = null; 6125174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String numberE164 = null; 6126174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 61273716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // If the query consists of a single word, we can do snippetizing after-the-fact for a 61283716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // performance boost. 61293716f1447ceb21180d1301790eabd8b9453f486dDave Santoro boolean singleTokenSearch = filter.split(QUERY_TOKENIZER_REGEX).length == 1; 61303716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 6131174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (filter.indexOf('@') != -1) { 61325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro emailAddress = mDbHelper.get().extractAddressFromEmailAddress(filter); 6133174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isEmailAddress = !TextUtils.isEmpty(emailAddress); 6134174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 6135174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isPhoneNumber = isPhoneNumber(filter); 613604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (isPhoneNumber) { 613704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann phoneNumber = PhoneNumberUtils.normalizeNumber(filter); 613804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann numberE164 = PhoneNumberUtils.formatNumberToE164(phoneNumber, 61395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getCountryIso()); 614004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 6141174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6142174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 6143174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(" JOIN (SELECT " + SearchIndexColumns.CONTACT_ID + " AS snippet_contact_id"); 6144174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (snippetNeeded) { 61455e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(", "); 61465e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 61473d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 61485e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 614904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Email.ADDRESS + ")"); 615004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + Tables.DATA_JOIN_RAW_CONTACTS); 615104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 615204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID + " AND " + Email.ADDRESS + " LIKE "); 615304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann DatabaseUtils.appendEscapedSQLString(sb, filter + "%"); 615404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 61553d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 61563d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(","); 61573716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 61583716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 61593716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 61603716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 61613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 61623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 61633716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 61643d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(")"); 61653d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 61663d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 61673d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 616804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("||(SELECT MIN(" + Phone.NUMBER + ")"); 616904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + 617004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann Tables.DATA_JOIN_RAW_CONTACTS + " JOIN " + Tables.PHONE_LOOKUP); 617104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" ON " + DataColumns.CONCRETE_ID); 617204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID); 617304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 617404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID); 617504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" AND " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 617604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(phoneNumber); 617704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 617804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(numberE164)) { 617904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" OR " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 618004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(numberE164); 618104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 618204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 618304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(")||"); 61845e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 61855e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 61863716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 61873716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 61883716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 61893716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 61903716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 61913716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 61923716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 61935e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 619403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 619504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann final String normalizedFilter = NameNormalizer.normalize(filter); 619604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(normalizedFilter)) { 61973716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Optimization for single-token search. 61983716f1447ceb21180d1301790eabd8b9453f486dDave Santoro if (singleTokenSearch) { 61993716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 62003716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 62013716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("(CASE WHEN EXISTS (SELECT 1 FROM "); 62023716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.RAW_CONTACTS + " AS rc INNER JOIN "); 62033716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.NAME_LOOKUP + " AS nl ON (rc." + RawContacts._ID); 62043716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=nl." + NameLookupColumns.RAW_CONTACT_ID); 62053716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") WHERE nl." + NameLookupColumns.NORMALIZED_NAME); 62063716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" GLOB '" + normalizedFilter + "*' AND "); 62073716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("nl." + NameLookupColumns.NAME_TYPE + "="); 62083716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(NameLookupType.NAME_COLLATION_KEY + " AND "); 62093716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 62103716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=rc." + RawContacts.CONTACT_ID); 62113716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") THEN NULL ELSE "); 62123716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 62133716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" END)"); 62143716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 621504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } else { 621604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("NULL"); 621704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 621803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 62195e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" AS " + SearchSnippetColumns.SNIPPET); 62205e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 622103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 62225e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" FROM " + Tables.SEARCH_INDEX); 62235e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" WHERE "); 62245e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(Tables.SEARCH_INDEX + " MATCH "); 62255e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 62262352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, "\"" + sanitizeMatch(filter) + "*\""); 62273d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 62282352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, 622904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann "\"" + sanitizeMatch(filter) + "*\" OR \"" + phoneNumber + "*\"" 62302352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov + (numberE164 != null ? " OR \"" + numberE164 + "\"" : "")); 623103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 62322352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, sanitizeMatch(filter) + "*"); 62339c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov } 623403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov sb.append(") ON (" + Contacts._ID + "=snippet_contact_id)"); 6235a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov } 6236a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov 62372352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov private String sanitizeMatch(String filter) { 62382352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov // TODO more robust preprocessing of match expressions 62392352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov return filter.replace('-', ' ').replace('\"', ' '); 62402352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov } 62412352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov 62425e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov private void appendSnippetFunction( 62435e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov StringBuilder sb, String startMatch, String endMatch, String ellipsis, int maxTokens) { 62445e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append("snippet(" + Tables.SEARCH_INDEX + ","); 62455e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 62465e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 62475e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 62485e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 62495e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, ellipsis); 62505e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 62515e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov // The index of the column used for the snippet, "content" 62525e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(",1,"); 62535e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(maxTokens); 62545e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 62555e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 62565e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 6257763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) { 6258763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar StringBuilder sb = new StringBuilder(); 6259ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.RAW_CONTACTS); 6260763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setTables(sb.toString()); 6261763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setProjectionMap(sRawContactsProjectionMap); 626243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 6263763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar } 6264763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar 6265a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForRawEntities(SQLiteQueryBuilder qb, Uri uri) { 6266ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.RAW_ENTITIES); 6267a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sRawEntityProjectionMap); 626843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 626946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 627046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 627182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 627282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String[] projection, boolean distinct) { 627346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, distinct, null); 627446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 627546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 627646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 627746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @param usageType when non-null {@link Tables#DATA_USAGE_STAT} is joined with the specified 627846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type. 627946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 628046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 628146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String[] projection, boolean distinct, Integer usageType) { 628282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6283ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 628482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov sb.append(" data"); 628582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov 6286a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID); 6287a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6288a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6289a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 62903296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey 629146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (usageType != null) { 629246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa appendDataUsageStatJoin(sb, usageType, DataColumns.CONCRETE_ID); 629346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 629446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 629582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov qb.setTables(sb.toString()); 6296f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov 6297f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov boolean useDistinct = distinct 62985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro || !mDbHelper.get().isInProjection(projection, DISTINCT_DATA_PROHIBITING_COLUMNS); 6299f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setDistinct(useDistinct); 6300f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setProjectionMap(useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap); 630143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 6302ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov } 6303ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov 63040a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb, 63050a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String[] projection) { 63060a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6307ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 63080a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" data"); 6309a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6310a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 63110a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6312a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6313a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sStatusUpdatesProjectionMap); 6314a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6315a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 63163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItems(SQLiteQueryBuilder qb) { 63179b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann qb.setTables(Views.STREAM_ITEMS); 63183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemsProjectionMap); 63193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 63203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 63213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItemPhotos(SQLiteQueryBuilder qb) { 63221dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.PHOTO_FILES 63231dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.STREAM_ITEM_PHOTOS + " ON (" 63241dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_PHOTO_FILE_ID + "=" 63251dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + PhotoFilesColumns.CONCRETE_ID 63261dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.STREAM_ITEMS + " ON (" 63271dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=" 63280bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + StreamItemsColumns.CONCRETE_ID + ")" 63290bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + " JOIN " + Tables.RAW_CONTACTS + " ON (" 63300bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + StreamItemsColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 63310bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + ")"); 63323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemPhotosProjectionMap); 63333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 63343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 6335a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForEntities(SQLiteQueryBuilder qb, Uri uri, 6336a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection) { 6337a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6338ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.ENTITIES); 6339a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" data"); 6340a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6341a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts.Entity.CONTACT_ID); 6342a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6343a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, Contacts.Entity.DATA_ID); 6344a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, Contacts.Entity.DATA_ID); 6345a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6346a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6347a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sEntityProjectionMap); 634843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro appendAccountFromParameter(qb, uri, true); 6349a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6350a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6351a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactStatusUpdateJoin(StringBuilder sb, String[] projection, 6352a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lastStatusUpdateIdColumn) { 63535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, 6354a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS, 6355a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_RES_PACKAGE, 6356a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_ICON, 6357a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_LABEL, 6358a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_TIMESTAMP)) { 6359a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " " 6360a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.ALIAS + 6361a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + lastStatusUpdateIdColumn + "=" 6362a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")"); 63630a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6364a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 63650a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6366a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataStatusUpdateJoin(StringBuilder sb, String[] projection, 6367a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 63685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, 63690a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS, 63700a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_RES_PACKAGE, 63710a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_ICON, 63720a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_LABEL, 63730a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_TIMESTAMP)) { 63740a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + 6375a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "=" 6376a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + dataIdColumn + ")"); 63770a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6378a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6379a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 638046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void appendDataUsageStatJoin(StringBuilder sb, int usageType, String dataIdColumn) { 638146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" LEFT OUTER JOIN " + Tables.DATA_USAGE_STAT + 638246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" + dataIdColumn + 638346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " AND " + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" + usageType + ")"); 638446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 638546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 6386a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactPresenceJoin(StringBuilder sb, String[] projection, 6387a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn) { 63885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, 6389a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_PRESENCE, Contacts.CONTACT_CHAT_CAPABILITY)) { 6390a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + 6391a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + contactIdColumn + " = " 6392a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + ")"); 6393a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6394a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6395a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6396a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataPresenceJoin(StringBuilder sb, String[] projection, 6397a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 63985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, Data.PRESENCE, Data.CHAT_CAPABILITY)) { 6399a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE + 6400a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdates.DATA_ID + "=" + dataIdColumn + ")"); 6401a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6402a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6403a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 640424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private boolean appendLocalDirectorySelectionIfNeeded(SQLiteQueryBuilder qb, long directoryId) { 6405385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directoryId == Directory.DEFAULT) { 6406385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY); 640724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 6408385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directoryId == Directory.LOCAL_INVISIBLE){ 6409385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov qb.appendWhere(Contacts._ID + " NOT IN " + Tables.DEFAULT_DIRECTORY); 641024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return true; 641124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 641224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro return false; 641324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 641424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 641543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri, 641643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro boolean includeDataSet) { 6417f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6418f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 641943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 6420e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6421e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6422e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6423e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 64245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 6425fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6426e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6427e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6428e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6429e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6430e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6431e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 643243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String toAppend = RawContacts.ACCOUNT_NAME + "=" 64334a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + DatabaseUtils.sqlEscapeString(accountName) + " AND " 64344a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + RawContacts.ACCOUNT_TYPE + "=" 643543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro + DatabaseUtils.sqlEscapeString(accountType); 643643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (includeDataSet) { 643743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (dataSet == null) { 643843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro toAppend += " AND " + RawContacts.DATA_SET + " IS NULL"; 643943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } else { 644043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro toAppend += " AND " + RawContacts.DATA_SET + "=" + 644143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro DatabaseUtils.sqlEscapeString(dataSet); 644243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 644343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 644443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro qb.appendWhere(toAppend); 64454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } else { 64464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere("1"); 64474a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 64484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 64494a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 6450e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong private String appendAccountToSelection(Uri uri, String selection) { 6451f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6452f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 645343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 6454e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6455e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6456e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6457e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 64585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 6459fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6460e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 6461e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6462e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6463e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 6464e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validAccount = !TextUtils.isEmpty(accountName); 6465e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 6466e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "=" 6467e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountName) + " AND " 6468e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + RawContacts.ACCOUNT_TYPE + "=" 6469e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong + DatabaseUtils.sqlEscapeString(accountType)); 647043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!TextUtils.isEmpty(dataSet)) { 647143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selectionSb.append(" AND " + RawContacts.DATA_SET + "=") 647243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .append(DatabaseUtils.sqlEscapeString(dataSet)); 647343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 6474e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong if (!TextUtils.isEmpty(selection)) { 6475e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(" AND ("); 6476e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(selection); 6477e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(')'); 6478e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6479e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selectionSb.toString(); 6480e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } else { 6481e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selection; 6482e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6483e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6484e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong 64857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 6486c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * Gets the value of the "limit" URI query parameter. 6487c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * 6488c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * @return A string containing a non-negative integer, or <code>null</code> if 6489c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * the parameter is not set, or is set to an invalid value. 6490c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov */ 6491f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private String getLimit(Uri uri) { 64922e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limitParam = getQueryParameter(uri, ContactsContract.LIMIT_PARAM_KEY); 6493c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (limitParam == null) { 6494c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6495c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6496c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov // make sure that the limit is a non-negative integer 6497c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov try { 6498c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov int l = Integer.parseInt(limitParam); 6499c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (l < 0) { 6500c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6501c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6502c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6503c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return String.valueOf(l); 6504c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } catch (NumberFormatException ex) { 6505c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 6506c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 6507c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6508c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6509c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 6510b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov @Override 6511f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 6512f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mode.equals("r")) { 6513f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mReadAccessLatch); 6514f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6515f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro waitForAccess(mWriteAccessLatch); 6516f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 65175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 65185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 65195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileProvider.openAssetFile(uri, mode); 65205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 65215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 65225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mode.equals("r")) { 65235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDb = mDbHelper.get().getReadableDatabase(); 65245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 65255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDb = mDbHelper.get().getWritableDatabase(); 65265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 65275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return openAssetFileLocal(uri, mode); 65285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 65295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 65305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 65315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public AssetFileDescriptor openAssetFileLocal(Uri uri, String mode) 65325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throws FileNotFoundException { 65335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 65345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 65355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 65365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(mDb); 65375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 6538415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6539b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov int match = sUriMatcher.match(uri); 6540b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov switch (match) { 6541a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 654224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 65435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return openPhotoAssetFile(mActiveDb.get(), uri, mode, 654424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Data._ID + "=" + Contacts.PHOTO_ID + " AND " + 654524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContacts.CONTACT_ID + "=?", 654624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(rawContactId)}); 6547e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6548b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6549f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: { 6550f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6551f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6552f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact ID can only be read."); 6553f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6554f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 65555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.CONTACTS, 6556f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{Contacts.PHOTO_FILE_ID}, 6557f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID + "=?", new String[]{String.valueOf(contactId)}, 6558f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, null); 6559f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6560f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6561f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(0); 6562f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6563f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6564f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6565f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6566f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6567f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6568f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6569f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: { 6570f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6571f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6572f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact lookup key can only be read."); 6573f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6574f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro List<String> pathSegments = uri.getPathSegments(); 6575f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int segmentCount = pathSegments.size(); 6576f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount < 4) { 65775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 6578f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Missing a lookup key", uri)); 6579f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6580f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String lookupKey = pathSegments.get(2); 6581f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Contacts.PHOTO_FILE_ID}; 6582f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount == 5) { 6583f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(pathSegments.get(3)); 6584f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 6585f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 65865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 6587f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro projection, null, null, null, null, null, 6588f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey); 6589f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c != null) { 6590f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6591f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6592f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6593f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6594f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6595f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6596f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6597f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6598f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6599f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6600f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6601f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 66025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 66035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = qb.query(mActiveDb.get(), projection, Contacts._ID + "=?", 6604f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(contactId)}, null, null, null); 6605f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6606f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6607f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 6608f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6609f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6610f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6611f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6612f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6613f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6614f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: { 6615f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6616f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean writeable = !mode.equals("r"); 6617f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6618f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Find the primary photo data record for this raw contact. 6619f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 6620f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Data._ID, Photo.PHOTO_FILE_ID}; 6621f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 66225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = qb.query(mActiveDb.get(), projection, 6623f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?", 6624f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(rawContactId), Photo.CONTENT_ITEM_TYPE}, 6625f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, Data.IS_PRIMARY + " DESC"); 6626f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long dataId = 0; 6627f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = 0; 6628f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6629f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c.getCount() >= 1) { 6630f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 6631f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro dataId = c.getLong(0); 6632f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro photoFileId = c.getLong(1); 6633f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6634f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 6635f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 6636f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6637f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6638f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If writeable, open a writeable file descriptor that we can monitor. 6639f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // When the caller finishes writing content, we'll process the photo and 6640f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // update the data record. 6641f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (writeable) { 6642f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForWrite(rawContactId, dataId, uri, mode); 6643f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6644f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6645f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6646f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6647f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6648f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: { 6649f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = ContentUris.parseId(uri); 6650f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 6651f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 6652f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by key can only be read."); 6653f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6654f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 6655f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6656f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6657e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov case DATA_ID: { 665824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = Long.parseLong(uri.getPathSegments().get(1)); 66595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return openPhotoAssetFile(mActiveDb.get(), uri, mode, 6660e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov Data._ID + "=? AND " + Data.MIMETYPE + "='" + Photo.CONTENT_ITEM_TYPE + "'", 666124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(dataId)}); 6662d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6663d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6664fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case PROFILE_AS_VCARD: { 6665fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // When opening a contact as file, we pass back contents as a 6666fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // vCard-encoded stream. We build into a local buffer first, 6667fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // then pipe into MemoryFile once the exact size is known. 6668fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6669fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6670fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen return buildAssetFileDescriptor(localStream); 6671fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 667242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 6673fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case CONTACTS_AS_VCARD: { 667442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // When opening a contact as file, we pass back contents as a 667542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // vCard-encoded stream. We build into a local buffer first, 667642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // then pipe into MemoryFile once the exact size is known. 667742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6678fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 6679f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 668042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 668142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 668242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 668342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKeys = uri.getPathSegments().get(2); 668442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String[] loopupKeyList = lookupKeys.split(":"); 668542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final StringBuilder inBuilder = new StringBuilder(); 6686fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Uri queryUri = Contacts.CONTENT_URI; 668742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann int index = 0; 6688fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen 6689d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // SQLite has limits on how many parameters can be used 6690d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // so the IDs are concatenated to a query string here instead 669142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann for (String lookupKey : loopupKeyList) { 669242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann if (index == 0) { 6693d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append("("); 669442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } else { 6695d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append(","); 669642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 66975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // TODO: Figure out what to do if the profile contact is in the list. 66985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 669924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro inBuilder.append(contactId); 670042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann index++; 670142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 670242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann inBuilder.append(')'); 670342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String selection = Contacts._ID + " IN " + inBuilder.toString(); 6704d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6705d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // When opening a contact as file, we pass back contents as a 6706d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // vCard-encoded stream. We build into a local buffer first, 6707d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // then pipe into MemoryFile once the exact size is known. 6708d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 6709fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(queryUri, localStream, selection, null); 6710f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 6711d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6712b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6713b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov default: 67145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new FileNotFoundException(mDbHelper.get().exceptionMessage( 67155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "File does not exist", uri)); 6716b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6717b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 6718b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 6719afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private AssetFileDescriptor openPhotoAssetFile(SQLiteDatabase db, Uri uri, String mode, 6720afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro String selection, String[] selectionArgs) 6721e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throws FileNotFoundException { 6722e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov if (!"r".equals(mode)) { 67235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new FileNotFoundException(mDbHelper.get().exceptionMessage("Mode " + mode 6724e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov + " not supported.", uri)); 6725e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6726e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6727e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov String sql = 6728ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann "SELECT " + Photo.PHOTO + " FROM " + Views.DATA + 6729e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov " WHERE " + selection; 673008ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood try { 6731f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6732f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert DatabaseUtils.blobFileDescriptorForQuery(db, sql, selectionArgs)); 673308ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } catch (SQLiteDoneException e) { 673408ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood // this will happen if the DB query returns no rows (i.e. contact does not exist) 673508ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood throw new FileNotFoundException(uri.toString()); 673608ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } 6737e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 6738e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 6739f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6740f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a display photo from the photo store for reading. 6741f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoFileId The display photo file ID 6742f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor that allows the file to be read. 6743f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @throws FileNotFoundException If no photo file for the given ID exists. 6744f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6745f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForRead(long photoFileId) 6746f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throws FileNotFoundException { 67475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore.Entry entry = mPhotoStore.get().get(photoFileId); 6748f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 6749f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return makeAssetFileDescriptor( 6750f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.open(new File(entry.path), 6751f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ParcelFileDescriptor.MODE_READ_ONLY), 6752f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro entry.size); 6753f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6754f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 6755f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new FileNotFoundException("No photo file found for ID " + photoFileId); 6756f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6757f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6758f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6759f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6760f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a file descriptor for a photo to be written. When the caller completes writing 6761f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to the file (closing the output stream), the image will be parsed out and processed. 6762f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If processing succeeds, the given raw contact ID's primary photo record will be 6763f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * populated with the inserted image (if no primary photo record exists, the data ID can 6764f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * be left as 0, and a new data record will be inserted). 6765f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rawContactId Raw contact ID this photo entry should be associated with. 6766f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param dataId Data ID for a photo mimetype that will be updated with the inserted 6767f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * image. May be set to 0, in which case the inserted image will trigger creation 6768f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * of a new primary photo image data row for the raw contact. 6769f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param uri The URI being used to access this file. 6770f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param mode Read/write mode string. 6771f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor the caller can use to write an image file for the 6772f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact. 6773f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6774f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForWrite(long rawContactId, long dataId, Uri uri, 6775f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String mode) { 6776f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6777c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro ParcelFileDescriptor[] pipeFds = ParcelFileDescriptor.createPipe(); 6778c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro PipeMonitor pipeMonitor = new PipeMonitor(rawContactId, dataId, pipeFds[0]); 6779c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro pipeMonitor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[]) null); 6780c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro return new AssetFileDescriptor(pipeFds[1], 0, AssetFileDescriptor.UNKNOWN_LENGTH); 6781f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException ioe) { 6782f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Could not create temp image file in mode " + mode); 6783f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return null; 6784f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6785f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6786f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6787f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 6788c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * Async task that monitors the given file descriptor (the read end of a pipe) for 6789c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * the writer finishing. If the data from the pipe contains a valid image, the image 6790c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * is either inserted into the given raw contact or updated in the given data row. 6791f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 6792c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private class PipeMonitor extends AsyncTask<Object, Object, Object> { 6793c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private final ParcelFileDescriptor mDescriptor; 6794f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mRawContactId; 6795f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mDataId; 6796c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private PipeMonitor(long rawContactId, long dataId, ParcelFileDescriptor descriptor) { 6797f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mRawContactId = rawContactId; 6798f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDataId = dataId; 6799c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro mDescriptor = descriptor; 6800f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6801f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6802f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro @Override 6803c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro protected Object doInBackground(Object... params) { 6804c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro AutoCloseInputStream is = new AutoCloseInputStream(mDescriptor); 6805f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 6806c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro Bitmap b = BitmapFactory.decodeStream(is); 6807f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (b != null) { 6808fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann waitForAccess(mWriteAccessLatch); 6809f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro PhotoProcessor processor = new PhotoProcessor(b, mMaxDisplayPhotoDim, 6810f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mMaxThumbnailPhotoDim); 6811f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6812f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Store the compressed photo in the photo store. 68135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore photoStore = ContactsContract.isProfileId(mRawContactId) 68145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ? mProfilePhotoStore 68155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro : mContactsPhotoStore; 68165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long photoFileId = photoStore.insert(processor); 6817f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6818c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro // Depending on whether we already had a data row to attach the photo 6819c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro // to, do an update or insert. 6820f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mDataId != 0) { 6821f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Update the data record with the new photo. 6822f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 6823f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6824f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6825f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6826f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6827f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6828f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6829f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6830f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6831c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro update(ContentUris.withAppendedId(Data.CONTENT_URI, mDataId), 6832c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro updateValues, null, null); 6833f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 6834f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Insert a new primary data record with the photo. 6835f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues insertValues = new ContentValues(); 6836f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6837f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 6838f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 6839f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6840f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 6841f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.IS_PRIMARY, 1); 6842f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 6843f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO_FILE_ID, photoFileId); 6844f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6845f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 6846f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insert(RawContacts.CONTENT_URI.buildUpon() 6847f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(String.valueOf(mRawContactId)) 6848f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(RawContacts.Data.CONTENT_DIRECTORY).build(), 6849f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues); 6850f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6851c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro 6852f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6853c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro } catch (IOException e) { 6854c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro throw new RuntimeException(e); 6855f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6856c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro return null; 6857f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6858f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 6859f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 6860d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile"; 6861d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6862d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6863f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert * Returns an {@link AssetFileDescriptor} backed by the 6864d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * contents of the given {@link ByteArrayOutputStream}. 6865d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6866f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) { 6867d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey try { 6868d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey stream.flush(); 6869d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6870d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final byte[] byteData = stream.toByteArray(); 6871d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6872f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 6873f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert ParcelFileDescriptor.fromData(byteData, CONTACT_MEMORY_FILE_NAME), 6874f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert byteData.length); 6875d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } catch (IOException e) { 6876ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert Log.w(TAG, "Problem writing stream into an ParcelFileDescriptor: " + e.toString()); 6877ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert return null; 6878d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6879d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6880d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6881f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd) { 6882f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor(fd, AssetFileDescriptor.UNKNOWN_LENGTH); 6883f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6884f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6885f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd, long length) { 6886f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return fd != null ? new AssetFileDescriptor(fd, 0, length) : null; 6887f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 6888f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 6889d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 6890d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * Output {@link RawContacts} matching the requested selection in the vCard 6891d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * format to the given {@link OutputStream}. This method returns silently if 6892d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * any errors encountered. 6893d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 6894fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen private void outputRawContactsAsVCard(Uri uri, OutputStream stream, 6895fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen String selection, String[] selectionArgs) { 6896d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final Context context = this.getContext(); 6897dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen int vcardconfig = VCardConfig.VCARD_TYPE_DEFAULT; 6898fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if(uri.getBooleanQueryParameter( 6899fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, false)) { 6900dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen vcardconfig |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT; 6901dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen } 69027a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa final VCardComposer composer = 6903dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen new VCardComposer(context, vcardconfig, false); 6904108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Writer writer = null; 6905108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6906108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer = new BufferedWriter(new OutputStreamWriter(stream)); 6907fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if (!composer.init(uri, selection, selectionArgs, null)) { 6908108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "Failed to init VCardComposer"); 6909108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa return; 6910108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6911d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 6912108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa while (!composer.isAfterLast()) { 6913108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.write(composer.createOneEntry()); 6914108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6915108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6916108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.e(TAG, "IOException: " + e); 6917108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } finally { 6918108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa composer.terminate(); 6919108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa if (writer != null) { 6920108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 6921108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.close(); 6922108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 6923108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "IOException during closing output stream: " + e); 6924108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 6925d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6926d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6927d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 6928b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 69294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 69304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 6931415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6932415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov waitForAccess(mReadAccessLatch); 6933415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 6934a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 69354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 6936b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS: 6937be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return Contacts.CONTENT_TYPE; 69382d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill case CONTACTS_LOOKUP: 6939b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_ID: 6940b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_LOOKUP_ID: 694124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 6942b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_ITEM_TYPE; 6943f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: 694442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: 694524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 6946f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey return Contacts.CONTENT_VCARD_TYPE; 6947f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov case CONTACTS_ID_PHOTO: 6948f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: 6949f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 6950f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: 6951f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: 6952f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case DISPLAY_PHOTO: 6953f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return "image/jpeg"; 6954b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS: 695524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 6956be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return RawContacts.CONTENT_TYPE; 6957b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS_ID: 695824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 6959b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return RawContacts.CONTENT_ITEM_TYPE; 6960f481f22a9323fe338672f99b88b26c5f0725cd42David Brown case DATA: 696124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 6962f481f22a9323fe338672f99b88b26c5f0725cd42David Brown return Data.CONTENT_TYPE; 6963508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 69645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long id = ContentUris.parseId(uri); 69655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (ContactsContract.isProfileId(id)) { 69665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileHelper.getDataMimeType(id); 69675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 69685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mContactsHelper.getDataMimeType(id); 69695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 697048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES: 697148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_TYPE; 697248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 697348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_ITEM_TYPE; 69749005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov case PHONE_LOOKUP: 69759005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov return PhoneLookup.CONTENT_TYPE; 697648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS: 697748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_TYPE; 697848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 697948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_ITEM_TYPE; 698048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS: 698148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_TYPE; 698248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: 698348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_ITEM_TYPE; 6984b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 6985b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_TYPE; 6986b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 6987b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_ITEM_TYPE; 6988b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case SETTINGS: 6989b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Settings.CONTENT_TYPE; 6990b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 6991b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_TYPE; 6992c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: 6993c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SUGGEST_MIME_TYPE; 6994c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: 6995c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SHORTCUT_MIME_TYPE; 6996d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES: 6997d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_TYPE; 6998d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID: 6999d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_ITEM_TYPE; 7000af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS: 7001af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.CONTENT_TYPE; 7002af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID: 7003af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.CONTENT_ITEM_TYPE; 7004af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID_PHOTOS: 7005af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.StreamItemPhotos.CONTENT_TYPE; 7006af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID_PHOTOS_ID: 7007af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.StreamItemPhotos.CONTENT_ITEM_TYPE; 7008af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_PHOTOS: 7009af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki throw new UnsupportedOperationException("Not supported for write-only URI " + uri); 701061efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov default: 701161efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov return mLegacyApiSupport.getType(uri); 70124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 70134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 70147e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 701509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov public String[] getDefaultProjection(Uri uri) { 701609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov final int match = sUriMatcher.match(uri); 701709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov switch (match) { 701809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS: 701909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP: 702009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_ID: 702109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP_ID: 702209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 702324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 702409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsProjectionMap.getColumnNames(); 702509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 70268727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov case CONTACTS_ID_ENTITIES: 702724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: 70288727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov return sEntityProjectionMap.getColumnNames(); 70298727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov 703009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_VCARD: 703109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_MULTI_VCARD: 703224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 703309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsVCardProjectionMap.getColumnNames(); 703409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 703509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS: 703609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS_ID: 703724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 703824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 703909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sRawContactsProjectionMap.getColumnNames(); 704009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 704109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DATA_ID: 704209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES: 704309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES_ID: 704409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS: 704509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS_ID: 704609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS: 704709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS_ID: 704824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 704909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDataProjectionMap.getColumnNames(); 705009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 705109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONE_LOOKUP: 705209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sPhoneLookupProjectionMap.getColumnNames(); 705309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 705409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 705509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 705609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sAggregationExceptionsProjectionMap.getColumnNames(); 705709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 705809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case SETTINGS: 705909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sSettingsProjectionMap.getColumnNames(); 706009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 706109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES: 706209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES_ID: 706309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDirectoryProjectionMap.getColumnNames(); 706409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 706509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov default: 706609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return null; 706709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 706809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 706909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 7070f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private class StructuredNameLookupBuilder extends NameLookupBuilder { 7071f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 7072f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov public StructuredNameLookupBuilder(NameSplitter splitter) { 7073f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov super(splitter); 7074f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7075f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 7076f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 7077f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected void insertNameLookup(long rawContactId, long dataId, int lookupType, 7078f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov String name) { 70795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().insertNameLookup(rawContactId, dataId, lookupType, name); 7080f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7081f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 7082f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 7083f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected String[] getCommonNicknameClusters(String normalizedName) { 7084d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); 7085f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7086f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7087f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 70882d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) { 7089d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov sb.append("(" + 7090d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov "SELECT DISTINCT " + RawContacts.CONTACT_ID + 7091d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 7092d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " JOIN " + Tables.NAME_LOOKUP + 7093d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " ON(" + RawContactsColumns.CONCRETE_ID + "=" 7094d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov + NameLookupColumns.RAW_CONTACT_ID + ")" + 7095d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " WHERE normalized_name GLOB '"); 7096e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(NameNormalizer.normalize(filterParam)); 7097916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov sb.append("*' AND " + NameLookupColumns.NAME_TYPE + 7098916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov " IN(" + CONTACT_LOOKUP_NAME_TYPES + "))"); 7099e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 7100e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 71019a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov public boolean isPhoneNumber(String filter) { 71029a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean atLeastOneDigit = false; 71039a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov int len = filter.length(); 71049a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov for (int i = 0; i < len; i++) { 71059a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov char c = filter.charAt(i); 71069a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (c >= '0' && c <= '9') { 71079a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov atLeastOneDigit = true; 71089a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } else if (c != '*' && c != '#' && c != '+' && c != 'N' && c != '.' && c != ';' 71099a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov && c != '-' && c != '(' && c != ')' && c != ' ') { 71109a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return false; 71119a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 71129a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 71139a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return atLeastOneDigit; 71149a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 71159a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 71164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** 71177a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * Takes components of a name from the query parameters and returns a cursor with those 71187a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * components as well as all missing components. There is no database activity involved 71197a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * in this so the call can be made on the UI thread. 71207a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov */ 71217a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private Cursor completeName(Uri uri, String[] projection) { 71227a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (projection == null) { 71237a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov projection = sDataProjectionMap.getColumnNames(); 71247a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 71257a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 71267a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ContentValues values = new ContentValues(); 7127f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataRowHandlerForStructuredName handler = (DataRowHandlerForStructuredName) 7128f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov getDataRowHandler(StructuredName.CONTENT_ITEM_TYPE); 71297a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 71307a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov copyQueryParamsToContentValues(values, uri, 71317a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.DISPLAY_NAME, 71327a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PREFIX, 71337a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.GIVEN_NAME, 71347a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.MIDDLE_NAME, 71357a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.FAMILY_NAME, 71367a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.SUFFIX, 71377a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_NAME, 71387a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_FAMILY_NAME, 71397a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_MIDDLE_NAME, 71407a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_GIVEN_NAME 71417a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ); 71427a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 71437a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov handler.fixStructuredNameComponents(values, values); 71447a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 71457a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 71467a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov Object[] row = new Object[projection.length]; 71477a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 71487a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov row[i] = values.get(projection[i]); 71497a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 71507a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov cursor.addRow(row); 71517a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return cursor; 71527a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 71537a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 71547a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private void copyQueryParamsToContentValues(ContentValues values, Uri uri, String... columns) { 71557a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (String column : columns) { 71567a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov String param = uri.getQueryParameter(column); 71577a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (param != null) { 71587a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov values.put(column, param); 71597a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 71607a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 71617a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 71627a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 71637a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 71647a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov /** 71654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov * Inserts an argument at the beginning of the selection arg list. 71664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov */ 71674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private String[] insertSelectionArg(String[] selectionArgs, String arg) { 7168b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 7169b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 7170b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 7171b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 7172b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 71734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov newSelectionArgs[0] = arg; 71744a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length); 7175b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 7176b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 7177b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 7178caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 71795e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar private String[] appendProjectionArg(String[] projection, String arg) { 71805e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection == null) { 71815e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return null; 71825e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 71835e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar final int length = projection.length; 71845e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar String[] newProjection = new String[length + 1]; 71855e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar System.arraycopy(projection, 0, newProjection, 0, length); 71865e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar newProjection[length] = arg; 71875e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return newProjection; 71885e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 71895e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 7190caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov protected Account getDefaultAccount() { 7191caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov AccountManager accountManager = AccountManager.get(getContext()); 7192caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov try { 71935f1f4a062ac34d75d2dbf586702cbeb121cf09caDmitri Plotnikov Account[] accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE); 7194caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov if (accounts != null && accounts.length > 0) { 7195caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov return accounts[0]; 7196caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 7197caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } catch (Throwable e) { 71986f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov Log.e(TAG, "Cannot determine the default account for contacts compatibility", e); 7199caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 72006f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov return null; 7201caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 7202f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 720373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov /** 720443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Returns true if the specified account type and data set is writable. 720573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov */ 720643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro protected boolean isWritableAccountWithDataSet(String accountTypeAndDataSet) { 720743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (accountTypeAndDataSet == null) { 7208bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov return true; 7209bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov } 7210bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov 721143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Boolean writable = mAccountWritability.get(accountTypeAndDataSet); 721273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable != null) { 721373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 721473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 721573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 7216627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov IContentService contentService = ContentResolver.getContentService(); 7217627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 721843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO(dsantoro): Need to update this logic to allow for sub-accounts. 7219627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) { 7220627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov if (ContactsContract.AUTHORITY.equals(sync.authority) && 722143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountTypeAndDataSet.equals(sync.accountType)) { 722273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = sync.supportsUploading(); 722373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov break; 7224627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7225627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7226627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } catch (RemoteException e) { 7227627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov Log.e(TAG, "Could not acquire sync adapter types"); 7228627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 722973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 723073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable == null) { 723173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = false; 723273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 723373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 723443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mAccountWritability.put(accountTypeAndDataSet, writable); 723573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 7236627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7237b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov 7238d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 7239f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter, 7240f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean defaultValue) { 7241f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7242f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov // Manually parse the query, which is much faster than calling uri.getQueryParameter 7243f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 7244f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 7245f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 7246f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7247f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7248f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = query.indexOf(parameter); 7249f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 7250f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 7251f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7252f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7253f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameter.length(); 7254f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7255f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return !matchQueryParameter(query, index, "=0", false) 7256f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && !matchQueryParameter(query, index, "=false", true); 7257f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7258f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7259f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private static boolean matchQueryParameter(String query, int index, String value, 7260f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean ignoreCase) { 7261f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int length = value.length(); 7262f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return query.regionMatches(ignoreCase, index, value, 0, length) 7263f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && (query.length() == index + length || query.charAt(index + length) == '&'); 7264f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7265f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7266f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /** 7267f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * A fast re-implementation of {@link Uri#getQueryParameter} 7268f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov */ 7269f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static String getQueryParameter(Uri uri, String parameter) { 7270f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 7271f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 7272f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7273f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7274f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7275f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int queryLength = query.length(); 7276f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int parameterLength = parameter.length(); 7277f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7278f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String value; 7279f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = 0; 7280f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov while (true) { 7281f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index = query.indexOf(parameter, index); 7282f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 7283f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 72845fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 72855fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa 72865fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // Should match against the whole parameter instead of its suffix. 72875fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // e.g. The parameter "param" must not be found in "some_param=val". 72885fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (index > 0) { 72895fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa char prevChar = query.charAt(index - 1); 72905fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (prevChar != '?' && prevChar != '&') { 72915fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // With "some_param=val1¶m=val2", we should find second "param" occurrence. 72925fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa index += parameterLength; 72935fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa continue; 72945fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 7295f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7296f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7297f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameterLength; 7298f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7299f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (queryLength == index) { 7300f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7301f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7302f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7303f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query.charAt(index) == '=') { 7304f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index++; 7305f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov break; 7306f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7307f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7308f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7309f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int ampIndex = query.indexOf('&', index); 7310f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (ampIndex == -1) { 7311f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index); 7312f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } else { 7313f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index, ampIndex); 7314f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7315f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7316f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return Uri.decode(value); 7317f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 73185dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 73190dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov protected boolean isAggregationUpgradeNeeded() { 73200dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov if (!mContactAggregator.isEnabled()) { 73210dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return false; 73220dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 73230dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 73245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int version = Integer.parseInt(mContactsHelper.getProperty( 73255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROPERTY_AGGREGATION_ALGORITHM, "1")); 73260dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return version < PROPERTY_AGGREGATION_ALGORITHM_VERSION; 73270dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 73280dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 7329bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void upgradeAggregationAlgorithmInBackground() { 73300dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // This upgrade will affect very few contacts, so it can be performed on the 73310dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov // main thread during the initial boot after an OTA 73320dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 73330dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Upgrading aggregation algorithm"); 73340dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int count = 0; 73350dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long start = SystemClock.currentThreadTimeMillis(); 73365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = null; 73370dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 73385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 73395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db = mContactsHelper.getWritableDatabase(); 73405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(db); 73415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.beginTransaction(); 73425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = db.query(true, 73430dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Tables.RAW_CONTACTS + " r1 JOIN " + Tables.RAW_CONTACTS + " r2", 73440dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov new String[]{"r1." + RawContacts._ID}, 73450dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov "r1." + RawContacts._ID + "!=r2." + RawContacts._ID + 73460dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.CONTACT_ID + "=r2." + RawContacts.CONTACT_ID + 73470dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.ACCOUNT_NAME + "=r2." + RawContacts.ACCOUNT_NAME + 734843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND r1." + RawContacts.ACCOUNT_TYPE + "=r2." + RawContacts.ACCOUNT_TYPE + 734943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " AND r1." + RawContacts.DATA_SET + "=r2." + RawContacts.DATA_SET, 73500dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov null, null, null, null, null); 73510dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 73520dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov while (cursor.moveToNext()) { 73530dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long rawContactId = cursor.getLong(0); 73540dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, 73550dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 73560dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov count++; 73570dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 73580dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 73590dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov cursor.close(); 73600dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 73615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator.aggregateInTransaction(mTransactionContext.get(), db); 7362bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 73635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.setTransactionSuccessful(); 73645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.setProperty(PROPERTY_AGGREGATION_ALGORITHM, 73650dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov String.valueOf(PROPERTY_AGGREGATION_ALGORITHM_VERSION)); 73660dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 73675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (db != null) { 73685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.endTransaction(); 73695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 73700dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long end = SystemClock.currentThreadTimeMillis(); 73710dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Aggregation algorithm upgraded for " + count 73720dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov + " contacts, in " + (end - start) + "ms"); 73730dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 73740dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 73759a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 73769a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov /* Visible for testing */ 73779a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean isPhone() { 73789a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov if (!sIsPhoneInitialized) { 73799a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhone = new TelephonyManager(getContext()).isVoiceCapable(); 73809a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov sIsPhoneInitialized = true; 73819a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 73829a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov return sIsPhone; 73839a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 738446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 738546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private boolean handleDataUsageFeedback(Uri uri) { 738646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final long currentTimeMillis = System.currentTimeMillis(); 738746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 738846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] ids = uri.getLastPathSegment().trim().split(","); 738946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ArrayList<Long> dataIds = new ArrayList<Long>(); 739046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 739146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (String id : ids) { 739246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa dataIds.add(Long.valueOf(id)); 739346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 739446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final boolean successful; 739546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (TextUtils.isEmpty(usageType)) { 739646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.w(TAG, "Method for data usage feedback isn't specified. Ignoring."); 739746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = false; 739846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 739946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = updateDataUsageStat(dataIds, usageType, currentTimeMillis) > 0; 740046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 740146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 740246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Handle old API. This doesn't affect the result of this entire method. 740346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] questionMarks = new String[ids.length]; 740446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Arrays.fill(questionMarks, "?"); 740546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = Data._ID + " IN (" + TextUtils.join(",", questionMarks) + ")"; 74065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final Cursor cursor = mActiveDb.get().query( 7407ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann Views.DATA, 740846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { Data.CONTACT_ID }, 740946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa where, ids, null, null, null); 741046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 741146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa while (cursor.moveToNext()) { 741246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa mSelectionArgs1[0] = cursor.getString(0); 741346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa ContentValues values2 = new ContentValues(); 741446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values2.put(Contacts.LAST_TIME_CONTACTED, currentTimeMillis); 74155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().update(Tables.CONTACTS, values2, Contacts._ID + "=?", 74165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mSelectionArgs1); 74175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 74185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 741946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 742046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 742146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 742246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 742346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 742446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return successful; 742546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 742646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 742746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 742846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Update {@link Tables#DATA_USAGE_STAT}. 742946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * 743046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @return the number of rows affected. 743146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 7432f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa @VisibleForTesting 7433f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa /* package */ int updateDataUsageStat( 7434f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa List<Long> dataIds, String type, long currentTimeMillis) { 743546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final int typeInt = sDataUsageTypeMap.get(type); 743646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String where = DataUsageStatColumns.DATA_ID + " =? AND " 743746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT + " =?"; 743846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] columns = 743946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { DataUsageStatColumns._ID, DataUsageStatColumns.TIMES_USED }; 744046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final ContentValues values = new ContentValues(); 744146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (Long dataId : dataIds) { 744246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] args = new String[] { dataId.toString(), String.valueOf(typeInt) }; 74435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().beginTransaction(); 744446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 74455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final Cursor cursor = mActiveDb.get().query(Tables.DATA_USAGE_STAT, columns, where, 74465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro args, null, null, null); 744746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 744846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (cursor.getCount() > 0) { 744946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!cursor.moveToFirst()) { 745046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.e(TAG, 745146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa "moveToFirst() failed while getAccount() returned non-zero."); 745246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 745346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 745446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, cursor.getInt(1) + 1); 745546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 74565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().update(Tables.DATA_USAGE_STAT, values, 745746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DataUsageStatColumns._ID + " =?", 745846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa new String[] { cursor.getString(0) }); 745946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 746046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 746146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.clear(); 746246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.DATA_ID, dataId); 746346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.USAGE_TYPE_INT, typeInt); 746446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.TIMES_USED, 1); 746546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa values.put(DataUsageStatColumns.LAST_TIME_USED, currentTimeMillis); 74665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().insert(Tables.DATA_USAGE_STAT, null, values); 746746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 74685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().setTransactionSuccessful(); 746946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 747046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa cursor.close(); 747146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 747246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 74735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().endTransaction(); 747446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 747546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 747646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 747746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return dataIds.size(); 747846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 747946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 748046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 748146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Returns a sort order String for promoting data rows (email addresses, phone numbers, etc.) 748246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * associated with a primary account. The primary account should be supplied from applications 748346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * with {@link ContactsContract#PRIMARY_ACCOUNT_NAME} and 748446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * {@link ContactsContract#PRIMARY_ACCOUNT_TYPE}. Null will be returned when the primary 748546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * account isn't available. 748646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 748746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private String getAccountPromotionSortOrder(Uri uri) { 748846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountName = 748946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME); 749046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountType = 749146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE); 749246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 749346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Data rows associated with primary account should be promoted. 749446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountName)) { 749546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa StringBuilder sb = new StringBuilder(); 749646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append("(CASE WHEN " + RawContacts.ACCOUNT_NAME + "="); 749746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountName); 749846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountType)) { 749946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 750046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountType); 750146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 750246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" THEN 0 ELSE 1 END)"); 750346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return sb.toString(); 750446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 750546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return null; 750646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 750746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 75084f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 7509