ContactsProvider2.java revision d364d74ce9cc677c10362b8686d7c33fafe78beb
14f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/*
24f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Copyright (C) 2009 The Android Open Source Project
34f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton *
44f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License");
54f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * you may not use this file except in compliance with the License.
64f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * You may obtain a copy of the License at
74f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton *
84f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton *      http://www.apache.org/licenses/LICENSE-2.0
94f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton *
104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Unless required by applicable law or agreed to in writing, software
114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS,
124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * See the License for the specific language governing permissions and
144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * limitations under the License
154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */
164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarpackage com.android.providers.contacts;
1828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar
1953214b3ed12b0ff9cb589b6559311f2ac142f2e3Bjorn Bringertimport com.android.common.content.SyncStateContentProviderHelper;
205b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport com.android.providers.contacts.ContactAggregator.AggregationSuggestionParameter;
2197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactLookupKey.LookupKeySegment;
2297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns;
2397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns;
2497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Clauses;
2597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns;
2697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsStatusUpdatesColumns;
2797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns;
2897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns;
2997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns;
3097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns;
3197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType;
3297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneColumns;
3397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns;
3497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns;
3597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns;
3697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SettingsColumns;
3797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns;
3897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables;
3997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardComposer;
4097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardConfig;
4197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Lists;
4297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Maps;
4397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Sets;
4497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov
45b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account;
46caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager;
475b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanaimport android.accounts.OnAccountsUpdateListener;
48bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.Notification;
49bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.NotificationManager;
50bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.app.PendingIntent;
51c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager;
52568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation;
53568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult;
546ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.content.ContentResolver;
5535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris;
5667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues;
5767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context;
58627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.IContentService;
59bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.content.Intent;
60568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException;
613d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences;
62627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.SyncAdapterType;
6367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher;
64f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringertimport android.content.res.AssetFileDescriptor;
651129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikovimport android.database.CharArrayBuffer;
664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor;
67ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.database.CursorWrapper;
68ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils;
6909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor;
7009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor.RowBuilder;
714f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase;
7208ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwoodimport android.database.sqlite.SQLiteDoneException;
734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder;
744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri;
75d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.net.Uri.Builder;
7651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikovimport android.os.AsyncTask;
776ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.os.Bundle;
78ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringertimport android.os.ParcelFileDescriptor;
79b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException;
800dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikovimport android.os.SystemClock;
810e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport android.os.SystemProperties;
823d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager;
83508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns;
843de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract;
85b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions;
8697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.BaseTypes;
8797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email;
8897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
8997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im;
9097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname;
9197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization;
9297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone;
9397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo;
9497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
9597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
96ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.provider.ContactsContract.ContactCounts;
973de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Contacts;
985b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.AggregationSuggestions;
993de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Data;
100d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.provider.ContactsContract.Directory;
1015dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport android.provider.ContactsContract.DisplayNameSources;
1025dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport android.provider.ContactsContract.FullNameStyle;
1033de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Groups;
104bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikovimport android.provider.ContactsContract.Intents;
1053de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup;
1065dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport android.provider.ContactsContract.PhoneticNameStyle;
10709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.provider.ContactsContract.ProviderStatus;
1083de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
109916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikovimport android.provider.ContactsContract.SearchSnippetColumns;
1103de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Settings;
11182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikovimport android.provider.ContactsContract.StatusUpdates;
11297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.LiveFolders;
11397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.OpenableColumns;
11497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.SyncStateContract;
115a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils;
116a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils;
117c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log;
1184f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
119d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.ByteArrayOutputStream;
120b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException;
121d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.IOException;
122d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.OutputStream;
12342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.text.SimpleDateFormat;
1247e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList;
1255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections;
12642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.util.Date;
127b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap;
1280e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.HashSet;
1295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List;
130622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkeyimport java.util.Locale;
131b5a4add17815167d20a90645779df34cdf45280dFred Quintanaimport java.util.Map;
1320e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.Set;
133ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch;
1344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
1354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/**
1364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications
1374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}.
1384f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */
1395b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanapublic class ContactsProvider2 extends SQLiteContentProvider implements OnAccountsUpdateListener {
140caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
141bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov    private static final String TAG = "ContactsProvider";
142bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov
143bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov    private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
1444f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
145619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: carefully prevent all incoming nested queries; they can be gaping security holes
146619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // TODO: check for restricted flag during insert(), update(), and delete() calls
147619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
1483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /** Default for the maximum number of returned aggregation suggestions. */
1493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private static final int DEFAULT_MAX_SUGGESTIONS = 5;
1503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1513d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /**
152b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov     * Property key for the legacy contact import version. The need for a version
1533d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * as opposed to a boolean flag is that if we discover bugs in the contact import process,
1543d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     * we can trigger re-import by incrementing the import version.
1553d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov     */
156b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov    private static final String PROPERTY_CONTACTS_IMPORTED = "contacts_imported_v1";
157b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov    private static final int PROPERTY_CONTACTS_IMPORT_VERSION = 1;
15851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov    private static final String PREF_LOCALE = "locale";
1593d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
1600dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov    private static final String PROPERTY_AGGREGATION_ALGORITHM = "aggregation_v2";
1610dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov    private static final int PROPERTY_AGGREGATION_ALGORITHM_VERSION = 2;
1620dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov
1630e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff    private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate";
1640e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff
165a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
1664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
167dd300fe5f5a1071b1c135af7c76e3ae149edda4dDmitri Plotnikov    private static final String TIMES_CONTACTED_SORT_COLUMN = "times_contacted_sort";
1685e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar
169d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final String STREQUENT_ORDER_BY = Contacts.STARRED + " DESC, "
170dd300fe5f5a1071b1c135af7c76e3ae149edda4dDmitri Plotnikov            + TIMES_CONTACTED_SORT_COLUMN + " DESC, "
1719b43551f1ce33b79141772737a262ce609bd0cebMegha Joshi            + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
172d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar    private static final String STREQUENT_LIMIT =
173d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            "(SELECT COUNT(1) FROM " + Tables.CONTACTS + " WHERE "
174d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            + Contacts.STARRED + "=1) + 25";
175d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov
1766e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori    /* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE =
1779b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            "UPDATE " + Tables.CONTACTS + " SET " + Contacts.TIMES_CONTACTED + "=" +
1789b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            " CASE WHEN " + Contacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " +
1799b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            " (" + Contacts.TIMES_CONTACTED + " + 1) END WHERE " + Contacts._ID + "=?";
1809b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori
1816e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori    /* package */ static final String UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE =
1829b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            "UPDATE " + Tables.RAW_CONTACTS + " SET " + RawContacts.TIMES_CONTACTED + "=" +
1839b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            " CASE WHEN " + RawContacts.TIMES_CONTACTED + " IS NULL THEN 1 ELSE " +
1849b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            " (" + RawContacts.TIMES_CONTACTED + " + 1) END WHERE " + RawContacts.CONTACT_ID + "=?";
1859b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori
186de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa    /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK";
187de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa
188d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS = 1000;
189d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private static final int CONTACTS_ID = 1001;
1905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_LOOKUP = 1002;
1915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_LOOKUP_ID = 1003;
192a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private static final int CONTACTS_ID_DATA = 1004;
1935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_FILTER = 1005;
1945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_STREQUENT = 1006;
1955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_STREQUENT_FILTER = 1007;
1965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private static final int CONTACTS_GROUP = 1008;
197a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private static final int CONTACTS_ID_PHOTO = 1009;
198f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey    private static final int CONTACTS_AS_VCARD = 1010;
19942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann    private static final int CONTACTS_AS_MULTI_VCARD = 1011;
2002149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov    private static final int CONTACTS_LOOKUP_DATA = 1012;
2012149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov    private static final int CONTACTS_LOOKUP_ID_DATA = 1013;
202a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private static final int CONTACTS_ID_ENTITIES = 1014;
203a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private static final int CONTACTS_LOOKUP_ENTITIES = 1015;
204a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private static final int CONTACTS_LOOKUP_ID_ENTITIES = 1016;
2054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
2065ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS = 2002;
2075ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_ID = 2003;
2085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    private static final int RAW_CONTACTS_DATA = 2004;
20946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana    private static final int RAW_CONTACT_ENTITY_ID = 2005;
2104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
2116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA = 3000;
2126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int DATA_ID = 3001;
213ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    private static final int PHONES = 3002;
21448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int PHONES_ID = 3003;
21548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int PHONES_FILTER = 3004;
21648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS = 3005;
21748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS_ID = 3006;
21848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS_LOOKUP = 3007;
21948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int EMAILS_FILTER = 3008;
22048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int POSTALS = 3009;
22148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov    private static final int POSTALS_ID = 3010;
222a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2236bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    private static final int PHONE_LOOKUP = 4000;
2246bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
225b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTIONS = 6000;
226b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    private static final int AGGREGATION_EXCEPTION_ID = 6001;
227b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
22882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private static final int STATUS_UPDATES = 7000;
22982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private static final int STATUS_UPDATES_ID = 7001;
2301f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
23131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    private static final int AGGREGATION_SUGGESTIONS = 8000;
23231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
233eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    private static final int SETTINGS = 9000;
234eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
235ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS = 10000;
236ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_ID = 10001;
237ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final int GROUPS_SUMMARY = 10003;
238ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
23935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana    private static final int SYNCSTATE = 11000;
240b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private static final int SYNCSTATE_ID = 11001;
24135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
242c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SUGGESTIONS = 12001;
243c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    private static final int SEARCH_SHORTCUT = 12002;
244c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
2451b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS = 14000;
2461b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_WITH_PHONES = 14001;
2471b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002;
2481b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003;
2491b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
25046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana    private static final int RAW_CONTACT_ENTITIES = 15001;
25146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
25209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov    private static final int PROVIDER_STATUS = 16001;
25309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov
254d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    private static final int DIRECTORIES = 17001;
255d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    private static final int DIRECTORIES_ID = 17002;
256d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
2577a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov    private static final int COMPLETE_NAME = 18000;
2587a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov
259dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private static final String SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID =
260dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            RawContactsColumns.CONCRETE_ID + "=? AND "
261dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + GroupsColumns.CONCRETE_ACCOUNT_NAME
262dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + "=" + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND "
263dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + GroupsColumns.CONCRETE_ACCOUNT_TYPE
264dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + "=" + RawContactsColumns.CONCRETE_ACCOUNT_TYPE
265dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + " AND " + Groups.FAVORITES + " != 0";
266dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
267dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private static final String SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID =
268dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            RawContactsColumns.CONCRETE_ID + "=? AND "
269dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + GroupsColumns.CONCRETE_ACCOUNT_NAME + "="
270dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AND "
271dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "="
272dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AND "
273dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + Groups.AUTO_ADD + " != 0";
274dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
275dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private static final String[] PROJECTION_GROUP_ID
276dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            = new String[]{Tables.GROUPS + "." + Groups._ID};
277dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
278dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private static final String SELECTION_GROUPMEMBERSHIP_DATA = DataColumns.MIMETYPE_ID + "=? "
279dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            + "AND " + GroupMembership.GROUP_ROW_ID + "=? "
280dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            + "AND " + GroupMembership.RAW_CONTACT_ID + "=?";
281dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
282dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private static final String SELECTION_STARRED_FROM_RAW_CONTACTS =
283dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            "SELECT " + RawContacts.STARRED
284dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    + " FROM " + Tables.RAW_CONTACTS + " WHERE " + RawContacts._ID + "=?";
285dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
286d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private interface DataContactsQuery {
287f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov        public static final String TABLE = "data "
288f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) "
289f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)";
29067dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
29167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String[] PROJECTION = new String[] {
2926cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov            RawContactsColumns.CONCRETE_ID,
2933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
294f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov            ContactsColumns.CONCRETE_ID
295ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
296ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
297d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 0;
29867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final int DATA_ID = 1;
299d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        public static final int CONTACT_ID = 2;
300ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
3011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
30214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    private interface DataDeleteQuery {
30367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
3043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
30588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] CONCRETE_COLUMNS = new String[] {
3063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            DataColumns.CONCRETE_ID,
3073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            MimetypesColumns.MIMETYPE,
3085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            Data.RAW_CONTACT_ID,
3093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            Data.IS_PRIMARY,
310f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            Data.DATA1,
31188e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        };
31288e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov
31388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        public static final String[] COLUMNS = new String[] {
31488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data._ID,
31588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            MimetypesColumns.MIMETYPE,
31688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.RAW_CONTACT_ID,
31788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov            Data.IS_PRIMARY,
318f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            Data.DATA1,
3193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        };
3203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
32114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public static final int _ID = 0;
3223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int MIMETYPE = 1;
3235ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 2;
3243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public static final int IS_PRIMARY = 3;
325f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        public static final int DATA1 = 4;
3263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
3273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
32814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    private interface DataUpdateQuery {
329321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        String[] COLUMNS = { Data._ID, Data.RAW_CONTACT_ID, Data.MIMETYPE };
33020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
33120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int _ID = 0;
332321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int RAW_CONTACT_ID = 1;
333321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        int MIMETYPE = 2;
33420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
33520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
336f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
33719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka    private interface RawContactsQuery {
33819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        String TABLE = Tables.RAW_CONTACTS;
33919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka
34019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        String[] COLUMNS = new String[] {
341ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                RawContacts.DELETED,
342ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
343ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
34419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        };
34519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka
34619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        int DELETED = 0;
347ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        int ACCOUNT_TYPE = 1;
348ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        int ACCOUNT_NAME = 2;
34919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka    }
35019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka
351c76cdd0723b99f478c9ba5329d14a971cd8dfb3dCostin Manolache    public static final String DEFAULT_ACCOUNT_TYPE = "com.google";
352df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana    public static final String FEATURE_LEGACY_HOSTED_OR_GOOGLE = "legacy_hosted_or_google";
353caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
35471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov    /** Sql where statement for filtering on groups. */
35571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov    private static final String CONTACTS_IN_GROUP_SELECT =
35671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov            Contacts._ID + " IN "
35771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    + "(SELECT " + RawContacts.CONTACT_ID
35871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    + " FROM " + Tables.RAW_CONTACTS
35971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN "
36071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                            + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID
36171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                            + " FROM " + Tables.DATA_JOIN_MIMETYPES
36271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                            + " WHERE " + Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE
36371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + "' AND " + GroupMembership.GROUP_ROW_ID + "="
36471e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + "(SELECT " + Tables.GROUPS + "." + Groups._ID
36571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + " FROM " + Tables.GROUPS
36671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                                    + " WHERE " + Groups.TITLE + "=?)))";
36771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov
368a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    /** Sql for updating DIRTY flag on multiple raw contacts */
369a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    private static final String UPDATE_RAW_CONTACT_SET_DIRTY_SQL =
370a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            "UPDATE " + Tables.RAW_CONTACTS +
371a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            " SET " + RawContacts.DIRTY + "=1" +
372a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            " WHERE " + RawContacts._ID + " IN (";
373a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov
374a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    /** Sql for updating VERSION on multiple raw contacts */
375a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL =
376a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            "UPDATE " + Tables.RAW_CONTACTS +
377a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            " SET " + RawContacts.VERSION + " = " + RawContacts.VERSION + " + 1" +
378a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            " WHERE " + RawContacts._ID + " IN (";
379a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov
380c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov    // Current contacts - those contacted within the last 3 days (in seconds)
381c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov    private static final long EMAIL_FILTER_CURRENT = 3 * 24 * 60 * 60;
382c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov
383c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov    // Recent contacts - those contacted within the last 30 days (in seconds)
384c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov    private static final long EMAIL_FILTER_RECENT = 30 * 24 * 60 * 60;
385c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov
386c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov    private static final String TIME_SINCE_LAST_CONTACTED =
387c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov            "(strftime('%s', 'now') - " + Contacts.LAST_TIME_CONTACTED + "/1000)";
388c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov
389c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov    /*
390c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov     * Sorting order for email address suggestions: first starred, then the rest.
391c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov     * Within the starred/unstarred groups - three buckets: very recently contacted, then fairly
392c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov     * recently contacted, then the rest.  Within each of the bucket - descending count
393c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov     * of times contacted. If all else fails, alphabetical.  (Super)primary email
394c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov     * address is returned before other addresses for the same contact.
395c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov     */
396c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov    private static final String EMAIL_FILTER_SORT_ORDER =
397c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov            "(CASE WHEN " + Contacts.STARRED + "=1 THEN 0 ELSE 1 END), "
398c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov            + "(CASE WHEN " + TIME_SINCE_LAST_CONTACTED + " < " + EMAIL_FILTER_CURRENT + " THEN 0 "
399c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov            + " WHEN " + TIME_SINCE_LAST_CONTACTED + " < " + EMAIL_FILTER_RECENT + " THEN 1 "
400c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov            + " ELSE 2 END),"
401c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov            + Contacts.TIMES_CONTACTED + " DESC, "
402c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov            + Contacts.DISPLAY_NAME + ", "
403c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov            + Data.CONTACT_ID + ", "
404c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov            + Data.IS_SUPER_PRIMARY + " DESC";
405c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov
406916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov    /** Name lookup types used for contact filtering */
407916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov    private static final String CONTACT_LOOKUP_NAME_TYPES =
408916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov            NameLookupType.NAME_COLLATION_KEY + "," +
409916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov            NameLookupType.EMAIL_BASED_NICKNAME + "," +
410916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov            NameLookupType.NICKNAME + "," +
411916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov            NameLookupType.NAME_SHORTHAND + "," +
412f84478382761d74b9fb98c4189de66002c04cef8Sang-il, Lee            NameLookupType.ORGANIZATION + "," +
413f84478382761d74b9fb98c4189de66002c04cef8Sang-il, Lee            NameLookupType.NAME_CONSONANTS;
414916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
415f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov    /**
416f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov     * If any of these columns are used in a Data projection, there is no point in
417f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov     * using the DISTINCT keyword, which can negatively affect performance.
418f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov     */
419f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov    private static final String[] DISTINCT_DATA_PROHIBITING_COLUMNS = {
420f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov            Data._ID,
421f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov            Data.RAW_CONTACT_ID,
422f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov            Data.NAME_RAW_CONTACT_ID,
423f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov            RawContacts.ACCOUNT_NAME,
424f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov            RawContacts.ACCOUNT_TYPE,
425f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov            RawContacts.DIRTY,
426f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov            RawContacts.NAME_VERIFIED,
427f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov            RawContacts.SOURCE_ID,
428f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov            RawContacts.VERSION,
429f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov    };
430916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
431f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sContactsColumns = ProjectionMap.builder()
432f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CUSTOM_RINGTONE)
433f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.DISPLAY_NAME)
434f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.DISPLAY_NAME_ALTERNATIVE)
435f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.DISPLAY_NAME_SOURCE)
436f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.IN_VISIBLE_GROUP)
437f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.LAST_TIME_CONTACTED)
438f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.LOOKUP_KEY)
439f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.PHONETIC_NAME)
440f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.PHONETIC_NAME_STYLE)
441f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.PHOTO_ID)
4423d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov            .add(Contacts.PHOTO_URI)
4433d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov            .add(Contacts.PHOTO_THUMBNAIL_URI)
444f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.SEND_TO_VOICEMAIL)
445f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.SORT_KEY_ALTERNATIVE)
446f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.SORT_KEY_PRIMARY)
447f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.STARRED)
448f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.TIMES_CONTACTED)
449cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov            .add(Contacts.HAS_PHONE_NUMBER)
450f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
451f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
452f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sContactsPresenceColumns = ProjectionMap.builder()
453f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_PRESENCE,
454f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE)
455f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_CHAT_CAPABILITY,
456f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY)
457f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_STATUS,
458f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    ContactsStatusUpdatesColumns.CONCRETE_STATUS)
459f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_STATUS_TIMESTAMP,
460f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP)
461f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_STATUS_RES_PACKAGE,
462f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE)
463f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_STATUS_LABEL,
464f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL)
465f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_STATUS_ICON,
466f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON)
467f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
468f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
469f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sSnippetColumns = ProjectionMap.builder()
470f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(SearchSnippetColumns.SNIPPET_MIMETYPE)
471f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(SearchSnippetColumns.SNIPPET_DATA_ID)
472f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(SearchSnippetColumns.SNIPPET_DATA1)
473f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(SearchSnippetColumns.SNIPPET_DATA2)
474f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(SearchSnippetColumns.SNIPPET_DATA3)
475f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(SearchSnippetColumns.SNIPPET_DATA4)
476f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
477f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
478f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
479f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sRawContactColumns = ProjectionMap.builder()
480f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.ACCOUNT_NAME)
481f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.ACCOUNT_TYPE)
482f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.DIRTY)
483f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.NAME_VERIFIED)
484f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.SOURCE_ID)
485f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.VERSION)
486f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
487f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
488f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sRawContactSyncColumns = ProjectionMap.builder()
489f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.SYNC1)
490f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.SYNC2)
491f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.SYNC3)
492f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.SYNC4)
493f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
494f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
495f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sDataColumns = ProjectionMap.builder()
496f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA1)
497f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA2)
498f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA3)
499f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA4)
500f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA5)
501f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA6)
502f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA7)
503f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA8)
504f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA9)
505f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA10)
506f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA11)
507f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA12)
508f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA13)
509f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA14)
510f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA15)
511f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.DATA_VERSION)
512f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.IS_PRIMARY)
513f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.IS_SUPER_PRIMARY)
514f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.MIMETYPE)
515f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.RES_PACKAGE)
516f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.SYNC1)
517f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.SYNC2)
518f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.SYNC3)
519f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.SYNC4)
520f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(GroupMembership.GROUP_SOURCE_ID)
521f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
522f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
523f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sContactPresenceColumns = ProjectionMap.builder()
524f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_PRESENCE,
525f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.PRESENCE)
526f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_CHAT_CAPABILITY,
527f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.CHAT_CAPABILITY)
528f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_STATUS,
529f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    ContactsStatusUpdatesColumns.CONCRETE_STATUS)
530f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_STATUS_TIMESTAMP,
531f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP)
532f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_STATUS_RES_PACKAGE,
533f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE)
534f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_STATUS_LABEL,
535f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL)
536f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.CONTACT_STATUS_ICON,
537f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON)
538f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
539f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
540f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sDataPresenceColumns = ProjectionMap.builder()
541f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.PRESENCE, Tables.PRESENCE + "." + StatusUpdates.PRESENCE)
542f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.CHAT_CAPABILITY, Tables.PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY)
543f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.STATUS, StatusUpdatesColumns.CONCRETE_STATUS)
544f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.STATUS_TIMESTAMP, StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP)
545f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.STATUS_RES_PACKAGE, StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE)
546f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.STATUS_LABEL, StatusUpdatesColumns.CONCRETE_STATUS_LABEL)
547f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.STATUS_ICON, StatusUpdatesColumns.CONCRETE_STATUS_ICON)
548f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
549f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
550038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana    /** Contains just BaseColumns._COUNT */
551f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sCountProjectionMap = ProjectionMap.builder()
552f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(BaseColumns._COUNT, "COUNT(*)")
553f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
554f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
555e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov    /** Contains just the contacts columns */
556f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sContactsProjectionMap = ProjectionMap.builder()
557f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts._ID)
558f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.HAS_PHONE_NUMBER)
559f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.NAME_RAW_CONTACT_ID)
560f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactsColumns)
561f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactsPresenceColumns)
562f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
563f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
564916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov    /** Contains just the contacts columns */
565f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sContactsProjectionWithSnippetMap = ProjectionMap.builder()
566f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactsProjectionMap)
567f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sSnippetColumns)
568f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
569916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
5705e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar    /** Used for pushing starred contacts to the top of a times contacted list **/
571f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sStrequentStarredProjectionMap = ProjectionMap.builder()
572f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactsProjectionMap)
573f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(TIMES_CONTACTED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE))
574f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
575f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
576f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder()
577f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactsProjectionMap)
578f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(TIMES_CONTACTED_SORT_COLUMN, Contacts.TIMES_CONTACTED)
579f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
580f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
581f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey    /** Contains just the contacts vCard columns */
582f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sContactsVCardProjectionMap = ProjectionMap.builder()
583f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME + " || '.vcf'")
584f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(OpenableColumns.SIZE, "NULL")
585f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
586f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
587ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    /** Contains just the raw contacts columns */
588f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sRawContactsProjectionMap = ProjectionMap.builder()
589f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts._ID)
590f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.CONTACT_ID)
591f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.DELETED)
592f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.DISPLAY_NAME_PRIMARY)
593f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.DISPLAY_NAME_ALTERNATIVE)
594f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.DISPLAY_NAME_SOURCE)
595f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.PHONETIC_NAME)
596f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.PHONETIC_NAME_STYLE)
597f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.SORT_KEY_PRIMARY)
598f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.SORT_KEY_ALTERNATIVE)
599f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.TIMES_CONTACTED)
600f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.LAST_TIME_CONTACTED)
601f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.CUSTOM_RINGTONE)
602f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.SEND_TO_VOICEMAIL)
603f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.STARRED)
604f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.AGGREGATION_MODE)
605f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sRawContactColumns)
606f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sRawContactSyncColumns)
607f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
608f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
609a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    /** Contains the columns from the raw entity view*/
610f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sRawEntityProjectionMap = ProjectionMap.builder()
611f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts._ID)
612f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.CONTACT_ID)
613f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.Entity.DATA_ID)
614f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.IS_RESTRICTED)
615f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.DELETED)
616f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.STARRED)
617f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sRawContactColumns)
618f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sRawContactSyncColumns)
619f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sDataColumns)
620f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
621f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
622a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    /** Contains the columns from the contact entity view*/
623f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sEntityProjectionMap = ProjectionMap.builder()
624f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.Entity._ID)
625f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.Entity.CONTACT_ID)
626f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.Entity.RAW_CONTACT_ID)
627f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.Entity.DATA_ID)
628f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.Entity.NAME_RAW_CONTACT_ID)
629f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.Entity.DELETED)
630f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Contacts.Entity.IS_RESTRICTED)
631f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactsColumns)
632f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactPresenceColumns)
633f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sRawContactColumns)
634f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sRawContactSyncColumns)
635f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sDataColumns)
636f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sDataPresenceColumns)
637f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
638f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
6394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /** Contains columns from the data view */
640f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sDataProjectionMap = ProjectionMap.builder()
641f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data._ID)
642f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.RAW_CONTACT_ID)
643f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.CONTACT_ID)
644f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data.NAME_RAW_CONTACT_ID)
645f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sDataColumns)
646f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sDataPresenceColumns)
647f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sRawContactColumns)
648f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactsColumns)
649f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactPresenceColumns)
650f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
651f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
6525e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    /** Contains columns from the data view */
653f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sDistinctDataProjectionMap = ProjectionMap.builder()
654f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Data._ID, "MIN(" + Data._ID + ")")
655f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(RawContacts.CONTACT_ID)
656f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sDataColumns)
657f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sDataPresenceColumns)
658f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactsColumns)
659f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sContactPresenceColumns)
660f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
661f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
6629261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /** Contains the data and contacts columns, for joined tables */
663f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sPhoneLookupProjectionMap = ProjectionMap.builder()
664f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup._ID, "contacts_view." + Contacts._ID)
665f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.LOOKUP_KEY, "contacts_view." + Contacts.LOOKUP_KEY)
666f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.DISPLAY_NAME, "contacts_view." + Contacts.DISPLAY_NAME)
667f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.LAST_TIME_CONTACTED, "contacts_view." + Contacts.LAST_TIME_CONTACTED)
668f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.TIMES_CONTACTED, "contacts_view." + Contacts.TIMES_CONTACTED)
669f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.STARRED, "contacts_view." + Contacts.STARRED)
670f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.IN_VISIBLE_GROUP, "contacts_view." + Contacts.IN_VISIBLE_GROUP)
671f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.PHOTO_ID, "contacts_view." + Contacts.PHOTO_ID)
6723d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov            .add(PhoneLookup.PHOTO_URI, "contacts_view." + Contacts.PHOTO_URI)
6733d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov            .add(PhoneLookup.PHOTO_THUMBNAIL_URI, "contacts_view." + Contacts.PHOTO_THUMBNAIL_URI)
674f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.CUSTOM_RINGTONE, "contacts_view." + Contacts.CUSTOM_RINGTONE)
675f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.HAS_PHONE_NUMBER, "contacts_view." + Contacts.HAS_PHONE_NUMBER)
676f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.SEND_TO_VOICEMAIL, "contacts_view." + Contacts.SEND_TO_VOICEMAIL)
677f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.NUMBER, Phone.NUMBER)
678f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.TYPE, Phone.TYPE)
679f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PhoneLookup.LABEL, Phone.LABEL)
6802530512f639c4979fd7371c7dd25dd67e8118124Bai Tao            .add(PhoneLookup.NORMALIZED_NUMBER, Phone.NORMALIZED_NUMBER)
681f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
682f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
683ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains the just the {@link Groups} columns */
684f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sGroupsProjectionMap = ProjectionMap.builder()
685f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups._ID)
686f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.ACCOUNT_NAME)
687f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.ACCOUNT_TYPE)
688f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.SOURCE_ID)
689f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.DIRTY)
690f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.VERSION)
691f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.RES_PACKAGE)
692f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.TITLE)
693f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.TITLE_RES)
694f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.GROUP_VISIBLE)
695f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.SYSTEM_ID)
696f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.DELETED)
697f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.NOTES)
698f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.SHOULD_SYNC)
699f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.FAVORITES)
700f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.AUTO_ADD)
701c039cfb78c40730483fd71178df63ada5826a315Dmitri Plotnikov            .add(Groups.GROUP_IS_READ_ONLY)
702f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.SYNC1)
703f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.SYNC2)
704f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.SYNC3)
705f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.SYNC4)
706f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
707f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
708ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /** Contains {@link Groups} columns along with summary details */
709f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sGroupsSummaryProjectionMap = ProjectionMap.builder()
710f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .addAll(sGroupsProjectionMap)
711f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.SUMMARY_COUNT,
712f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID
713f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS
714f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " WHERE " + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP
715f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " AND " + Clauses.BELONGS_TO_GROUP
716f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + ")")
717f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Groups.SUMMARY_WITH_PHONES,
718f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    "(SELECT COUNT(DISTINCT " + ContactsColumns.CONCRETE_ID
719f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + ") FROM " + Tables.DATA_JOIN_MIMETYPES_RAW_CONTACTS_CONTACTS
720f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " WHERE " + Clauses.MIMETYPE_IS_GROUP_MEMBERSHIP
721f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " AND " + Clauses.BELONGS_TO_GROUP
722f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " AND " + Contacts.HAS_PHONE_NUMBER + ")")
723f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
724f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
725373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov    /** Contains the agg_exceptions columns */
726f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sAggregationExceptionsProjectionMap = ProjectionMap.builder()
727f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id")
728f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(AggregationExceptions.TYPE)
729f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(AggregationExceptions.RAW_CONTACT_ID1)
730f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(AggregationExceptions.RAW_CONTACT_ID2)
731f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
732f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
733eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey    /** Contains the agg_exceptions columns */
734f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sSettingsProjectionMap = ProjectionMap.builder()
735f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Settings.ACCOUNT_NAME)
736f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Settings.ACCOUNT_TYPE)
737f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Settings.UNGROUPED_VISIBLE)
738f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Settings.SHOULD_SYNC)
739f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Settings.ANY_UNSYNCED,
740f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    "(CASE WHEN MIN(" + Settings.SHOULD_SYNC
741f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                        + ",(SELECT "
742f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                                + "(CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL"
743f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                                + " THEN 1"
744f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                                + " ELSE MIN(" + Groups.SHOULD_SYNC + ")"
745f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                                + " END)"
746f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                            + " FROM " + Tables.GROUPS
747f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                            + " WHERE " + GroupsColumns.CONCRETE_ACCOUNT_NAME + "="
748f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                                    + SettingsColumns.CONCRETE_ACCOUNT_NAME
749f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                                + " AND " + GroupsColumns.CONCRETE_ACCOUNT_TYPE + "="
750f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                                    + SettingsColumns.CONCRETE_ACCOUNT_TYPE + "))=0"
751f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " THEN 1"
752f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " ELSE 0"
753f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " END)")
754f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Settings.UNGROUPED_COUNT,
755f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    "(SELECT COUNT(*)"
756f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " FROM (SELECT 1"
757f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                            + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS
758f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                            + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID
759f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                            + " HAVING " + Clauses.HAVING_NO_GROUPS
760f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + "))")
761f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Settings.UNGROUPED_WITH_PHONES,
762f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    "(SELECT COUNT(*)"
763f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " FROM (SELECT 1"
764f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                            + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS
765f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                            + " WHERE " + Contacts.HAS_PHONE_NUMBER
766f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                            + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID
767f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                            + " HAVING " + Clauses.HAVING_NO_GROUPS
768f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + "))")
769f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
770f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
77182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    /** Contains StatusUpdates columns */
772f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sStatusUpdatesProjectionMap = ProjectionMap.builder()
773f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(PresenceColumns.RAW_CONTACT_ID)
774f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.DATA_ID, DataColumns.CONCRETE_ID)
775f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.IM_ACCOUNT)
776f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.IM_HANDLE)
777f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.PROTOCOL)
778f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            // We cannot allow a null in the custom protocol field, because SQLite3 does not
779f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            // properly enforce uniqueness of null values
780f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.CUSTOM_PROTOCOL,
781f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL + "=''"
782f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " THEN NULL"
783f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                    + " ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END)")
784f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.PRESENCE)
785f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.CHAT_CAPABILITY)
786f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.STATUS)
787f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.STATUS_TIMESTAMP)
788f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.STATUS_RES_PACKAGE)
789f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.STATUS_ICON)
790f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(StatusUpdates.STATUS_LABEL)
791f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
792f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
7931b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov    /** Contains Live Folders columns */
794f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sLiveFoldersProjectionMap = ProjectionMap.builder()
795f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(LiveFolders._ID, Contacts._ID)
796f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(LiveFolders.NAME, Contacts.DISPLAY_NAME)
797f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            // TODO: Put contact photo back when we have a way to display a default icon
798f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            // for contacts without a photo
799f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            // .add(LiveFolders.ICON_BITMAP, Photos.DATA)
800f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
801f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov
802d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    /** Contains {@link Directory} columns */
803f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov    private static final ProjectionMap sDirectoryProjectionMap = ProjectionMap.builder()
804f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Directory._ID)
805f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Directory.PACKAGE_NAME)
806f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Directory.TYPE_RESOURCE_ID)
807f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Directory.DISPLAY_NAME)
808f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Directory.DIRECTORY_AUTHORITY)
809f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Directory.ACCOUNT_TYPE)
810f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Directory.ACCOUNT_NAME)
811f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .add(Directory.EXPORT_SUPPORT)
812778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov            .add(Directory.SHORTCUT_SUPPORT)
813778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov            .add(Directory.PHOTO_SUPPORT)
814f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            .build();
8157e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
8169705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    // where clause to update the status_updates table
8179705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE =
8189705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID +
8199705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE +
8209705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE ";
8219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
8222526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov    private static final String[] EMPTY_STRING_ARRAY = new String[0];
8232526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov
824bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov    /**
825bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov     * Notification ID for failure to import contacts.
826bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov     */
827bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov    private static final int LEGACY_IMPORT_FAILED_NOTIFICATION = 1;
82851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov
829f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov    private StringBuilder mSb = new StringBuilder();
8301129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private String[] mSelectionArgs1 = new String[1];
8311129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private String[] mSelectionArgs2 = new String[2];
8322526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov    private ArrayList<String> mSelectionArgs = Lists.newArrayList();
8332526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov
834f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    private Account mAccount;
835f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov
8364f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    static {
8374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        // Contacts URI matching table
838a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final UriMatcher matcher = sUriMatcher;
839d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS);
840d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
841a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA);
842a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES);
8433653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions",
8443653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                AGGREGATION_SUGGESTIONS);
8452d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*",
8462d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                AGGREGATION_SUGGESTIONS);
847a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO);
848c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER);
8495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER);
8505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP);
8512149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA);
8525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID);
8532149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data",
8542149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                CONTACTS_LOOKUP_ID_DATA);
855a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities",
856a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                CONTACTS_LOOKUP_ENTITIES);
857a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities",
858a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                CONTACTS_LOOKUP_ID_ENTITIES);
859f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD);
86042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann        matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*",
86142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                CONTACTS_AS_MULTI_VCARD);
8625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT);
863ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*",
864ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                CONTACTS_STREQUENT_FILTER);
8655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP);
8663653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
8675ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
8685ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);
8695ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA);
87046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ENTITY_ID);
87146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
87246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES);
873b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
8744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
8754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);
876ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES);
87748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID);
8785e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER);
879ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER);
8804a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS);
88148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID);
8821dac83b8fa58944acfd00f44e717a7dddc659d2dDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP);
8835e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP);
8845e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER);
8854a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER);
886ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar        matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS);
88748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID);
8881f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
889ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS);
890ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID);
891ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY);
892ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
89335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE);
894b5a4add17815167d20a90645779df34cdf45280dFred Quintana        matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#",
895b5a4add17815167d20a90645779df34cdf45280dFred Quintana                SYNCSTATE_ID);
89635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
897a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP);
898b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions",
899b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTIONS);
900b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*",
901b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                AGGREGATION_EXCEPTION_ID);
9024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
903eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey        matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS);
904eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
90582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES);
90682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID);
9071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
908c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
909c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
910c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
911c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SUGGESTIONS);
9122d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill        matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*",
913c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                SEARCH_SHORTCUT);
914c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
9151b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts",
9161b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS);
9171b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts/*",
9181b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_GROUP_NAME);
9191b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/contacts_with_phones",
9201b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_WITH_PHONES);
9211b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "live_folders/favorites",
9221b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                LIVE_FOLDERS_CONTACTS_FAVORITES);
92309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov
92409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS);
925d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
926d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES);
927d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID);
9287a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov
9297a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME);
93019a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov    }
93119a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov
932d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    private static class DirectoryInfo {
933d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        String authority;
934d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        String accountName;
935d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        String accountType;
936d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    }
937d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
938d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    /**
939d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov     * Cached information about contact directories.
940d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov     */
9414458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov    private HashMap<String, DirectoryInfo> mDirectoryCache = new HashMap<String, DirectoryInfo>();
9424458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov    private boolean mDirectoryCacheValid = false;
943d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
9443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    /**
9453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     * Handles inserts and update for a specific Data type.
9463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov     */
9473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private abstract class DataRowHandler {
9483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected final String mMimetype;
949653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        protected long mMimetypeId;
9503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
9511129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        @SuppressWarnings("all")
9523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public DataRowHandler(String mimetype) {
9533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mMimetype = mimetype;
954a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka
955a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            // To ensure the data column position. This is dead code if properly configured.
956a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            if (StructuredName.DISPLAY_NAME != Data.DATA1 || Nickname.NAME != Data.DATA1
957a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    || Organization.COMPANY != Data.DATA1 || Phone.NUMBER != Data.DATA1
958a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    || Email.DATA != Data.DATA1) {
959a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                throw new AssertionError("Some of ContactsContract.CommonDataKinds class primary"
960a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                        + " data is not in DATA1 column");
961a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            }
9623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
9633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
964653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        protected long getMimeTypeId() {
965653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (mMimetypeId == 0) {
966b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                mMimetypeId = mDbHelper.getMimeTypeId(mMimetype);
967653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
968653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return mMimetypeId;
969653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
970653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
9713cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
9723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Inserts a row into the {@link Data} table.
9733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
974d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
975d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values) {
976e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            final long dataId = db.insert(Tables.DATA, null, values);
977e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
9786dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            final Integer primary = values.getAsInteger(Data.IS_PRIMARY);
9796dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            final Integer superPrimary = values.getAsInteger(Data.IS_SUPER_PRIMARY);
9806dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            if ((primary != null && primary != 0) || (superPrimary != null && superPrimary != 0)) {
9816dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                final long mimeTypeId = getMimeTypeId();
98278fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId);
9836dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann
9846dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                // We also have to make sure that no other data item on this raw_contact is
9856dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                // configured super primary
9866dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                if (superPrimary != null) {
9876dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    if (superPrimary != 0) {
98878fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                        mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
9896dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    } else {
99078fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                        mDbHelper.clearSuperPrimary(rawContactId, mimeTypeId);
9916dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    }
9926dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                } else {
9936dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    // if there is already another data item configured as super-primary,
9946dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    // take over the flag (which will automatically remove it from the other item)
995189273b8a9ae75d88690febfbed2d635138799ecDmitri Plotnikov                    if (mDbHelper.rawContactHasSuperPrimary(rawContactId, mimeTypeId)) {
99678fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                        mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
9976dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    }
9986dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                }
999e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
1000e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1001e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return dataId;
10023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
10053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * Validates data and updates a {@link Data} row using the cursor, which contains
10063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         * the current data.
1007813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov         *
1008813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov         * @return true if update changed something
10093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
1010d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public boolean update(SQLiteDatabase db, TransactionContext txContext,
1011d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values, Cursor c, boolean callerIsSyncAdapter) {
101214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
101314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1014653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
10156dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            handlePrimaryAndSuperPrimary(values, dataId, rawContactId);
1016653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1017653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (values.size() > 0) {
10184da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                mSelectionArgs1[0] = String.valueOf(dataId);
1019189273b8a9ae75d88690febfbed2d635138799ecDmitri Plotnikov                db.update(Tables.DATA, values, Data._ID + " =?", mSelectionArgs1);
1020653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1021653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1022f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            if (!callerIsSyncAdapter) {
1023d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                txContext.markRawContactDirty(rawContactId);
1024653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1025813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov
1026813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return true;
10273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
10283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
10296dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann        /**
10306dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann         * Ensures that all super-primary and primary flags of this raw_contact are
10316dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann         * configured correctly
10326dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann         */
10336dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann        private void handlePrimaryAndSuperPrimary(ContentValues values, long dataId,
10346dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                long rawContactId) {
10356dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            final boolean hasPrimary = values.containsKey(Data.IS_PRIMARY);
10366dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            final boolean hasSuperPrimary = values.containsKey(Data.IS_SUPER_PRIMARY);
10376dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann
10386dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            // Nothing to do? Bail out early
10396dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            if (!hasPrimary && !hasSuperPrimary) return;
10406dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann
10416dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            final long mimeTypeId = getMimeTypeId();
10426dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann
10436dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            // Check if we want to clear values
10446dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            final boolean clearPrimary = hasPrimary &&
10456dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    values.getAsInteger(Data.IS_PRIMARY) == 0;
10466dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            final boolean clearSuperPrimary = hasSuperPrimary &&
10476dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    values.getAsInteger(Data.IS_SUPER_PRIMARY) == 0;
10486dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann
10496dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            if (clearPrimary || clearSuperPrimary) {
10506dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                // Test whether these values are currently set
1051189273b8a9ae75d88690febfbed2d635138799ecDmitri Plotnikov                mSelectionArgs1[0] = String.valueOf(dataId);
10526dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                final String[] cols = new String[] { Data.IS_PRIMARY, Data.IS_SUPER_PRIMARY };
1053189273b8a9ae75d88690febfbed2d635138799ecDmitri Plotnikov                final Cursor c = mDbHelper.getReadableDatabase().query(Tables.DATA,
1054189273b8a9ae75d88690febfbed2d635138799ecDmitri Plotnikov                        cols, Data._ID + "=?", mSelectionArgs1, null, null, null);
10556dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                try {
10566dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    if (c.moveToFirst()) {
10576dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                        final boolean isPrimary = c.getInt(0) != 0;
10586dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                        final boolean isSuperPrimary = c.getInt(1) != 0;
10596dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                        // Clear values if they are currently set
10606dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                        if (isSuperPrimary) {
106178fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                            mDbHelper.clearSuperPrimary(rawContactId, mimeTypeId);
10626dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                        }
10636dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                        if (clearPrimary && isPrimary) {
106478fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                            mDbHelper.setIsPrimary(rawContactId, -1, mimeTypeId);
10656dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                        }
10666dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    }
10676dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                } finally {
10686dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    c.close();
10696dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                }
10706dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            } else {
10716dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                // Check if we want to set values
10726dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                final boolean setPrimary = hasPrimary &&
10736dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                        values.getAsInteger(Data.IS_PRIMARY) != 0;
10746dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                final boolean setSuperPrimary = hasSuperPrimary &&
10756dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                        values.getAsInteger(Data.IS_SUPER_PRIMARY) != 0;
10766dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                if (setSuperPrimary) {
10776dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    // Set both super primary and primary
107878fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                    mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
107978fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                    mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId);
10806dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                } else if (setPrimary) {
108178fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                    // Primary was explicitly set, but super-primary was not.
10826dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    // In this case we set super-primary on this data item, if
10836dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    // any data item of the same raw-contact already is super-primary
1084189273b8a9ae75d88690febfbed2d635138799ecDmitri Plotnikov                    if (mDbHelper.rawContactHasSuperPrimary(rawContactId, mimeTypeId)) {
108578fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                        mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
10866dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                    }
108778fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                    mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId);
10886dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann                }
10896dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            }
10906dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann
10916dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            // Now that we've taken care of clearing this, remove it from "values".
10926dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            values.remove(Data.IS_SUPER_PRIMARY);
10936dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann            values.remove(Data.IS_PRIMARY);
10946dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann        }
10956dd371aea88e09cbe56b8c483021f3bf61527331Daniel Lehmann
1096d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
109714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
109814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
109914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            boolean primary = c.getInt(DataDeleteQuery.IS_PRIMARY) != 0;
11004da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(dataId);
11014da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            int count = db.delete(Tables.DATA, Data._ID + "=?", mSelectionArgs1);
11024da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(rawContactId);
11034da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            db.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=?", mSelectionArgs1);
11043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            if (count != 0 && primary) {
11055ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                fixPrimary(db, rawContactId);
11063cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
11073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            return count;
11083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11105ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        private void fixPrimary(SQLiteDatabase db, long rawContactId) {
11114da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            long mimeTypeId = getMimeTypeId();
1112e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            long primaryId = -1;
1113e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            int primaryType = -1;
11144da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(rawContactId);
11154da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            Cursor c = db.query(DataDeleteQuery.TABLE,
11164da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    DataDeleteQuery.CONCRETE_COLUMNS,
11174da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    Data.RAW_CONTACT_ID + "=?" +
11184da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        " AND " + DataColumns.MIMETYPE_ID + "=" + mimeTypeId,
11194da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    mSelectionArgs1, null, null, null);
11203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            try {
1121e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                while (c.moveToNext()) {
112214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                    long dataId = c.getLong(DataDeleteQuery._ID);
1123f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                    int type = c.getInt(DataDeleteQuery.DATA1);
1124e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) {
1125e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryId = dataId;
1126e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                        primaryType = type;
1127e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                    }
11283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                }
11293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            } finally {
11303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                c.close();
11313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
11324da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            if (primaryId != -1) {
113378fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                mDbHelper.setIsPrimary(rawContactId, primaryId, mimeTypeId);
11344da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            }
1135e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1136e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1137e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        /**
1138e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * Returns the rank of a specific record type to be used in determining the primary
1139e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         * row. Lower number represents higher priority.
1140e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov         */
1141e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
1142e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            return 0;
11433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1145d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        protected void fixRawContactDisplayName(SQLiteDatabase db, TransactionContext txContext,
1146d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                long rawContactId) {
1147d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            if (!isNewRawContact(txContext, rawContactId)) {
1148d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov                updateRawContactDisplayName(db, rawContactId);
1149fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                mContactAggregator.updateDisplayNameForRawContact(db, rawContactId);
1150285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
11513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
1152a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1153d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        private boolean isNewRawContact(TransactionContext txContext, long rawContactId) {
1154d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            return txContext.isNewRawContact(rawContactId);
1155d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        }
1156d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov
1157622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1158622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Return set of values, using current values at given {@link Data#_ID}
1159813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov         * as baseline, but augmented with any updates.  Returns null if there is
1160813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov         * no change.
1161622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1162622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public ContentValues getAugmentedValues(SQLiteDatabase db, long dataId,
1163622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                ContentValues update) {
1164813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            boolean changing = false;
1165622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues values = new ContentValues();
11664da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(dataId);
11674da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            final Cursor cursor = db.query(Tables.DATA, null, Data._ID + "=?",
11684da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    mSelectionArgs1, null, null, null);
1169622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            try {
1170622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                if (cursor.moveToFirst()) {
1171622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                    for (int i = 0; i < cursor.getColumnCount(); i++) {
1172622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                        final String key = cursor.getColumnName(i);
1173813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                        final String value = cursor.getString(i);
1174813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                        if (!changing && update.containsKey(key)) {
1175813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                            Object newValue = update.get(key);
1176813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                            String newString = newValue == null ? null : newValue.toString();
1177813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                            changing |= !TextUtils.equals(newString, value);
1178813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                        }
1179813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                        values.put(key, value);
1180622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                    }
1181622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                }
1182622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            } finally {
1183622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                cursor.close();
1184622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
1185813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            if (!changing) {
1186813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                return null;
1187813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
1188813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov
1189622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            values.putAll(update);
1190622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            return values;
1191622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
11923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
11933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CustomDataRowHandler extends DataRowHandler {
11953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
11963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CustomDataRowHandler(String mimetype) {
11973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
11983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
11993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
12003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class StructuredNameRowHandler extends DataRowHandler {
1202622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private final NameSplitter mSplitter;
12033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1204622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public StructuredNameRowHandler(NameSplitter splitter) {
12053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(StructuredName.CONTENT_ITEM_TYPE);
1206622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            mSplitter = splitter;
12073cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
12083cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12093cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
1210d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
1211d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values) {
1212622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredNameComponents(values, values);
121314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1214d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            long dataId = super.insert(db, txContext, rawContactId, values);
121514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1216f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            String name = values.getAsString(StructuredName.DISPLAY_NAME);
1217d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov            Integer fullNameStyle = values.getAsInteger(StructuredName.FULL_NAME_STYLE);
1218d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov            insertNameLookupForStructuredName(rawContactId, dataId, name,
121951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov                    fullNameStyle != null
122051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov                            ? mNameSplitter.getAdjustedFullNameStyle(fullNameStyle)
122151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov                            : FullNameStyle.UNDEFINED);
122248786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov            insertNameLookupForPhoneticName(rawContactId, dataId, values);
1223d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            fixRawContactDisplayName(db, txContext, rawContactId);
1224813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            triggerAggregation(rawContactId);
122514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
122614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
122714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
122814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
1229d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
1230d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                Cursor c, boolean callerIsSyncAdapter) {
1231622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long dataId = c.getLong(DataUpdateQuery._ID);
1232622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1233cabac02a2416b495e030654accffcbb5ae526678Dmitri Plotnikov
1234622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues augmented = getAugmentedValues(db, dataId, values);
1235813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            if (augmented == null) {  // No change
1236813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                return false;
1237813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
1238813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov
1239622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredNameComponents(augmented, values);
124014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1241d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            super.update(db, txContext, values, c, callerIsSyncAdapter);
12427ceafd016eb07d2de808d18cd5a9463efaee781dDmitri Plotnikov            if (values.containsKey(StructuredName.DISPLAY_NAME) ||
12437ceafd016eb07d2de808d18cd5a9463efaee781dDmitri Plotnikov                    values.containsKey(StructuredName.PHONETIC_FAMILY_NAME) ||
12447ceafd016eb07d2de808d18cd5a9463efaee781dDmitri Plotnikov                    values.containsKey(StructuredName.PHONETIC_MIDDLE_NAME) ||
12457ceafd016eb07d2de808d18cd5a9463efaee781dDmitri Plotnikov                    values.containsKey(StructuredName.PHONETIC_GIVEN_NAME)) {
12467ceafd016eb07d2de808d18cd5a9463efaee781dDmitri Plotnikov                augmented.putAll(values);
12477ceafd016eb07d2de808d18cd5a9463efaee781dDmitri Plotnikov                String name = augmented.getAsString(StructuredName.DISPLAY_NAME);
124878fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                mDbHelper.deleteNameLookup(dataId);
12497ceafd016eb07d2de808d18cd5a9463efaee781dDmitri Plotnikov                Integer fullNameStyle = augmented.getAsInteger(StructuredName.FULL_NAME_STYLE);
1250d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov                insertNameLookupForStructuredName(rawContactId, dataId, name,
125151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov                        fullNameStyle != null
125251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov                                ? mNameSplitter.getAdjustedFullNameStyle(fullNameStyle)
125351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov                                : FullNameStyle.UNDEFINED);
12547ceafd016eb07d2de808d18cd5a9463efaee781dDmitri Plotnikov                insertNameLookupForPhoneticName(rawContactId, dataId, augmented);
125514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            }
1256d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            fixRawContactDisplayName(db, txContext, rawContactId);
1257813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            triggerAggregation(rawContactId);
1258813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return true;
125914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
126014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
126114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
1262d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
126314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
126414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
126514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1266d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            int count = super.delete(db, txContext, c);
126714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
126878fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov            mDbHelper.deleteNameLookup(dataId);
1269d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            fixRawContactDisplayName(db, txContext, rawContactId);
1270813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            triggerAggregation(rawContactId);
127114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
12723cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
12733cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
12743cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        /**
1275622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Specific list of structured fields.
12763cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov         */
1277622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private final String[] STRUCTURED_FIELDS = new String[] {
1278622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredName.PREFIX, StructuredName.GIVEN_NAME, StructuredName.MIDDLE_NAME,
1279622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredName.FAMILY_NAME, StructuredName.SUFFIX
1280622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        };
12813cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1282622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1283622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Parses the supplied display name, but only if the incoming values do
1284622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * not already contain structured name parts. Also, if the display name
1285622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * is not provided, generate one by concatenating first name and last
1286622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * name.
1287622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
12887a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        public void fixStructuredNameComponents(ContentValues augmented, ContentValues update) {
128967c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final String unstruct = update.getAsString(StructuredName.DISPLAY_NAME);
1290622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
129167c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final boolean touchedUnstruct = !TextUtils.isEmpty(unstruct);
129267c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final boolean touchedStruct = !areAllEmpty(update, STRUCTURED_FIELDS);
1293622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1294622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            if (touchedUnstruct && !touchedStruct) {
12958c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                NameSplitter.Name name = new NameSplitter.Name();
1296622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                mSplitter.split(name, unstruct);
1297622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                name.toValues(update);
129867c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            } else if (!touchedUnstruct
129967c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                    && (touchedStruct || areAnySpecified(update, STRUCTURED_FIELDS))) {
130067c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                // We need to update the display name when any structured components
130167c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                // are specified, even when they are null, which is why we are checking
130267c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                // areAnySpecified.  The touchedStruct in the condition is an optimization:
130367c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                // if there are non-null values, we know for a fact that some values are present.
13048c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                NameSplitter.Name name = new NameSplitter.Name();
1305622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                name.fromValues(augmented);
13064cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                // As the name could be changed, let's guess the name style again.
13074cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                name.fullNameStyle = FullNameStyle.UNDEFINED;
13084cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                mSplitter.guessNameStyle(name);
1309ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao                int unadjustedFullNameStyle = name.fullNameStyle;
1310ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao                name.fullNameStyle = mSplitter.getAdjustedFullNameStyle(name.fullNameStyle);
13115dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                final String joined = mSplitter.join(name, true);
1312622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                update.put(StructuredName.DISPLAY_NAME, joined);
13135dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
1314ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao                update.put(StructuredName.FULL_NAME_STYLE, unadjustedFullNameStyle);
13155dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                update.put(StructuredName.PHONETIC_NAME_STYLE, name.phoneticNameStyle);
13164cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao            } else if (touchedUnstruct && touchedStruct){
1317d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov                if (!update.containsKey(StructuredName.FULL_NAME_STYLE)) {
1318d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov                    update.put(StructuredName.FULL_NAME_STYLE,
1319d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov                            mSplitter.guessFullNameStyle(unstruct));
13204cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                }
1321d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov                if (!update.containsKey(StructuredName.PHONETIC_NAME_STYLE)) {
1322d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov                    update.put(StructuredName.PHONETIC_NAME_STYLE,
1323d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov                            mSplitter.guessPhoneticNameStyle(unstruct));
13244cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao                }
1325622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
1326622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1327622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    }
1328622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1329622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    public class StructuredPostalRowHandler extends DataRowHandler {
1330622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private PostalSplitter mSplitter;
1331622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1332622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        public StructuredPostalRowHandler(PostalSplitter splitter) {
1333622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            super(StructuredPostal.CONTENT_ITEM_TYPE);
1334622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            mSplitter = splitter;
1335622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1336622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1337622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        @Override
1338d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
1339d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values) {
1340622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredPostalComponents(values, values);
1341d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            return super.insert(db, txContext, rawContactId, values);
1342622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1343622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1344622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        @Override
1345d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
1346d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                Cursor c, boolean callerIsSyncAdapter) {
1347622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long dataId = c.getLong(DataUpdateQuery._ID);
1348622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues augmented = getAugmentedValues(db, dataId, values);
1349813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            if (augmented == null) {    // No change
1350813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                return false;
1351813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
1352813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov
1353622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            fixStructuredPostalComponents(augmented, values);
1354d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            super.update(db, txContext, values, c, callerIsSyncAdapter);
1355813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return true;
1356622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
1357622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1358622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1359622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Specific list of structured fields.
1360622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1361622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private final String[] STRUCTURED_FIELDS = new String[] {
1362622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredPostal.STREET, StructuredPostal.POBOX, StructuredPostal.NEIGHBORHOOD,
1363622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredPostal.CITY, StructuredPostal.REGION, StructuredPostal.POSTCODE,
1364622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                StructuredPostal.COUNTRY,
1365622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        };
1366622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1367622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1368622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * Prepares the given {@link StructuredPostal} row, building
1369622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * {@link StructuredPostal#FORMATTED_ADDRESS} to match the structured
1370622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * values when missing. When structured components are missing, the
1371622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * unstructured value is assigned to {@link StructuredPostal#STREET}.
1372622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1373622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private void fixStructuredPostalComponents(ContentValues augmented, ContentValues update) {
137467c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final String unstruct = update.getAsString(StructuredPostal.FORMATTED_ADDRESS);
137567c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov
137667c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final boolean touchedUnstruct = !TextUtils.isEmpty(unstruct);
137767c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            final boolean touchedStruct = !areAllEmpty(update, STRUCTURED_FIELDS);
1378622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1379622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final PostalSplitter.Postal postal = new PostalSplitter.Postal();
1380622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1381622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            if (touchedUnstruct && !touchedStruct) {
1382622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                mSplitter.split(postal, unstruct);
1383622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                postal.toValues(update);
138467c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            } else if (!touchedUnstruct
138567c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                    && (touchedStruct || areAnySpecified(update, STRUCTURED_FIELDS))) {
138667c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                // See comment in
1387622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                postal.fromValues(augmented);
1388622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                final String joined = mSplitter.join(postal);
1389622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                update.put(StructuredPostal.FORMATTED_ADDRESS, joined);
13903cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
13913cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
13923cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
13933cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
13943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class CommonDataRowHandler extends DataRowHandler {
13953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
13963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mTypeColumn;
13973cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        private final String mLabelColumn;
13983cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
13993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public CommonDataRowHandler(String mimetype, String typeColumn, String labelColumn) {
14003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(mimetype);
14013cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mTypeColumn = typeColumn;
14023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mLabelColumn = labelColumn;
14033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
14043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
14053cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
1406d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
1407d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values) {
1408622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            enforceTypeAndLabel(values, values);
1409d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            return super.insert(db, txContext, rawContactId, values);
1410622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
14113cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1412622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        @Override
1413d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
1414d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                Cursor c, boolean callerIsSyncAdapter) {
1415622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final long dataId = c.getLong(DataUpdateQuery._ID);
1416622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final ContentValues augmented = getAugmentedValues(db, dataId, values);
1417813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            if (augmented == null) {        // No change
1418813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                return false;
1419813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
1420622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            enforceTypeAndLabel(augmented, values);
1421d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            return super.update(db, txContext, values, c, callerIsSyncAdapter);
1422622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
14233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1424622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        /**
1425622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * If the given {@link ContentValues} defines {@link #mTypeColumn},
1426622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * enforce that {@link #mLabelColumn} only appears when type is
1427622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         * {@link BaseTypes#TYPE_CUSTOM}. Exception is thrown otherwise.
1428622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey         */
1429622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        private void enforceTypeAndLabel(ContentValues augmented, ContentValues update) {
1430622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final boolean hasType = !TextUtils.isEmpty(augmented.getAsString(mTypeColumn));
1431622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            final boolean hasLabel = !TextUtils.isEmpty(augmented.getAsString(mLabelColumn));
14323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1433622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            if (hasLabel && !hasType) {
1434622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                // When label exists, assert that some type is defined
1435622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                throw new IllegalArgumentException(mTypeColumn + " must be specified when "
1436622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey                        + mLabelColumn + " is defined.");
1437622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
14383cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
14393cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
14403cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
14413cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class OrganizationDataRowHandler extends CommonDataRowHandler {
14423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
14433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public OrganizationDataRowHandler() {
14443cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Organization.CONTENT_ITEM_TYPE, Organization.TYPE, Organization.LABEL);
14453cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
14463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
14473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
1448d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
1449d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values) {
1450a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String company = values.getAsString(Organization.COMPANY);
1451a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String title = values.getAsString(Organization.TITLE);
1452a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka
1453d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            long dataId = super.insert(db, txContext, rawContactId, values);
1454a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka
1455d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            fixRawContactDisplayName(db, txContext, rawContactId);
1456a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            insertNameLookupForOrganization(rawContactId, dataId, company, title);
1457a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            return dataId;
14583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
14593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
14603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
1461d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
1462d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                Cursor c, boolean callerIsSyncAdapter) {
1463d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            if (!super.update(db, txContext, values, c, callerIsSyncAdapter)) {
1464813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                return false;
1465813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
146614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
146731168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov            boolean containsCompany = values.containsKey(Organization.COMPANY);
146831168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov            boolean containsTitle = values.containsKey(Organization.TITLE);
146931168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov            if (containsCompany || containsTitle) {
1470813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                long dataId = c.getLong(DataUpdateQuery._ID);
1471813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1472813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov
147331168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                String company;
147431168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov
147531168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                if (containsCompany) {
147631168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    company = values.getAsString(Organization.COMPANY);
147731168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                } else {
147831168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    mSelectionArgs1[0] = String.valueOf(dataId);
147931168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    company = DatabaseUtils.stringForQuery(db,
148031168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            "SELECT " + Organization.COMPANY +
148131168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            " FROM " + Tables.DATA +
148231168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            " WHERE " + Data._ID + "=?", mSelectionArgs1);
148331168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                }
148431168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov
148531168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                String title;
148631168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                if (containsTitle) {
148731168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    title = values.getAsString(Organization.TITLE);
148831168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                } else {
148931168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    mSelectionArgs1[0] = String.valueOf(dataId);
149031168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                    title = DatabaseUtils.stringForQuery(db,
149131168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            "SELECT " + Organization.TITLE +
149231168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            " FROM " + Tables.DATA +
149331168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                            " WHERE " + Data._ID + "=?", mSelectionArgs1);
149431168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                }
149531168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov
149678fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                mDbHelper.deleteNameLookup(dataId);
149731168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov                insertNameLookupForOrganization(rawContactId, dataId, company, title);
149831168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov
1499d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                fixRawContactDisplayName(db, txContext, rawContactId);
150031168f49a3da9b9a9d5346f3d6a8098b76179c9cDmitri Plotnikov            }
1501813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return true;
150214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
150314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
150414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
1505d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
1506a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            long dataId = c.getLong(DataUpdateQuery._ID);
150714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
150814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1509d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            int count = super.delete(db, txContext, c);
1510d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            fixRawContactDisplayName(db, txContext, rawContactId);
151178fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov            mDbHelper.deleteNameLookup(dataId);
151214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
151314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
151414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
151514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
15163cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
15173cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
15183cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_WORK: return 0;
15193cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_CUSTOM: return 1;
15203cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Organization.TYPE_OTHER: return 2;
15213cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
15223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
15233cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
15243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
15253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1526e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    public class EmailDataRowHandler extends CommonDataRowHandler {
1527e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1528e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        public EmailDataRowHandler() {
1529e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            super(Email.CONTENT_ITEM_TYPE, Email.TYPE, Email.LABEL);
1530e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1531e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1532e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
1533d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
1534d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values) {
1535813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            String email = values.getAsString(Email.DATA);
153614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1537d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            long dataId = super.insert(db, txContext, rawContactId, values);
153814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1539d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            fixRawContactDisplayName(db, txContext, rawContactId);
1540813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            String address = insertNameLookupForEmail(rawContactId, dataId, email);
1541813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            if (address != null) {
1542813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                triggerAggregation(rawContactId);
1543813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
154414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
154514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
154614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
154714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
1548d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
1549d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                Cursor c, boolean callerIsSyncAdapter) {
1550d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            if (!super.update(db, txContext, values, c, callerIsSyncAdapter)) {
1551813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                return false;
1552813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
155314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1554b06484032125877d1a89785a1a912ca58c12d448Dmitri Plotnikov            if (values.containsKey(Email.DATA)) {
1555813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                long dataId = c.getLong(DataUpdateQuery._ID);
1556813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1557813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov
1558b06484032125877d1a89785a1a912ca58c12d448Dmitri Plotnikov                String address = values.getAsString(Email.DATA);
155978fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                mDbHelper.deleteNameLookup(dataId);
1560b06484032125877d1a89785a1a912ca58c12d448Dmitri Plotnikov                insertNameLookupForEmail(rawContactId, dataId, address);
1561d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                fixRawContactDisplayName(db, txContext, rawContactId);
1562813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                triggerAggregation(rawContactId);
1563b06484032125877d1a89785a1a912ca58c12d448Dmitri Plotnikov            }
1564813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov
1565813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return true;
156614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
156714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
156814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
1569d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
157014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
157114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
157214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1573d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            int count = super.delete(db, txContext, c);
157414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
157578fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov            mDbHelper.deleteNameLookup(dataId);
1576d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            fixRawContactDisplayName(db, txContext, rawContactId);
1577813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            triggerAggregation(rawContactId);
157814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
1579e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1580e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
1581e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        @Override
1582e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        protected int getTypeRank(int type) {
1583e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            switch (type) {
1584e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_HOME: return 0;
1585e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_WORK: return 1;
1586e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_CUSTOM: return 2;
1587e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                case Email.TYPE_OTHER: return 3;
1588e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov                default: return 1000;
1589e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
1590e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov        }
1591e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov    }
1592e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov
159314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    public class NicknameDataRowHandler extends CommonDataRowHandler {
159414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
159514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        public NicknameDataRowHandler() {
159614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            super(Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE, Nickname.LABEL);
159714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
159814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
159914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
1600d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
1601d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values) {
160214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String nickname = values.getAsString(Nickname.NAME);
160314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1604d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            long dataId = super.insert(db, txContext, rawContactId, values);
160514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1606813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            if (!TextUtils.isEmpty(nickname)) {
1607d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                fixRawContactDisplayName(db, txContext, rawContactId);
1608813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                insertNameLookupForNickname(rawContactId, dataId, nickname);
1609813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                triggerAggregation(rawContactId);
1610813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
161114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return dataId;
161214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
161314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
161414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
1615d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
1616d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                Cursor c, boolean callerIsSyncAdapter) {
161714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataUpdateQuery._ID);
161814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
161914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1620d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            if (!super.update(db, txContext, values, c, callerIsSyncAdapter)) {
1621813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                return false;
1622813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
162314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1624b06484032125877d1a89785a1a912ca58c12d448Dmitri Plotnikov            if (values.containsKey(Nickname.NAME)) {
1625b06484032125877d1a89785a1a912ca58c12d448Dmitri Plotnikov                String nickname = values.getAsString(Nickname.NAME);
162678fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                mDbHelper.deleteNameLookup(dataId);
1627b06484032125877d1a89785a1a912ca58c12d448Dmitri Plotnikov                insertNameLookupForNickname(rawContactId, dataId, nickname);
1628d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                fixRawContactDisplayName(db, txContext, rawContactId);
1629813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                triggerAggregation(rawContactId);
1630b06484032125877d1a89785a1a912ca58c12d448Dmitri Plotnikov            }
1631813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov
1632813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return true;
163314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
163414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
163514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
1636d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
163714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
163814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
163914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1640d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            int count = super.delete(db, txContext, c);
164114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
164278fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov            mDbHelper.deleteNameLookup(dataId);
1643d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            fixRawContactDisplayName(db, txContext, rawContactId);
1644813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            triggerAggregation(rawContactId);
164514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
164614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
164714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov    }
164814bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
16493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    public class PhoneDataRowHandler extends CommonDataRowHandler {
16503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
16513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        public PhoneDataRowHandler() {
16523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            super(Phone.CONTENT_ITEM_TYPE, Phone.TYPE, Phone.LABEL);
16533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
16543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
16553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
1656d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
1657d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values) {
16580b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            long dataId;
16590b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
16600b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov                String number = values.getAsString(Phone.NUMBER);
16616206cd7e15b1fe63b72cc9ba32a4d84c764963ceDmitri Plotnikov
1662d015a8321fb9dcbfa96becb909145dfcce3da608Bai Tao                String numberE164 =
1663d015a8321fb9dcbfa96becb909145dfcce3da608Bai Tao                        PhoneNumberUtils.formatNumberToE164(number, getCurrentCountryIso());
1664892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                if (numberE164 != null) {
1665892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    values.put(PhoneColumns.NORMALIZED_NUMBER, numberE164);
1666892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                }
1667d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                dataId = super.insert(db, txContext, rawContactId, values);
1668653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1669892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                updatePhoneLookup(db, rawContactId, dataId, number, numberE164);
1670285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateHasPhoneNumber(db, rawContactId);
1671d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                fixRawContactDisplayName(db, txContext, rawContactId);
1672892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                if (numberE164 != null) {
1673813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                    triggerAggregation(rawContactId);
1674813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                }
16750b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            } else {
1676d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                dataId = super.insert(db, txContext, rawContactId, values);
16770b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            }
1678653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return dataId;
1679653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1680653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1681653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1682d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
1683d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                Cursor c, boolean callerIsSyncAdapter) {
1684813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            String number = null;
1685813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            String normalizedNumber = null;
1686892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov            String numberE164 = null;
16870b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
1688813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                number = values.getAsString(Phone.NUMBER);
1689892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                if (number != null) {
1690892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    numberE164 =
1691892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                        PhoneNumberUtils.formatNumberToE164(number, getCurrentCountryIso());
1692892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                }
1693892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                if (numberE164 != null) {
1694892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    values.put(PhoneColumns.NORMALIZED_NUMBER, numberE164);
1695892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                }
1696813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
1697653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1698d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            if (!super.update(db, txContext, values, c, callerIsSyncAdapter)) {
1699813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                return false;
1700813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
1701653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1702813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            if (values.containsKey(Phone.NUMBER)) {
1703813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                long dataId = c.getLong(DataUpdateQuery._ID);
1704813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1705892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                updatePhoneLookup(db, rawContactId, dataId, number, numberE164);
1706285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updateHasPhoneNumber(db, rawContactId);
1707d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                fixRawContactDisplayName(db, txContext, rawContactId);
1708813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                triggerAggregation(rawContactId);
17090b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov            }
1710813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return true;
171114bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        }
171214bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
171314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        @Override
1714d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
171514bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long dataId = c.getLong(DataDeleteQuery._ID);
171614bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
171714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
1718d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            int count = super.delete(db, txContext, c);
171914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov
172014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            updatePhoneLookup(db, rawContactId, dataId, null, null);
1721285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            mContactAggregator.updateHasPhoneNumber(db, rawContactId);
1722d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            fixRawContactDisplayName(db, txContext, rawContactId);
1723813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            triggerAggregation(rawContactId);
172414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            return count;
1725653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1726653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1727653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private void updatePhoneLookup(SQLiteDatabase db, long rawContactId, long dataId,
1728892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                String number, String numberE164) {
1729892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(dataId);
1730892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov            db.delete(Tables.PHONE_LOOKUP, PhoneLookupColumns.DATA_ID + "=?", mSelectionArgs1);
1731e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            if (number != null) {
1732892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                String normalizedNumber = PhoneNumberUtils.normalizeNumber(number);
1733892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                if (!TextUtils.isEmpty(normalizedNumber)) {
1734892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    ContentValues phoneValues = new ContentValues();
1735892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    phoneValues.put(PhoneLookupColumns.RAW_CONTACT_ID, rawContactId);
1736892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    phoneValues.put(PhoneLookupColumns.DATA_ID, dataId);
1737892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, normalizedNumber);
1738892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    phoneValues.put(PhoneLookupColumns.MIN_MATCH,
1739892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                            PhoneNumberUtils.toCallerIDMinMatch(normalizedNumber));
1740892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    db.insert(Tables.PHONE_LOOKUP, null, phoneValues);
1741892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov
1742892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    if (numberE164 != null && !numberE164.equals(normalizedNumber)) {
1743892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                        phoneValues.put(PhoneLookupColumns.NORMALIZED_NUMBER, numberE164);
1744892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                        phoneValues.put(PhoneLookupColumns.MIN_MATCH,
1745892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                                PhoneNumberUtils.toCallerIDMinMatch(numberE164));
1746892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                        db.insert(Tables.PHONE_LOOKUP, null, phoneValues);
1747892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    }
1748892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                }
1749e80e514a6175ad2ee03ea6eff6201e0e47d5a710Dmitri Plotnikov            }
17503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
17513cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
17523cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        @Override
17533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        protected int getTypeRank(int type) {
17543cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            switch (type) {
17553cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_MOBILE: return 0;
17563cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_WORK: return 1;
17573cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_HOME: return 2;
17583cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_PAGER: return 3;
17593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_CUSTOM: return 4;
17603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_OTHER: return 5;
17613cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_WORK: return 6;
17623cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                case Phone.TYPE_FAX_HOME: return 7;
17633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                default: return 1000;
17643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            }
17653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
17663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
17673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
1768653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    public class GroupMembershipRowHandler extends DataRowHandler {
1769653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1770dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        private static final String SELECTION_RAW_CONTACT_ID = RawContacts._ID + "=?";
1771dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
1772dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        private static final String QUERY_COUNT_FAVORITES_GROUP_MEMBERSHIPS_BY_RAW_CONTACT_ID =
1773dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                "SELECT COUNT(*) FROM " + Tables.DATA + " LEFT OUTER JOIN " + Tables .GROUPS
1774dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                        + " ON " + Tables.DATA + "." + GroupMembership.GROUP_ROW_ID
1775dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                        + "=" + GroupsColumns.CONCRETE_ID
1776dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                        + " WHERE " + DataColumns.MIMETYPE_ID + "=?"
1777dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                        + " AND " + Tables.DATA + "." + GroupMembership.RAW_CONTACT_ID + "=?"
1778dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                        + " AND " + Groups.FAVORITES + "!=0";
1779dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
1780653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        public GroupMembershipRowHandler() {
1781653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            super(GroupMembership.CONTENT_ITEM_TYPE);
1782653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1783653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1784653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1785d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
1786d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values) {
1787653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            resolveGroupSourceIdInValues(rawContactId, db, values, true);
1788d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            long dataId = super.insert(db, txContext, rawContactId, values);
1789dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            if (hasFavoritesGroupMembership(db, rawContactId)) {
1790dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                updateRawContactsStar(db, rawContactId, true /* starred */);
1791dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
17920be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            updateVisibility(rawContactId);
17930be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            return dataId;
1794653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1795653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1796653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        @Override
1797d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
1798d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                Cursor c, boolean callerIsSyncAdapter) {
179914bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1800dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            boolean wasStarred = hasFavoritesGroupMembership(db, rawContactId);
1801653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            resolveGroupSourceIdInValues(rawContactId, db, values, false);
1802d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            if (!super.update(db, txContext, values, c, callerIsSyncAdapter)) {
1803813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                return false;
1804813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
1805dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            boolean isStarred = hasFavoritesGroupMembership(db, rawContactId);
1806dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            if (wasStarred != isStarred) {
1807dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                updateRawContactsStar(db, rawContactId, isStarred);
1808dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
18090be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            updateVisibility(rawContactId);
1810813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return true;
18110be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        }
18120be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov
1813dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        private void updateRawContactsStar(SQLiteDatabase db, long rawContactId, boolean starred) {
1814dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            ContentValues rawContactValues = new ContentValues();
1815dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            rawContactValues.put(RawContacts.STARRED, starred ? 1 : 0);
1816dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            if (db.update(Tables.RAW_CONTACTS, rawContactValues, SELECTION_RAW_CONTACT_ID,
1817dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    new String[]{Long.toString(rawContactId)}) > 0) {
1818dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                mContactAggregator.updateStarred(rawContactId);
1819dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
1820dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        }
1821dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
1822dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        private boolean hasFavoritesGroupMembership(SQLiteDatabase db, long rawContactId) {
1823dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            final long groupMembershipMimetypeId = mDbHelper
1824dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
1825dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            boolean isStarred = 0 < DatabaseUtils
1826dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    .longForQuery(db, QUERY_COUNT_FAVORITES_GROUP_MEMBERSHIPS_BY_RAW_CONTACT_ID,
1827dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    new String[]{Long.toString(groupMembershipMimetypeId), Long.toString(rawContactId)});
1828dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            return isStarred;
1829dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        }
1830dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
18310be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        @Override
1832d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
18330be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
1834dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            boolean wasStarred = hasFavoritesGroupMembership(db, rawContactId);
1835d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            int count = super.delete(db, txContext, c);
1836dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            boolean isStarred = hasFavoritesGroupMembership(db, rawContactId);
1837dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            if (wasStarred && !isStarred) {
1838dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                updateRawContactsStar(db, rawContactId, false /* starred */);
1839dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
18400be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            updateVisibility(rawContactId);
18410be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            return count;
18420be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        }
18430be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov
18440be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov        private void updateVisibility(long rawContactId) {
1845b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            long contactId = mDbHelper.getContactId(rawContactId);
18460be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            if (contactId != 0) {
1847b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                mDbHelper.updateContactVisible(contactId);
18480be993f8ef0078b9825a5ffe6add08a6786d8dacDmitri Plotnikov            }
1849653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1850653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1851653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        private void resolveGroupSourceIdInValues(long rawContactId, SQLiteDatabase db,
1852653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                ContentValues values, boolean isInsert) {
1853653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            boolean containsGroupSourceId = values.containsKey(GroupMembership.GROUP_SOURCE_ID);
1854653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            boolean containsGroupId = values.containsKey(GroupMembership.GROUP_ROW_ID);
1855653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (containsGroupSourceId && containsGroupId) {
1856653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                throw new IllegalArgumentException(
1857653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                        "you are not allowed to set both the GroupMembership.GROUP_SOURCE_ID "
1858653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                + "and GroupMembership.GROUP_ROW_ID");
1859653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1860653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1861653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (!containsGroupSourceId && !containsGroupId) {
1862653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                if (isInsert) {
1863653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                    throw new IllegalArgumentException(
1864653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                            "you must set exactly one of GroupMembership.GROUP_SOURCE_ID "
1865653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                                    + "and GroupMembership.GROUP_ROW_ID");
1866653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                } else {
1867653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                    return;
1868653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                }
1869653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1870653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1871653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            if (containsGroupSourceId) {
1872653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                final String sourceId = values.getAsString(GroupMembership.GROUP_SOURCE_ID);
1873ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                final long groupId = getOrMakeGroup(db, rawContactId, sourceId,
1874d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                        mTransactionContext.getAccountForRawContact(rawContactId));
1875653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.remove(GroupMembership.GROUP_SOURCE_ID);
1876653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov                values.put(GroupMembership.GROUP_ROW_ID, groupId);
1877653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            }
1878653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        }
1879653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov    }
1880653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
1881a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov    public class PhotoDataRowHandler extends DataRowHandler {
1882a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1883a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        public PhotoDataRowHandler() {
1884a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            super(Photo.CONTENT_ITEM_TYPE);
1885a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1886a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1887a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1888d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
1889d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                ContentValues values) {
1890d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            long dataId = super.insert(db, txContext, rawContactId, values);
1891d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            if (!txContext.isNewRawContact(rawContactId)) {
1892285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov                mContactAggregator.updatePhotoId(db, rawContactId);
1893285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
1894a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return dataId;
1895a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1896a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1897a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1898d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
1899d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                Cursor c, boolean callerIsSyncAdapter) {
1900a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
1901d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            if (!super.update(db, txContext, values, c, callerIsSyncAdapter)) {
1902813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov                return false;
1903813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            }
1904813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov
1905a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            mContactAggregator.updatePhotoId(db, rawContactId);
1906813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return true;
1907a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1908a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1909a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        @Override
1910d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
1911a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
1912d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            int count = super.delete(db, txContext, c);
1913a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            mContactAggregator.updatePhotoId(db, rawContactId);
1914a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            return count;
1915a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
1916a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov    }
1917a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
1918ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    /**
1919ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov     * An entry in group id cache. It maps the combination of (account type, account name
1920ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov     * and source id) to group row id.
1921ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov     */
1922ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    public class GroupIdCacheEntry {
1923ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        String accountType;
1924ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        String accountName;
1925ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        String sourceId;
1926ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        long groupId;
1927ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    }
1928a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov
19293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private HashMap<String, DataRowHandler> mDataRowHandlers;
1930b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov    private ContactsDatabaseHelper mDbHelper;
193131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
19324097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov    private NameSplitter mNameSplitter;
1933f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private NameLookupBuilder mNameLookupBuilder;
1934315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov
1935622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    private PostalSplitter mPostalSplitter;
1936622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
1937ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    // We don't need a soft cache for groups - the assumption is that there will only
1938ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    // be a small number of contact groups. The cache is keyed off source id.  The value
1939ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    // is a list of groups with this group id.
1940ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap();
1941ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
194272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private ContactDirectoryManager mContactDirectoryManager;
1943622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    private ContactAggregator mContactAggregator;
1944f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    private LegacyApiSupport mLegacyApiSupport;
1945a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov    private GlobalSearchSupport mGlobalSearchSupport;
1946d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov    private CommonNicknameCache mCommonNicknameCache;
1947a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
194820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    private ContentValues mValues = new ContentValues();
19491129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov    private CharArrayBuffer mCharArrayBuffer = new CharArrayBuffer(128);
19505dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    private NameSplitter.Name mName = new NameSplitter.Name();
195173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov    private HashMap<String, Boolean> mAccountWritability = Maps.newHashMap();
195220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
195309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov    private int mProviderStatus = ProviderStatus.STATUS_NORMAL;
19543826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov    private boolean mProviderStatusUpdateNeeded;
195509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov    private long mEstimatedStorageRequirement = 0;
1956ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov    private volatile CountDownLatch mAccessLatch;
195773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
1958d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov    private TransactionContext mTransactionContext = new TransactionContext();
1959de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov
19601a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey    private boolean mVisibleTouched = false;
19611a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey
196281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov    private boolean mSyncToNetwork;
196381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov
19644cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao    private Locale mCurrentLocale;
19653826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov    private int mContactsAccountCount;
1966d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov
19672530512f639c4979fd7371c7dd25dd67e8118124Bai Tao    private CountryMonitor mCountryMonitor;
196873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov
19694f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
19704f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public boolean onCreate() {
1971de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        super.onCreate();
1972ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov        try {
1973ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov            return initialize();
1974ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov        } catch (RuntimeException e) {
1975ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov            Log.e(TAG, "Cannot start provider", e);
1976ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov            return false;
1977ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov        }
1978ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov    }
197935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
1980ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov    private boolean initialize() {
1981de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final Context context = getContext();
198289b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        mCountryMonitor = new CountryMonitor(context);
1983b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mDbHelper = (ContactsDatabaseHelper)getDatabaseHelper();
198472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        mContactDirectoryManager = new ContactDirectoryManager(this);
1985a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov        mGlobalSearchSupport = new GlobalSearchSupport(this);
1986b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mLegacyApiSupport = new LegacyApiSupport(context, mDbHelper, this, mGlobalSearchSupport);
1987653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
198851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        initForDefaultLocale();
1989d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov
19903826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        updateAccounts();
1991bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov
199265ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov        if (isLegacyContactImportNeeded()) {
199365ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov            importLegacyContactsAsync();
199480952e03e425a04ea2fd77e3ff44a8453ffdefe1Dmitri Plotnikov        } else {
199580952e03e425a04ea2fd77e3ff44a8453ffdefe1Dmitri Plotnikov            verifyLocale();
199665ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov        }
199765ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov
199872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        startContactDirectoryManager();
199972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
20002a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov        if (isAggregationUpgradeNeeded()) {
20012a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov            upgradeAggregationAlgorithm();
20022a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov        }
20032a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov
20043826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        updateProviderStatus();
20053826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
200649d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov        return true;
20074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
20084f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
20092530512f639c4979fd7371c7dd25dd67e8118124Bai Tao    protected String getCurrentCountryIso() {
20102530512f639c4979fd7371c7dd25dd67e8118124Bai Tao        return mCountryMonitor.getCountryIso();
2011892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov    }
2012892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov
2013ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao    private void initDataRowHandlers() {
2014ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers = new HashMap<String, DataRowHandler>();
2015ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao
2016ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers.put(Email.CONTENT_ITEM_TYPE, new EmailDataRowHandler());
2017ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers.put(Im.CONTENT_ITEM_TYPE,
2018ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao              new CommonDataRowHandler(Im.CONTENT_ITEM_TYPE, Im.TYPE, Im.LABEL));
2019ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler(
2020ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao              StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, StructuredPostal.LABEL));
2021ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, new OrganizationDataRowHandler());
2022ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, new PhoneDataRowHandler());
2023ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new NicknameDataRowHandler());
2024ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE,
2025ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao              new StructuredNameRowHandler(mNameSplitter));
2026ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers.put(StructuredPostal.CONTENT_ITEM_TYPE,
2027ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao              new StructuredPostalRowHandler(mPostalSplitter));
2028ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE, new GroupMembershipRowHandler());
2029ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao      mDataRowHandlers.put(Photo.CONTENT_ITEM_TYPE, new PhotoDataRowHandler());
2030ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao    }
203172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
203251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov    /**
2033767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov     * Visible for testing.
2034767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov     */
2035767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov    /* package */ PhotoPriorityResolver createPhotoPriorityResolver(Context context) {
2036767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov        return new PhotoPriorityResolver(context);
2037767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov    }
2038767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov
2039767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov    /**
204051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov     * (Re)allocates all locale-sensitive structures.
204151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov     */
204204b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov    private void initForDefaultLocale() {
20434cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        mCurrentLocale = getLocale();
204404b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov        mNameSplitter = mDbHelper.createNameSplitter();
20454cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter);
20464cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao        mPostalSplitter = new PostalSplitter(mCurrentLocale);
204751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        mCommonNicknameCache = new CommonNicknameCache(mDbHelper.getReadableDatabase());
2048cdd03b2ba03718a7fa85663a2438136284a1557cBai Tao        ContactLocaleUtils.getIntance().setLocale(mCurrentLocale);
20495b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov        mContactAggregator = new ContactAggregator(this, mDbHelper,
20505b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                createPhotoPriorityResolver(getContext()), mNameSplitter, mCommonNicknameCache);
20515b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov        mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true));
20525b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov
2053ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao        initDataRowHandlers();
20544cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao    }
20554cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao
205653fac8f99f3884c372c907a76766d27fa9e1d95fDmitri Plotnikov    public void onLocaleChanged() {
20573826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        if (mProviderStatus != ProviderStatus.STATUS_NORMAL
20583826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov                && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) {
20594f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov            return;
20604f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov        }
20614f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov
206251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        initForDefaultLocale();
206351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        verifyLocale();
20644cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao    }
206551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov
206651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov    /**
206751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov     * Verifies that the contacts database is properly configured for the current locale.
206851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov     * If not, changes the database locale to the current locale using an asynchronous task.
206951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov     * This needs to be done asynchronously because the process involves rebuilding
207051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov     * large data structures (name lookup, sort keys), which can take minutes on
207151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov     * a large set of contacts.
207251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov     */
207351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov    protected void verifyLocale() {
2074f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov
2075f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov        // The process is already running - postpone the change
2076f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov        if (mProviderStatus == ProviderStatus.STATUS_CHANGING_LOCALE) {
2077f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov            return;
2078f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov        }
2079f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov
208051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
208151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        final String providerLocale = prefs.getString(PREF_LOCALE, null);
208251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        final Locale currentLocale = mCurrentLocale;
208351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        if (currentLocale.toString().equals(providerLocale)) {
208451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov            return;
208551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        }
208651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov
208751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        int providerStatus = mProviderStatus;
208851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        setProviderStatus(ProviderStatus.STATUS_CHANGING_LOCALE);
208951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov
209051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        AsyncTask<Integer, Void, Void> task = new AsyncTask<Integer, Void, Void>() {
209151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov
209251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov            int savedProviderStatus;
209351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov
209451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov            @Override
209551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov            protected Void doInBackground(Integer... params) {
209651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov                savedProviderStatus = params[0];
209751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov                mDbHelper.setLocale(ContactsProvider2.this, currentLocale);
209851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov                return null;
209951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov            }
210051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov
210151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov            @Override
210251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov            protected void onPostExecute(Void result) {
21039516b6eef76b3504913f5efcadf603969946a3d0Brad Fitzpatrick                prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).apply();
210451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov                setProviderStatus(savedProviderStatus);
2105f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov
2106f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov                // Recursive invocation, needed to cover the case where locale
2107f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov                // changes once and then changes again before the db upgrade is completed.
2108f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov                verifyLocale();
210951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov            }
211051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        };
211151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov
211251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov        task.execute(providerStatus);
211351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov    }
211451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov
21153826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov    private void updateProviderStatus() {
21163826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        if (mProviderStatus != ProviderStatus.STATUS_NORMAL
21173826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov                && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) {
21183826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            return;
21193826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        }
21203826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
21213826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        if (mContactsAccountCount == 0
212249d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov                && DatabaseUtils.queryNumEntries(mDbHelper.getReadableDatabase(),
212349d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov                        Tables.CONTACTS, null) == 0) {
21243826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            setProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS);
21253826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        } else {
21263826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            setProviderStatus(ProviderStatus.STATUS_NORMAL);
21273826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        }
21283826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov    }
21293826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
213031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    /* Visible for testing */
2131de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    @Override
2132b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov    protected ContactsDatabaseHelper getDatabaseHelper(final Context context) {
2133b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        return ContactsDatabaseHelper.getInstance(context);
213431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov    }
213531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
2136013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    /* package */ NameSplitter getNameSplitter() {
2137013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov        return mNameSplitter;
2138013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov    }
2139013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov
21405dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    /* Visible for testing */
214172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    public ContactDirectoryManager getContactDirectoryManager() {
214272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        return mContactDirectoryManager;
214372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
214472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
214572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /* Visible for testing */
21465dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    protected Locale getLocale() {
21475dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        return Locale.getDefault();
21485dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov    }
21495dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
215072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /* Visible for testing */
215172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    protected void startContactDirectoryManager() {
215272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        getContactDirectoryManager().start();
215372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
215472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
21553d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    protected boolean isLegacyContactImportNeeded() {
2156b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov        int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_CONTACTS_IMPORTED, "0"));
2157b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov        return version < PROPERTY_CONTACTS_IMPORT_VERSION;
21583d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
21593d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
2160568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    protected LegacyContactImporter getLegacyContactImporter() {
2161568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return new LegacyContactImporter(getContext(), this);
2162568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2163568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2164568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /**
2165568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * Imports legacy contacts in a separate thread.  As long as the import process is running
2166568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * all other access to the contacts is blocked.
2167568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     */
2168568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    private void importLegacyContactsAsync() {
2169bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        Log.v(TAG, "Importing legacy contacts");
2170bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        setProviderStatus(ProviderStatus.STATUS_UPGRADING);
2171bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        if (mAccessLatch == null) {
2172bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            mAccessLatch = new CountDownLatch(1);
2173bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        }
2174568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2175568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        Thread importThread = new Thread("LegacyContactImport") {
2176568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            @Override
2177568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            public void run() {
217880952e03e425a04ea2fd77e3ff44a8453ffdefe1Dmitri Plotnikov                final SharedPreferences prefs =
217980952e03e425a04ea2fd77e3ff44a8453ffdefe1Dmitri Plotnikov                    PreferenceManager.getDefaultSharedPreferences(getContext());
218080952e03e425a04ea2fd77e3ff44a8453ffdefe1Dmitri Plotnikov                mDbHelper.setLocale(ContactsProvider2.this, mCurrentLocale);
218180952e03e425a04ea2fd77e3ff44a8453ffdefe1Dmitri Plotnikov                prefs.edit().putString(PREF_LOCALE, mCurrentLocale.toString()).commit();
218280952e03e425a04ea2fd77e3ff44a8453ffdefe1Dmitri Plotnikov
2183bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                LegacyContactImporter importer = getLegacyContactImporter();
2184bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                if (importLegacyContacts(importer)) {
2185bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                    onLegacyContactImportSuccess();
2186bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                } else {
2187bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                    onLegacyContactImportFailure();
2188568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov                }
2189568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            }
2190568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        };
2191568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2192568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        importThread.start();
2193568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2194568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2195bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov    /**
2196bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov     * Unlocks the provider and declares that the import process is complete.
2197bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov     */
2198bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov    private void onLegacyContactImportSuccess() {
2199bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        NotificationManager nm =
2200bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            (NotificationManager)getContext().getSystemService(Context.NOTIFICATION_SERVICE);
2201bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        nm.cancel(LEGACY_IMPORT_FAILED_NOTIFICATION);
2202bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov
2203b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov        // Store a property in the database indicating that the conversion process succeeded
2204b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov        mDbHelper.setProperty(PROPERTY_CONTACTS_IMPORTED,
2205b2e27298ae54ec2215eadf98ecc100aedba98d1aDmitri Plotnikov                String.valueOf(PROPERTY_CONTACTS_IMPORT_VERSION));
2206bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        setProviderStatus(ProviderStatus.STATUS_NORMAL);
2207bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        mAccessLatch.countDown();
2208bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        mAccessLatch = null;
2209bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        Log.v(TAG, "Completed import of legacy contacts");
2210bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov    }
2211bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov
2212bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov    /**
2213bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov     * Announces the provider status and keeps the provider locked.
2214bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov     */
2215bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov    private void onLegacyContactImportFailure() {
2216bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        Context context = getContext();
2217bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        NotificationManager nm =
2218bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
2219bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov
2220bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        // Show a notification
2221bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        Notification n = new Notification(android.R.drawable.stat_notify_error,
2222bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                context.getString(R.string.upgrade_out_of_memory_notification_ticker),
2223bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                System.currentTimeMillis());
2224bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        n.setLatestEventInfo(context,
2225bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                context.getString(R.string.upgrade_out_of_memory_notification_title),
2226bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                context.getString(R.string.upgrade_out_of_memory_notification_text),
2227bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                PendingIntent.getActivity(context, 0, new Intent(Intents.UI.LIST_DEFAULT), 0));
2228bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        n.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
2229bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov
2230bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        nm.notify(LEGACY_IMPORT_FAILED_NOTIFICATION, n);
2231bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov
2232bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        setProviderStatus(ProviderStatus.STATUS_UPGRADE_OUT_OF_MEMORY);
2233bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        Log.v(TAG, "Failed to import legacy contacts");
22343d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
22353d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
22363d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    /* Visible for testing */
2237568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /* package */ boolean importLegacyContacts(LegacyContactImporter importer) {
22380e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff        boolean aggregatorEnabled = mContactAggregator.isEnabled();
22393d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        mContactAggregator.setEnabled(false);
22403d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        try {
2241bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            if (importer.importContacts()) {
2242bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov
2243bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                // TODO aggregate all newly added raw contacts
2244bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                mContactAggregator.setEnabled(aggregatorEnabled);
2245bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                return true;
2246bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            }
22473d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        } catch (Throwable e) {
22483d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov           Log.e(TAG, "Legacy contact import failed", e);
22493d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
2250bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        mEstimatedStorageRequirement = importer.getEstimatedStorageRequirement();
2251bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        return false;
22523d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov    }
22533d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
2254a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
2255a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     * Wipes all data from the contacts database.
2256a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov     */
2257a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /* package */ void wipeData() {
2258b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mDbHelper.wipeData();
22593826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        mProviderStatus = ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS;
2260a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    }
2261a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
2262568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    /**
2263568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * While importing and aggregating contacts, this content provider will
2264568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * block all attempts to change contacts data. In particular, it will hold
2265568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * up all contact syncs. As soon as the import process is complete, all
2266568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * processes waiting to write to the provider are unblocked and can proceed
2267568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     * to compete for the database transaction monitor.
2268568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov     */
2269568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    private void waitForAccess() {
2270ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        CountDownLatch latch = mAccessLatch;
2271ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov        if (latch != null) {
2272ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov            while (true) {
2273ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                try {
2274ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    latch.await();
2275ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    mAccessLatch = null;
2276ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                    return;
2277ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                } catch (InterruptedException e) {
227881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                    Thread.currentThread().interrupt();
2279ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov                }
2280ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov            }
2281568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        }
2282568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2283568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2284568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
2285568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public Uri insert(Uri uri, ContentValues values) {
2286568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
2287568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.insert(uri, values);
2288568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2289568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2290568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
2291568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
2292bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        if (mAccessLatch != null) {
2293bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            // We are stuck trying to upgrade contacts db.  The only update request
2294bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            // allowed in this case is an update of provider status, which will trigger
2295bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            // an attempt to upgrade contacts again.
2296bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            int match = sUriMatcher.match(uri);
2297bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            if (match == PROVIDER_STATUS && isLegacyContactImportNeeded()) {
2298bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                Integer newStatus = values.getAsInteger(ProviderStatus.STATUS);
2299bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                if (newStatus != null && newStatus == ProviderStatus.STATUS_UPGRADING) {
2300bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                    importLegacyContactsAsync();
2301bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                    return 1;
2302bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                } else {
2303bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                    return 0;
2304bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov                }
2305bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov            }
2306bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov        }
2307568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
2308568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.update(uri, values, selection, selectionArgs);
2309568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2310568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2311568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
2312568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public int delete(Uri uri, String selection, String[] selectionArgs) {
2313568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
2314568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.delete(uri, selection, selectionArgs);
2315568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2316568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
2317568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    @Override
2318568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
2319568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov            throws OperationApplicationException {
2320568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        waitForAccess();
2321568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov        return super.applyBatch(operations);
2322568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov    }
2323568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
23244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2325285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    protected void onBeginTransaction() {
2326bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
2327b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "onBeginTransaction");
2328b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2329285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        super.onBeginTransaction();
23301ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana        mContactAggregator.clearPendingAggregations();
2331d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        mTransactionContext.clear();
2332b5a4add17815167d20a90645779df34cdf45280dFred Quintana    }
2333b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2334285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
2335285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    @Override
2336285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    protected void beforeTransactionCommit() {
23371129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov
2338bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
2339b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "beforeTransactionCommit");
2340b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2341285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        super.beforeTransactionCommit();
2342b5a4add17815167d20a90645779df34cdf45280dFred Quintana        flushTransactionalChanges();
23431ea29714ef8fdd62b71f265f27391c22f4a50340Fred Quintana        mContactAggregator.aggregateInTransaction(mDb);
23441a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (mVisibleTouched) {
23451a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = false;
2346b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            mDbHelper.updateAllVisible();
23471a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        }
23483826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
23493826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        if (mProviderStatusUpdateNeeded) {
23503826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            updateProviderStatus();
23513826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            mProviderStatusUpdateNeeded = false;
23523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        }
2353b5a4add17815167d20a90645779df34cdf45280dFred Quintana    }
2354b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2355b5a4add17815167d20a90645779df34cdf45280dFred Quintana    private void flushTransactionalChanges() {
2356bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
2357b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "flushTransactionChanges");
2358b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
23591129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov
2360d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        for (long rawContactId : mTransactionContext.getInsertedRawContactIds()) {
2361d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov            updateRawContactDisplayName(mDb, rawContactId);
2362d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov            mContactAggregator.onRawContactInsert(mDb, rawContactId);
2363285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        }
2364b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2365d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        Set<Long> dirtyRawContacts = mTransactionContext.getDirtyRawContactIds();
2366d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        if (!dirtyRawContacts.isEmpty()) {
2367a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.setLength(0);
2368a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL);
2369d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            appendIds(mSb, dirtyRawContacts);
2370a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.append(")");
2371a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mDb.execSQL(mSb.toString());
2372a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov        }
2373a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov
2374d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        Set<Long> updatedRawContacts = mTransactionContext.getUpdatedRawContactIds();
2375d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        if (!updatedRawContacts.isEmpty()) {
2376a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.setLength(0);
2377a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL);
2378d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            appendIds(mSb, updatedRawContacts);
2379a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mSb.append(")");
2380a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            mDb.execSQL(mSb.toString());
2381b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2382b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2383d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        for (Map.Entry<Long, Object> entry : mTransactionContext.getUpdatedSyncStates()) {
2384b5a4add17815167d20a90645779df34cdf45280dFred Quintana            long id = entry.getKey();
23859d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana            if (mDbHelper.getSyncState().update(mDb, id, entry.getValue()) <= 0) {
23869d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana                throw new IllegalStateException(
23879d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana                        "unable to update sync state, does it still exist?");
23889d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana            }
2389b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2390b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2391d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        mTransactionContext.clear();
2392b5a4add17815167d20a90645779df34cdf45280dFred Quintana    }
2393b5a4add17815167d20a90645779df34cdf45280dFred Quintana
2394a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov    /**
2395a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov     * Appends comma separated ids.
2396a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov     * @param ids Should not be empty
2397a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov     */
2398d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov    private void appendIds(StringBuilder sb, Set<Long> ids) {
2399b5a4add17815167d20a90645779df34cdf45280dFred Quintana        for (long id : ids) {
2400a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov            sb.append(id).append(',');
2401b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2402a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov
2403a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov        sb.setLength(sb.length() - 1); // Yank the last comma
2404285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    }
2405285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
2406285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov    @Override
2407cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    protected void notifyChange() {
240881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        notifyChange(mSyncToNetwork);
240981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        mSyncToNetwork = false;
241081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov    }
241181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov
241281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov    protected void notifyChange(boolean syncToNetwork) {
241381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null,
241481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                syncToNetwork);
2415cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov    }
2416568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov
241751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov    protected void setProviderStatus(int status) {
24183826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        if (mProviderStatus != status) {
24193826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            mProviderStatus = status;
24203826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            getContext().getContentResolver().notifyChange(ProviderStatus.CONTENT_URI, null, false);
24213826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        }
242251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov    }
242351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov
24243cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    private DataRowHandler getDataRowHandler(final String mimeType) {
24253cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        DataRowHandler handler = mDataRowHandlers.get(mimeType);
24263cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        if (handler == null) {
24273cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            handler = new CustomDataRowHandler(mimeType);
24283cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov            mDataRowHandlers.put(mimeType, handler);
24293cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        }
24303cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        return handler;
24313cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov    }
24323cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov
24334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
2434de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected Uri insertInTransaction(Uri uri, ContentValues values) {
2435bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
24361129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov            Log.v(TAG, "insertInTransaction: " + uri + " " + values);
2437b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
2438f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana
2439f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        final boolean callerIsSyncAdapter =
2440f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false);
2441f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana
2442a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
2443a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
244435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2445a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        switch (match) {
244635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
2447b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                id = mDbHelper.getSyncState().insert(mDb, values);
244835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                break;
244935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
2450d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
2451d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                insertContact(values);
24526bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
24536bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
24546bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
24555ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
2456dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                id = insertRawContact(uri, values, callerIsSyncAdapter);
2457f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
2458a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2459a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2460a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
24615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
24625ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(1));
2463f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                id = insertData(values, callerIsSyncAdapter);
2464f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
2465a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2466a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2467a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2468a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case DATA: {
2469f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                id = insertData(values, callerIsSyncAdapter);
2470f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
2471a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
2472a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
2473a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2474ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
2475f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                id = insertGroup(uri, values, callerIsSyncAdapter);
2476f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
2477ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
2478ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
2479ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
2480eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
24815aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                id = insertSettings(uri, values);
248243880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov                mSyncToNetwork |= !callerIsSyncAdapter;
2483eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
2484eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
2485eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
248682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES: {
248782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                id = insertStatusUpdate(values);
24881f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                break;
24891f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
24901f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
2491a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            default:
249281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                mSyncToNetwork = true;
2493f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.insert(uri, values);
2494a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
2495a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
24967e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        if (id < 0) {
24977e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            return null;
24987e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana        }
24997e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
2500de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        return ContentUris.withAppendedId(uri, id);
2501a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
2502a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2503a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
2504e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * If account is non-null then store it in the values. If the account is
2505e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * already specified in the values then it must be consistent with the
2506e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * account, if it is non-null.
2507e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *
2508e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * @param uri Current {@link Uri} being operated on.
2509e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * @param values {@link ContentValues} to read and possibly update.
2510e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * @throws IllegalArgumentException when only one of
2511e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *             {@link RawContacts#ACCOUNT_NAME} or
2512e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *             {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the
2513e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *             other undefined.
2514e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME}
2515e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *             and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between
2516e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey     *             the given {@link Uri} and {@link ContentValues}.
25177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana     */
2518e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey    private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException {
2519f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME);
2520f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE);
2521e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType);
2522f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2523f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME);
2524f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
2525e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean partialValues = TextUtils.isEmpty(valueAccountName)
2526e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                ^ TextUtils.isEmpty(valueAccountType);
2527e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
2528e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (partialUri || partialValues) {
2529e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            // Throw when either account is incomplete
2530fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov            throw new IllegalArgumentException(mDbHelper.exceptionMessage(
2531fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                    "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri));
2532e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        }
2533e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
2534e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // Accounts are valid by only checking one parameter, since we've
2535e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // already ruled out partial accounts.
2536e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean validUri = !TextUtils.isEmpty(accountName);
2537e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean validValues = !TextUtils.isEmpty(valueAccountName);
2538e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
2539e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (validValues && validUri) {
2540e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            // Check that accounts match when both present
2541e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            final boolean accountMatch = TextUtils.equals(accountName, valueAccountName)
2542e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                    && TextUtils.equals(accountType, valueAccountType);
2543e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            if (!accountMatch) {
2544fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                throw new IllegalArgumentException(mDbHelper.exceptionMessage(
2545fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                        "When both specified, ACCOUNT_NAME and ACCOUNT_TYPE must match", uri));
2546e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            }
2547e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        } else if (validUri) {
2548e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            // Fill values from Uri when not present
2549f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            values.put(RawContacts.ACCOUNT_NAME, accountName);
2550f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            values.put(RawContacts.ACCOUNT_TYPE, accountType);
2551e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        } else if (validValues) {
2552f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            accountName = valueAccountName;
2553f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            accountType = valueAccountType;
2554e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        } else {
2555e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            return null;
2556f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
2557f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2558e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // Use cached Account object when matches, otherwise create
2559f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (mAccount == null
2560f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                || !mAccount.name.equals(accountName)
2561f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                || !mAccount.type.equals(accountType)) {
2562f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            mAccount = new Account(accountName, accountType);
2563035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana        }
2564f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2565e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        return mAccount;
25667e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    }
25677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25687e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
2569d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov     * Inserts an item in the contacts table
25706bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     *
25716bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @param values the values for the new row
25726bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     * @return the row ID of the newly created row
25736bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov     */
2574d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    private long insertContact(ContentValues values) {
2575de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        throw new UnsupportedOperationException("Aggregate contacts are created automatically");
25766bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    }
25776bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
25786bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov    /**
2579a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the contacts table
2580a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
2581f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov     * @param uri the values for the new row
2582f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov     * @param values the account this contact should be associated with. may be null.
2583dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana     * @param callerIsSyncAdapter
2584a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
2585a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
2586dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private long insertRawContact(Uri uri, ContentValues values, boolean callerIsSyncAdapter) {
2587f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.clear();
2588f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.putAll(values);
2589f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.putNull(RawContacts.CONTACT_ID);
2590f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2591e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final Account account = resolveAccount(uri, mValues);
25927e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
25933d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        if (values.containsKey(RawContacts.DELETED)
25943d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov                && values.getAsInteger(RawContacts.DELETED) != 0) {
2595f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
25963d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov        }
25973d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov
2598f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        long rawContactId = mDb.insert(Tables.RAW_CONTACTS, RawContacts.CONTACT_ID, mValues);
2599f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov        int aggregationMode = RawContacts.AGGREGATION_MODE_DEFAULT;
2600f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov        if (mValues.containsKey(RawContacts.AGGREGATION_MODE)) {
2601f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov            aggregationMode = mValues.getAsInteger(RawContacts.AGGREGATION_MODE);
2602f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov        }
2603f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov        mContactAggregator.markNewForAggregation(rawContactId, aggregationMode);
2604285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov
2605285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov        // Trigger creation of a Contact based on this RawContact at the end of transaction
2606d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        mTransactionContext.rawContactInserted(rawContactId, account);
2607f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
2608dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        if (!callerIsSyncAdapter) {
2609dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            addAutoAddMembership(rawContactId);
2610dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            final Long starred = values.getAsLong(RawContacts.STARRED);
2611dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            if (starred != null && starred != 0) {
2612dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                updateFavoritesMembership(rawContactId, starred != 0);
2613dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
2614dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        }
2615dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
26163826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        mProviderStatusUpdateNeeded = true;
2617023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov        return rawContactId;
2618a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    }
2619a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
2620dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private void addAutoAddMembership(long rawContactId) {
2621dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        final Long groupId = findGroupByRawContactId(SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID,
2622dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                rawContactId);
2623dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        if (groupId != null) {
2624dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            insertDataGroupMembership(rawContactId, groupId);
2625dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        }
2626dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    }
2627dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
2628dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private Long findGroupByRawContactId(String selection, long rawContactId) {
2629dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        Cursor c = mDb.query(Tables.GROUPS + "," + Tables.RAW_CONTACTS, PROJECTION_GROUP_ID,
2630dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                selection,
2631dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                new String[]{Long.toString(rawContactId)},
2632dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                null /* groupBy */, null /* having */, null /* orderBy */);
2633dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        try {
2634dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            while (c.moveToNext()) {
2635dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                return c.getLong(0);
2636dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
2637dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            return null;
2638dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        } finally {
2639dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            c.close();
2640dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        }
2641dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    }
2642dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
2643dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private void updateFavoritesMembership(long rawContactId, boolean isStarred) {
2644dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        final Long groupId = findGroupByRawContactId(SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID,
2645dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                rawContactId);
2646dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        if (groupId != null) {
2647dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            if (isStarred) {
2648dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                insertDataGroupMembership(rawContactId, groupId);
2649dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            } else {
2650dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                deleteDataGroupMembership(rawContactId, groupId);
2651dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
2652dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        }
2653dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    }
2654dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
2655dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private void insertDataGroupMembership(long rawContactId, long groupId) {
2656dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        ContentValues groupMembershipValues = new ContentValues();
2657dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        groupMembershipValues.put(GroupMembership.GROUP_ROW_ID, groupId);
2658dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        groupMembershipValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId);
2659dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        groupMembershipValues.put(DataColumns.MIMETYPE_ID,
2660dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE));
2661dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        mDb.insert(Tables.DATA, null, groupMembershipValues);
2662dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    }
2663dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
2664dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private void deleteDataGroupMembership(long rawContactId, long groupId) {
2665dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        final String[] selectionArgs = {
2666dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                Long.toString(mDbHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)),
2667dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                Long.toString(groupId),
2668dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                Long.toString(rawContactId)};
2669dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        mDb.delete(Tables.DATA, SELECTION_GROUPMEMBERSHIP_DATA, selectionArgs);
2670dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    }
2671dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
2672a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton    /**
2673a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * Inserts an item in the data table
2674a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     *
2675a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @param values the values for the new row
2676a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     * @return the row ID of the newly created row
2677a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton     */
2678f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana    private long insertData(ContentValues values, boolean callerIsSyncAdapter) {
2679a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        long id = 0;
2680de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.clear();
2681de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.putAll(values);
268267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey
2683de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID);
268420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
2685de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace package with internal mapping
2686de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String packageName = mValues.getAsString(Data.RES_PACKAGE);
2687de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (packageName != null) {
2688b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName));
2689de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
2690de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.RES_PACKAGE);
2691508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
2692de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Replace mimetype with internal mapping
2693de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        final String mimeType = mValues.getAsString(Data.MIMETYPE);
2694de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        if (TextUtils.isEmpty(mimeType)) {
2695de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            throw new IllegalArgumentException(Data.MIMETYPE + " is required");
2696de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        }
26974097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov
2698b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.getMimeTypeId(mimeType));
2699de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
2700a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov
2701a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        DataRowHandler rowHandler = getDataRowHandler(mimeType);
2702d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        id = rowHandler.insert(mDb, mTransactionContext, rawContactId, mValues);
2703f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (!callerIsSyncAdapter) {
2704d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            mTransactionContext.markRawContactDirty(rawContactId);
2705a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        }
2706d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        mTransactionContext.rawContactUpdated(rawContactId);
2707a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        return id;
27084f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
27094f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
27108e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov    private void triggerAggregation(long rawContactId) {
27118e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        if (!mContactAggregator.isEnabled()) {
27128e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            return;
27138e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov        }
27148e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
2715b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        int aggregationMode = mDbHelper.getAggregationMode(rawContactId);
2716f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        switch (aggregationMode) {
27178e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DISABLED:
27188e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                break;
27198e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
27208e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_DEFAULT: {
272169cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov                mContactAggregator.markForAggregation(rawContactId, aggregationMode, false);
2722f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
27238e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
27248e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov
27258e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            case RawContacts.AGGREGATION_MODE_SUSPENDED: {
2726b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                long contactId = mDbHelper.getContactId(rawContactId);
2727f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
27288e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                if (contactId != 0) {
27298e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                    mContactAggregator.updateAggregateData(contactId);
27308e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov                }
2731f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
27328e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
2733f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
2734c100221f706afc08409e8317a27d6850b11c54d3Omari Stephens            case RawContacts.AGGREGATION_MODE_IMMEDIATE: {
27350dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                mContactAggregator.aggregateContact(mDb, rawContactId);
2736f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                break;
27378e45e5f2142db78941b095f7418cc05b71668094Dmitri Plotnikov            }
2738f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov        }
2739f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
2740f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov
2741a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov    /**
27425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * Returns the group id of the group with sourceId and the same account as rawContactId.
27439261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * If the group doesn't already exist then it is first created,
27449261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param db SQLiteDatabase to use for this operation
27455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov     * @param rawContactId the contact this group is associated with
27469261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @param sourceId the sourceIf of the group to query or create
27479261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @return the group id of the existing or created group
27489261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalArgumentException if the contact is not associated with an account
27499261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     * @throws IllegalStateException if a group needs to be created but the creation failed
27509261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana     */
2751ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov    private long getOrMakeGroup(SQLiteDatabase db, long rawContactId, String sourceId,
2752ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            Account account) {
2753ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
2754ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        if (account == null) {
27554da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(rawContactId);
2756ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            Cursor c = db.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS,
27574da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    RawContacts._ID + "=?", mSelectionArgs1, null, null, null);
2758ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            try {
2759ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                if (c.moveToFirst()) {
2760ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    String accountName = c.getString(RawContactsQuery.ACCOUNT_NAME);
2761ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    String accountType = c.getString(RawContactsQuery.ACCOUNT_TYPE);
2762ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
2763ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                        account = new Account(accountName, accountType);
2764ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    }
27659261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
2766ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            } finally {
2767ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                c.close();
27689261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
27699261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
2770ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
27719261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        if (account == null) {
27729261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            throw new IllegalArgumentException("if the groupmembership only "
2773ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    + "has a sourceid the the contact must be associated with "
27749261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    + "an account");
27759261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
27769261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
2777ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        ArrayList<GroupIdCacheEntry> entries = mGroupIdCache.get(sourceId);
2778ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        if (entries == null) {
2779ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            entries = new ArrayList<GroupIdCacheEntry>(1);
2780ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            mGroupIdCache.put(sourceId, entries);
2781ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        }
2782ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
2783ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        int count = entries.size();
2784ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        for (int i = 0; i < count; i++) {
2785ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            GroupIdCacheEntry entry = entries.get(i);
2786ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            if (entry.accountName.equals(account.name) && entry.accountType.equals(account.type)) {
2787ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                return entry.groupId;
2788ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            }
2789ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        }
2790ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
2791ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        GroupIdCacheEntry entry = new GroupIdCacheEntry();
2792ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        entry.accountName = account.name;
2793ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        entry.accountType = account.type;
2794ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        entry.sourceId = sourceId;
2795ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        entries.add(0, entry);
2796ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
27979261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        // look up the group that contains this sourceId and has the same account name and type
27985ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        // as the contact refered to by rawContactId
2799ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        Cursor c = db.query(Tables.GROUPS, new String[]{RawContacts._ID},
28009261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                Clauses.GROUP_HAS_ACCOUNT_AND_SOURCE_ID,
2801df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                new String[]{sourceId, account.name, account.type}, null, null, null);
28029261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        try {
2803ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov            if (c.moveToFirst()) {
2804ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                entry.groupId = c.getLong(0);
28059261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            } else {
28069261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                ContentValues groupValues = new ContentValues();
2807df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                groupValues.put(Groups.ACCOUNT_NAME, account.name);
2808df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                groupValues.put(Groups.ACCOUNT_TYPE, account.type);
28099261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                groupValues.put(Groups.SOURCE_ID, sourceId);
28109261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                long groupId = db.insert(Tables.GROUPS, Groups.ACCOUNT_NAME, groupValues);
28119261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                if (groupId < 0) {
28129261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                    throw new IllegalStateException("unable to create a new group with "
28139261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                            + "this sourceid: " + groupValues);
28149261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana                }
2815ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                entry.groupId = groupId;
28169261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            }
28179261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        } finally {
28189261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana            c.close();
28199261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana        }
2820ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
2821ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        return entry.groupId;
28229261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    }
28239261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana
2824d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov    private interface DisplayNameQuery {
28251129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        public static final String RAW_SQL =
28261129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                "SELECT "
28271129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        + DataColumns.MIMETYPE_ID + ","
28281129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        + Data.IS_PRIMARY + ","
28291129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        + Data.DATA1 + ","
28305dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA2 + ","
28315dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA3 + ","
28325dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA4 + ","
28335dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA5 + ","
28345dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA6 + ","
28355dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA7 + ","
28365dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA8 + ","
28375dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA9 + ","
28385dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA10 + ","
28395dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        + Data.DATA11 +
28401129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                " FROM " + Tables.DATA +
28411129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                " WHERE " + Data.RAW_CONTACT_ID + "=?" +
28421129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        " AND (" + Data.DATA1 + " NOT NULL OR " +
28431129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                                Organization.TITLE + " NOT NULL)";
2844d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
2845d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov        public static final int MIMETYPE = 0;
2846d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov        public static final int IS_PRIMARY = 1;
28475dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int DATA1 = 2;
28485dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int GIVEN_NAME = 3;                         // data2
28495dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int FAMILY_NAME = 4;                        // data3
28505dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int PREFIX = 5;                             // data4
28515dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int TITLE = 5;                              // data4
28525dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int MIDDLE_NAME = 6;                        // data5
28535dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int SUFFIX = 7;                             // data6
28545dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int PHONETIC_GIVEN_NAME = 8;                // data7
28555dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int PHONETIC_MIDDLE_NAME = 9;               // data8
28565dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int ORGANIZATION_PHONETIC_NAME = 9;         // data8
28575dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int PHONETIC_FAMILY_NAME = 10;              // data9
28585dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int FULL_NAME_STYLE = 11;                   // data10
28595dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int ORGANIZATION_PHONETIC_NAME_STYLE = 11;  // data10
28605dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public static final int PHONETIC_NAME_STYLE = 12;               // data11
2861d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov    }
2862d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
2863d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov    /**
2864d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov     * Updates a raw contact display name based on data rows, e.g. structured name,
2865d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov     * organization, email etc.
2866d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov     */
2867ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov    public void updateRawContactDisplayName(SQLiteDatabase db, long rawContactId) {
2868bca1c8b44f99528fc123d5547723e44771e8e934Mike Lockwood        int bestDisplayNameSource = DisplayNameSources.UNDEFINED;
28695dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        NameSplitter.Name bestName = null;
28705dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String bestDisplayName = null;
28715dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String bestPhoneticName = null;
28725dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        int bestPhoneticNameStyle = PhoneticNameStyle.UNDEFINED;
2873d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
28741129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(rawContactId);
28751129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov        Cursor c = db.rawQuery(DisplayNameQuery.RAW_SQL, mSelectionArgs1);
2876d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov        try {
2877d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov            while (c.moveToNext()) {
28781129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                int mimeType = c.getInt(DisplayNameQuery.MIMETYPE);
28792a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov                int source = mDbHelper.getDisplayNameSourceForMimeTypeId(mimeType);
28805dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                if (source < bestDisplayNameSource || source == DisplayNameSources.UNDEFINED) {
28815dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    continue;
28825dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                }
28831129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov
28845dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                if (source == bestDisplayNameSource && c.getInt(DisplayNameQuery.IS_PRIMARY) == 0) {
28855dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    continue;
2886d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov                }
28871129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov
28882a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov                if (mimeType == mDbHelper.getMimeTypeIdForStructuredName()) {
28895dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    NameSplitter.Name name;
28905dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    if (bestName != null) {
28915dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        name = new NameSplitter.Name();
28925dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    } else {
28935dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        name = mName;
28945dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        name.clear();
28955dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    }
28965dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.prefix = c.getString(DisplayNameQuery.PREFIX);
28975dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.givenNames = c.getString(DisplayNameQuery.GIVEN_NAME);
28985dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.middleName = c.getString(DisplayNameQuery.MIDDLE_NAME);
28995dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.familyName = c.getString(DisplayNameQuery.FAMILY_NAME);
29005dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.suffix = c.getString(DisplayNameQuery.SUFFIX);
29015dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.fullNameStyle = c.isNull(DisplayNameQuery.FULL_NAME_STYLE)
29025dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            ? FullNameStyle.UNDEFINED
29035dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            : c.getInt(DisplayNameQuery.FULL_NAME_STYLE);
29045dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.phoneticFamilyName = c.getString(DisplayNameQuery.PHONETIC_FAMILY_NAME);
29055dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.phoneticMiddleName = c.getString(DisplayNameQuery.PHONETIC_MIDDLE_NAME);
29065dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.phoneticGivenName = c.getString(DisplayNameQuery.PHONETIC_GIVEN_NAME);
29075dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    name.phoneticNameStyle = c.isNull(DisplayNameQuery.PHONETIC_NAME_STYLE)
29085dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            ? PhoneticNameStyle.UNDEFINED
29095dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            : c.getInt(DisplayNameQuery.PHONETIC_NAME_STYLE);
29105dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    if (!name.isEmpty()) {
29115dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestDisplayNameSource = source;
29125dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestName = name;
29135dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    }
29142a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov                } else if (mimeType == mDbHelper.getMimeTypeIdForOrganization()) {
29155dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    mCharArrayBuffer.sizeCopied = 0;
29165dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    c.copyStringToBuffer(DisplayNameQuery.DATA1, mCharArrayBuffer);
29175dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    if (mCharArrayBuffer.sizeCopied != 0) {
2918d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov                        bestDisplayNameSource = source;
29191129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        bestDisplayName = new String(mCharArrayBuffer.data, 0,
29201129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                                mCharArrayBuffer.sizeCopied);
29215dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestPhoneticName = c.getString(DisplayNameQuery.ORGANIZATION_PHONETIC_NAME);
29225dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestPhoneticNameStyle =
29235dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                                c.isNull(DisplayNameQuery.ORGANIZATION_PHONETIC_NAME_STYLE)
29245dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                                    ? PhoneticNameStyle.UNDEFINED
29255dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                                    : c.getInt(DisplayNameQuery.ORGANIZATION_PHONETIC_NAME_STYLE);
29265dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    } else {
29275dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        c.copyStringToBuffer(DisplayNameQuery.TITLE, mCharArrayBuffer);
29285dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        if (mCharArrayBuffer.sizeCopied != 0) {
29291129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                            bestDisplayNameSource = source;
29301129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                            bestDisplayName = new String(mCharArrayBuffer.data, 0,
29311129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                                    mCharArrayBuffer.sizeCopied);
29325dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            bestPhoneticName = null;
29335dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            bestPhoneticNameStyle = PhoneticNameStyle.UNDEFINED;
29341129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                        }
2935d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov                    }
29365dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                } else {
29375dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    // Display name is at DATA1 in all other types.
29385dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    // This is ensured in the constructor.
29395dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
29405dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    mCharArrayBuffer.sizeCopied = 0;
29415dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    c.copyStringToBuffer(DisplayNameQuery.DATA1, mCharArrayBuffer);
29425dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    if (mCharArrayBuffer.sizeCopied != 0) {
29435dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestDisplayNameSource = source;
29445dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestDisplayName = new String(mCharArrayBuffer.data, 0,
29455dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                                mCharArrayBuffer.sizeCopied);
29465dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestPhoneticName = null;
29475dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        bestPhoneticNameStyle = PhoneticNameStyle.UNDEFINED;
29485dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    }
2949d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov                }
2950d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov            }
2951d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
2952d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov        } finally {
2953d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov            c.close();
2954d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov        }
2955d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
29565dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String displayNamePrimary;
29575dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String displayNameAlternative;
29585dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String sortKeyPrimary = null;
29595dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        String sortKeyAlternative = null;
29605dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        int displayNameStyle = FullNameStyle.UNDEFINED;
29615dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
29625dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        if (bestDisplayNameSource == DisplayNameSources.STRUCTURED_NAME) {
29635dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            displayNameStyle = bestName.fullNameStyle;
29645dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            if (displayNameStyle == FullNameStyle.CJK
29655dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    || displayNameStyle == FullNameStyle.UNDEFINED) {
29665dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                displayNameStyle = mNameSplitter.getAdjustedFullNameStyle(displayNameStyle);
29675dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                bestName.fullNameStyle = displayNameStyle;
29685dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            }
29695dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
29705dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            displayNamePrimary = mNameSplitter.join(bestName, true);
29715dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            displayNameAlternative = mNameSplitter.join(bestName, false);
29725dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
29735dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            bestPhoneticName = mNameSplitter.joinPhoneticName(bestName);
29745dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            bestPhoneticNameStyle = bestName.phoneticNameStyle;
29755dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        } else {
29765dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            displayNamePrimary = displayNameAlternative = bestDisplayName;
29775dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        }
29785dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
29795dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        if (bestPhoneticName != null) {
29805dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            sortKeyPrimary = sortKeyAlternative = bestPhoneticName;
29815dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            if (bestPhoneticNameStyle == PhoneticNameStyle.UNDEFINED) {
29825dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                bestPhoneticNameStyle = mNameSplitter.guessPhoneticNameStyle(bestPhoneticName);
29835dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            }
29845dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        } else {
29855dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            if (displayNameStyle == FullNameStyle.UNDEFINED) {
29865dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                displayNameStyle = mNameSplitter.guessFullNameStyle(bestDisplayName);
29875dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                if (displayNameStyle == FullNameStyle.UNDEFINED
29885dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                        || displayNameStyle == FullNameStyle.CJK) {
29895dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                    displayNameStyle = mNameSplitter.getAdjustedNameStyleBasedOnPhoneticNameStyle(
29905dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                            displayNameStyle, bestPhoneticNameStyle);
29915dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                }
29925dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                displayNameStyle = mNameSplitter.getAdjustedFullNameStyle(displayNameStyle);
29935dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            }
2994ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao            if (displayNameStyle == FullNameStyle.CHINESE ||
2995ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao                    displayNameStyle == FullNameStyle.CJK) {
29965dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                sortKeyPrimary = sortKeyAlternative =
2997cdd03b2ba03718a7fa85663a2438136284a1557cBai Tao                        ContactLocaleUtils.getIntance().getSortKey(
2998ee0e6b105832366143e4ddb30beb5bb0e5c81ec5Bai Tao                                displayNamePrimary, displayNameStyle);
29995dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            }
30005dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        }
30015dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
30025dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        if (sortKeyPrimary == null) {
30035dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            sortKeyPrimary = displayNamePrimary;
30045dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            sortKeyAlternative = displayNameAlternative;
30055dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        }
30065dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
300778fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov        mDbHelper.setDisplayName(rawContactId, bestDisplayNameSource, displayNamePrimary,
30085dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                displayNameAlternative, bestPhoneticName, bestPhoneticNameStyle,
30095dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov                sortKeyPrimary, sortKeyAlternative);
3010d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov    }
3011d0f63551e3147babcebde5326b31285d7bdf6739Dmitri Plotnikov
30129261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana    /**
301320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     * Delete data row by row so that fixing of primaries etc work correctly.
301420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov     */
3015f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana    private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) {
301620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        int count = 0;
301720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
3018de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
3019de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
302014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, selection, selectionArgs, null);
3021de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        try {
3022de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            while(c.moveToNext()) {
302314bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
302414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov                String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
3025a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov                DataRowHandler rowHandler = getDataRowHandler(mimeType);
3026d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                count += rowHandler.delete(mDb, mTransactionContext, c);
3027f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                if (!callerIsSyncAdapter) {
3028d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                    mTransactionContext.markRawContactDirty(rawContactId);
302988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov                }
303020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
303120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
3032de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            c.close();
303320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
303420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
303520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        return count;
303620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
303720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
303888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov    /**
303988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     * Delete a data row provided that it is one of the allowed mime types.
304088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov     */
304120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    public int deleteData(long dataId, String[] allowedMimeTypes) {
3042f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
304388e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
304488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov        // so we don't need to worry about deleting data we don't have permission to read.
30454da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(dataId);
30464da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov        Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, Data._ID + "=?",
30474da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                mSelectionArgs1, null);
3048f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov
304920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        try {
305020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!c.moveToFirst()) {
305120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                return 0;
305220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
305320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
305414bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
305520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            boolean valid = false;
305620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            for (int i = 0; i < allowedMimeTypes.length; i++) {
305720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                if (TextUtils.equals(mimeType, allowedMimeTypes[i])) {
305820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    valid = true;
305920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                    break;
306020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                }
306120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
306220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
306320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            if (!valid) {
30647a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana                throw new IllegalArgumentException("Data type mismatch: expected "
306520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                        + Lists.newArrayList(allowedMimeTypes));
306620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
306720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
3068a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov            DataRowHandler rowHandler = getDataRowHandler(mimeType);
3069d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            return rowHandler.delete(mDb, mTransactionContext, c);
307020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        } finally {
307120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            c.close();
307220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
307320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
307420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
307520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    /**
3076ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Inserts an item in the groups table
3077ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
3078f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) {
3079f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.clear();
3080f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.putAll(values);
3081f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
3082e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final Account account = resolveAccount(uri, mValues);
3083ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3084ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        // Replace package with internal mapping
3085f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        final String packageName = mValues.getAsString(Groups.RES_PACKAGE);
308667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        if (packageName != null) {
3087f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName));
308867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        }
3089f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        mValues.remove(Groups.RES_PACKAGE);
3090ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3091dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        final boolean isFavoritesGroup = mValues.getAsLong(Groups.FAVORITES) != null
3092dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                ? mValues.getAsLong(Groups.FAVORITES) != 0
3093dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                : false;
3094dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
3095f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (!callerIsSyncAdapter) {
3096f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            mValues.put(Groups.DIRTY, 1);
309773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
309873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
3099f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        long result = mDb.insert(Tables.GROUPS, Groups.TITLE, mValues);
3100ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey
3101dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        if (!callerIsSyncAdapter && isFavoritesGroup) {
3102dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            // add all starred raw contacts to this group
3103dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            String selection;
3104dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            String[] selectionArgs;
3105dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            if (account == null) {
3106dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                selection = RawContacts.ACCOUNT_NAME + " IS NULL AND "
3107dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                        + RawContacts.ACCOUNT_TYPE + " IS NULL";
3108dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                selectionArgs = null;
3109dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            } else {
3110dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                selection = RawContacts.ACCOUNT_NAME + "=? AND "
3111dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                        + RawContacts.ACCOUNT_TYPE + "=?";
3112dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                selectionArgs = new String[]{account.name, account.type};
3113dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
3114dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            Cursor c = mDb.query(Tables.RAW_CONTACTS,
3115dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    new String[]{RawContacts._ID, RawContacts.STARRED},
3116dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    selection, selectionArgs, null, null, null);
3117892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov            try {
3118892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                while (c.moveToNext()) {
3119892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    if (c.getLong(1) != 0) {
3120892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                        final long rawContactId = c.getLong(0);
3121892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                        insertDataGroupMembership(rawContactId, result);
3122d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                        mTransactionContext.markRawContactDirty(rawContactId);
3123892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    }
3124dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                }
3125892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov            } finally {
3126892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                c.close();
3127dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
3128dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        }
3129dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
3130f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (mValues.containsKey(Groups.GROUP_VISIBLE)) {
31311a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
3132ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        }
3133ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey
3134ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        return result;
3135ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
3136ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
31375aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private long insertSettings(Uri uri, ContentValues values) {
3138e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final long id = mDb.insert(Tables.SETTINGS, null, values);
31395aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey
31401a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (values.containsKey(Settings.UNGROUPED_VISIBLE)) {
31411a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
3142e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
31431a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey
3144e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return id;
3145e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
3146e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
3147ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
314882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov     * Inserts a status update.
31491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey     */
315082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    public long insertStatusUpdate(ContentValues values) {
315182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        final String handle = values.getAsString(StatusUpdates.IM_HANDLE);
31520a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL);
31534dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov        String customProtocol = null;
31544dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov
31550a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) {
315682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL);
31574dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            if (TextUtils.isEmpty(customProtocol)) {
31584dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                throw new IllegalArgumentException(
31594dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov                        "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM");
31604dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov            }
31611f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
31621f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
3163dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton        long rawContactId = -1;
3164dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton        long contactId = -1;
316582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        Long dataId = values.getAsLong(StatusUpdates.DATA_ID);
3166f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov        mSb.setLength(0);
31672526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov        mSelectionArgs.clear();
3168dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton        if (dataId != null) {
3169dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            // Lookup the contact info for the given data row.
3170dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton
31712526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov            mSb.append(Tables.DATA + "." + Data._ID + "=?");
31722526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov            mSelectionArgs.add(String.valueOf(dataId));
31731f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } else {
3174dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            // Lookup the data row to attach this presence update to
3175dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton
31760a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            if (TextUtils.isEmpty(handle) || protocol == null) {
31770a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required");
31780a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            }
31790a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
3180dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            // TODO: generalize to allow other providers to match against email
3181dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol;
3182dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton
31832a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov            String mimeTypeIdIm = String.valueOf(mDbHelper.getMimeTypeIdForIm());
3184dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            if (matchEmail) {
31852a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov                String mimeTypeIdEmail = String.valueOf(mDbHelper.getMimeTypeIdForEmail());
3186f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov
3187f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise
3188f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                // the "OR" conjunction confuses it and it switches to a full scan of
3189f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                // the raw_contacts table.
3190f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov
3191f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                // This code relies on the fact that Im.DATA and Email.DATA are in fact the same
3192f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov                // column - Data.DATA1
31932526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSb.append(DataColumns.MIMETYPE_ID + " IN (?,?)" +
31942526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                        " AND " + Data.DATA1 + "=?" +
31952526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                        " AND ((" + DataColumns.MIMETYPE_ID + "=? AND " + Im.PROTOCOL + "=?");
31962526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSelectionArgs.add(mimeTypeIdEmail);
31972526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSelectionArgs.add(mimeTypeIdIm);
31982526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSelectionArgs.add(handle);
31992526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSelectionArgs.add(mimeTypeIdIm);
32002526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSelectionArgs.add(String.valueOf(protocol));
3201dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                if (customProtocol != null) {
32022526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                    mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?");
32032526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                    mSelectionArgs.add(customProtocol);
3204dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                }
32052526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=?))");
32062526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSelectionArgs.add(mimeTypeIdEmail);
3207dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            } else {
32082526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSb.append(DataColumns.MIMETYPE_ID + "=?" +
32092526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                        " AND " + Im.PROTOCOL + "=?" +
32102526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                        " AND " + Im.DATA + "=?");
32112526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSelectionArgs.add(mimeTypeIdIm);
32122526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSelectionArgs.add(String.valueOf(protocol));
32132526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSelectionArgs.add(handle);
3214dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                if (customProtocol != null) {
32152526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                    mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?");
32162526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                    mSelectionArgs.add(customProtocol);
3217dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton                }
3218dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            }
32191f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
322082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            if (values.containsKey(StatusUpdates.DATA_ID)) {
32212526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSb.append(" AND " + DataColumns.CONCRETE_ID + "=?");
32222526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                mSelectionArgs.add(values.getAsString(StatusUpdates.DATA_ID));
3223dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton            }
322470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
3225f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov        mSb.append(" AND ").append(getContactsRestrictions());
322670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
32271f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        Cursor cursor = null;
32281f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        try {
3229de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            cursor = mDb.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION,
32302526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov                    mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null,
32314394086494fe7909aaca70f56fb4bb08beebf303Dmitri Plotnikov                    Clauses.CONTACT_VISIBLE + " DESC, " + Data.RAW_CONTACT_ID);
32321f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            if (cursor.moveToFirst()) {
323367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey                dataId = cursor.getLong(DataContactsQuery.DATA_ID);
32345ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID);
3235e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                contactId = cursor.getLong(DataContactsQuery.CONTACT_ID);
32361f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            } else {
32371f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                // No contact found, return a null URI
32381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey                return -1;
32391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
32401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        } finally {
324131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            if (cursor != null) {
324231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                cursor.close();
324331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
32441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        }
32451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
324682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (values.containsKey(StatusUpdates.PRESENCE)) {
3247a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            if (customProtocol == null) {
3248a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                // We cannot allow a null in the custom protocol field, because SQLite3 does not
3249a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                // properly enforce uniqueness of null values
3250a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov                customProtocol = "";
3251a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            }
3252a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
3253a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mValues.clear();
325482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.DATA_ID, dataId);
3255a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId);
3256a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mValues.put(PresenceColumns.CONTACT_ID, contactId);
325782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.PROTOCOL, protocol);
325882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol);
325982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.IM_HANDLE, handle);
326082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            if (values.containsKey(StatusUpdates.IM_ACCOUNT)) {
326182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT));
3262a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            }
326382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            mValues.put(StatusUpdates.PRESENCE,
326482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                    values.getAsString(StatusUpdates.PRESENCE));
3265aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori            mValues.put(StatusUpdates.CHAT_CAPABILITY,
3266aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori                    values.getAsString(StatusUpdates.CHAT_CAPABILITY));
32671f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
3268a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            // Insert the presence update
3269a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            mDb.replace(Tables.PRESENCE, null, mValues);
3270a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        }
3271e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
32720a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
327382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        if (values.containsKey(StatusUpdates.STATUS)) {
327482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            String status = values.getAsString(StatusUpdates.STATUS);
32750a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE);
32760a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            Integer labelResource = values.getAsInteger(StatusUpdates.STATUS_LABEL);
32770a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
32780a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            if (TextUtils.isEmpty(resPackage)
32790a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    && (labelResource == null || labelResource == 0)
32800a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                    && protocol != null) {
32810a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                labelResource = Im.getProtocolLabelResource(protocol);
32820a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            }
32830a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
32840a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            Long iconResource = values.getAsLong(StatusUpdates.STATUS_ICON);
32850a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            // TODO compute the default icon based on the protocol
32860a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
3287a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            if (TextUtils.isEmpty(status)) {
328878fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                mDbHelper.deleteStatusUpdate(dataId);
328982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            } else if (values.containsKey(StatusUpdates.STATUS_TIMESTAMP)) {
329082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP);
329178fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                mDbHelper.replaceStatusUpdate(dataId, timestamp, status, resPackage, iconResource,
329278fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                        labelResource);
3293a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov            } else {
329478fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                mDbHelper.insertStatusUpdate(dataId, status, resPackage, iconResource,
329578fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                        labelResource);
3296e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov            }
3297e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        }
3298bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov
3299a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        if (contactId != -1) {
3300f4015ab9ab7c26b766b5331fbf6655b8c54877eaDmitri Plotnikov            mContactAggregator.updateLastStatusUpdateId(contactId);
3301a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        }
3302a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov
3303a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov        return dataId;
33041f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey    }
33051f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
33064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
3307de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
3308bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
3309b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "deleteInTransaction: " + uri);
3310b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
3311b5a4add17815167d20a90645779df34cdf45280dFred Quintana        flushTransactionalChanges();
3312f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        final boolean callerIsSyncAdapter =
3313f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false);
3314508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        final int match = sUriMatcher.match(uri);
3315508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        switch (match) {
331635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
3317b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getSyncState().delete(mDb, selection, selectionArgs);
331835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
3319b5a4add17815167d20a90645779df34cdf45280dFred Quintana            case SYNCSTATE_ID:
3320b5a4add17815167d20a90645779df34cdf45280dFred Quintana                String selectionWithId =
3321b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ")
3322b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        + (selection == null ? "" : " AND (" + selection + ")");
3323b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getSyncState().delete(mDb, selectionWithId, selectionArgs);
3324b5a4add17815167d20a90645779df34cdf45280dFred Quintana
3325cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            case CONTACTS: {
3326cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                // TODO
3327cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                return 0;
3328cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            }
3329cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
3330d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
3331d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
3332dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                return deleteContact(contactId, callerIsSyncAdapter);
33336bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
33346bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
33359fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann            case CONTACTS_LOOKUP: {
33362e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final List<String> pathSegments = uri.getPathSegments();
33372e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final int segmentCount = pathSegments.size();
33382e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                if (segmentCount < 3) {
3339fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                    throw new IllegalArgumentException(mDbHelper.exceptionMessage(
3340fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                            "Missing a lookup key", uri));
33412e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                }
33422e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final String lookupKey = pathSegments.get(2);
33432e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final long contactId = lookupContactIdByLookupKey(mDb, lookupKey);
3344dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                return deleteContact(contactId, callerIsSyncAdapter);
33452e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            }
33462e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey
33479fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann            case CONTACTS_LOOKUP_ID: {
33489fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                // lookup contact by id and lookup key to see if they still match the actual record
33499fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                final List<String> pathSegments = uri.getPathSegments();
33509fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                final String lookupKey = pathSegments.get(2);
33519fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder();
33529fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                setTablesAndProjectionMapForContacts(lookupQb, uri, null);
3353a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
33549fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                String[] args;
33559fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                if (selectionArgs == null) {
33569fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                    args = new String[2];
33579fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                } else {
33589fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                    args = new String[selectionArgs.length + 2];
33599fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                    System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length);
33609fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                }
33619fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                args[0] = String.valueOf(contactId);
336260de6f6c3c70e53b603a47b0efc80993353a8368Daniel Lehmann                args[1] = Uri.encode(lookupKey);
33639fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?");
33649fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                final SQLiteDatabase db = mDbHelper.getReadableDatabase();
33659fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                Cursor c = query(db, lookupQb, null, selection, args, null, null, null);
33669fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                try {
33679fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                    if (c.getCount() == 1) {
33689fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                        // contact was unmodified so go ahead and delete it
3369dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                        return deleteContact(contactId, callerIsSyncAdapter);
33709fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                    } else {
33719fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                        // row was changed (e.g. the merging might have changed), we got multiple
33729fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                        // rows or the supplied selection filtered the record out
33739fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                        return 0;
33749fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                    }
33759fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                } finally {
33769fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                    c.close();
33779fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann                }
33789fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann            }
33799fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann
33802971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            case RAW_CONTACTS: {
33812971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                int numDeletes = 0;
3382fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                Cursor c = mDb.query(Tables.RAW_CONTACTS,
3383fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        new String[]{RawContacts._ID, RawContacts.CONTACT_ID},
3384e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs, null, null, null);
33852971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                try {
33862971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    while (c.moveToNext()) {
33872971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                        final long rawContactId = c.getLong(0);
3388fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        long contactId = c.getLong(1);
3389fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        numDeletes += deleteRawContact(rawContactId, contactId,
3390fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                                callerIsSyncAdapter);
33912971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    }
33922971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                } finally {
33932971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    c.close();
33942971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                }
33952971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return numDeletes;
33962971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            }
33972971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana
33985ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
33992971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                final long rawContactId = ContentUris.parseId(uri);
3400fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                return deleteRawContact(rawContactId, mDbHelper.getContactId(rawContactId),
3401fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov                        callerIsSyncAdapter);
3402508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
3403508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
340420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
3405f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
3406944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                return deleteData(appendAccountToSelection(uri, selection), selectionArgs,
3407f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                        callerIsSyncAdapter);
340820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
340920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
341048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case DATA_ID:
341148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID:
341248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID:
341348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID: {
3414508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey                long dataId = ContentUris.parseId(uri);
3415f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
34164da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                mSelectionArgs1[0] = String.valueOf(dataId);
34174da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter);
3418ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
3419ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3420ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
3421f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mSyncToNetwork |= !callerIsSyncAdapter;
34225aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter);
34232971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            }
34242971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana
34252971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana            case GROUPS: {
34262971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                int numDeletes = 0;
34272971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups._ID},
3428e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                        appendAccountToSelection(uri, selection), selectionArgs, null, null, null);
34292971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                try {
34302971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    while (c.moveToNext()) {
34315aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                        numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter);
34322971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    }
34332971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                } finally {
34342971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                    c.close();
34352971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                }
343681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (numDeletes > 0) {
3437f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
343881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
34392971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana                return numDeletes;
3440508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            }
3441508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey
3442eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
344343880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov                mSyncToNetwork |= !callerIsSyncAdapter;
3444e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs);
3445eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
3446eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
344782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES: {
34480a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                return deleteStatusUpdates(selection, selectionArgs);
34491f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey            }
34501f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey
345181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            default: {
345281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                mSyncToNetwork = true;
34533cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                return mLegacyApiSupport.delete(uri, selection, selectionArgs);
345481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            }
3455508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey        }
34564f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
34574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
34581c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov    public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) {
3459ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        mGroupIdCache.clear();
3460b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        final long groupMembershipMimetypeId = mDbHelper
346194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
3462de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov        mDb.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "="
346394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "="
346494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                + groupId, null);
346594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
346694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        try {
3467f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            if (callerIsSyncAdapter) {
3468de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null);
346994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            } else {
347094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.clear();
347194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana                mValues.put(Groups.DELETED, 1);
3472f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                mValues.put(Groups.DIRTY, 1);
3473de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                return mDb.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, null);
347494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana            }
347594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        } finally {
34761a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
347794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
347894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
347994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
34805aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private int deleteSettings(Uri uri, String selection, String[] selectionArgs) {
3481e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final int count = mDb.delete(Tables.SETTINGS, selection, selectionArgs);
34821a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        mVisibleTouched = true;
3483e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return count;
3484e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
3485e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
3486dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private int deleteContact(long contactId, boolean callerIsSyncAdapter) {
348796b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker        mSelectionArgs1[0] = Long.toString(contactId);
3488cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        Cursor c = mDb.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID},
348996b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker                RawContacts.CONTACT_ID + "=?", mSelectionArgs1,
349096b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker                null, null, null);
3491cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        try {
3492cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            while (c.moveToNext()) {
3493cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov                long rawContactId = c.getLong(0);
3494dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                markRawContactAsDeleted(rawContactId, callerIsSyncAdapter);
3495cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            }
3496cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        } finally {
3497cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov            c.close();
3498cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        }
3499cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
35003826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        mProviderStatusUpdateNeeded = true;
35013826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
3502cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        return mDb.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null);
3503cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov    }
3504cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
3505fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov    public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) {
35063389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov        mContactAggregator.invalidateAggregationExceptionCache();
35073826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        mProviderStatusUpdateNeeded = true;
35083826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
3509f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (callerIsSyncAdapter) {
351014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov            mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null);
3511fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov            int count = mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null);
3512fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov            mContactAggregator.updateDisplayNameForContact(mDb, contactId);
3513fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov            return count;
351433b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        } else {
3515b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            mDbHelper.removeContactIfSingleton(rawContactId);
3516dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            return markRawContactAsDeleted(rawContactId, callerIsSyncAdapter);
351733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov        }
351833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
351933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
35200a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov    private int deleteStatusUpdates(String selection, String[] selectionArgs) {
35219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      // delete from both tables: presence and status_updates
35229705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      // TODO should account type/name be appended to the where clause?
35239705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      if (VERBOSE_LOGGING) {
35249705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori          Log.v(TAG, "deleting data from status_updates for " + selection);
35259705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      }
35269705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      mDb.delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection),
35279705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori          selectionArgs);
35289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori      return mDb.delete(Tables.PRESENCE, selection, selectionArgs);
35290a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov    }
35300a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
3531dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private int markRawContactAsDeleted(long rawContactId, boolean callerIsSyncAdapter) {
353281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov        mSyncToNetwork = true;
353381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov
3534cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.clear();
3535cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContacts.DELETED, 1);
3536cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
3537cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1);
3538cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.putNull(RawContacts.CONTACT_ID);
3539cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov        mValues.put(RawContacts.DIRTY, 1);
3540dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        return updateRawContact(rawContactId, mValues, callerIsSyncAdapter);
3541cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov    }
3542cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov
35434f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
3544de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov    protected int updateInTransaction(Uri uri, ContentValues values, String selection,
3545de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov            String[] selectionArgs) {
3546bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
3547b5a4add17815167d20a90645779df34cdf45280dFred Quintana            Log.v(TAG, "updateInTransaction: " + uri);
3548b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
3549b5a4add17815167d20a90645779df34cdf45280dFred Quintana
355035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana        int count = 0;
355100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
355200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        final int match = sUriMatcher.match(uri);
3553b5a4add17815167d20a90645779df34cdf45280dFred Quintana        if (match == SYNCSTATE_ID && selection == null) {
3554b5a4add17815167d20a90645779df34cdf45280dFred Quintana            long rowId = ContentUris.parseId(uri);
35551129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov            Object data = values.get(ContactsContract.SyncState.DATA);
3556d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov            mTransactionContext.syncStateUpdated(rowId, data);
3557b5a4add17815167d20a90645779df34cdf45280dFred Quintana            return 1;
3558b5a4add17815167d20a90645779df34cdf45280dFred Quintana        }
3559b5a4add17815167d20a90645779df34cdf45280dFred Quintana        flushTransactionalChanges();
3560f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        final boolean callerIsSyncAdapter =
3561f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false);
356200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        switch(match) {
356335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
3564b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getSyncState().update(mDb, values,
3565b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        appendAccountToSelection(uri, selection), selectionArgs);
3566b5a4add17815167d20a90645779df34cdf45280dFred Quintana
3567b5a4add17815167d20a90645779df34cdf45280dFred Quintana            case SYNCSTATE_ID: {
3568b5a4add17815167d20a90645779df34cdf45280dFred Quintana                selection = appendAccountToSelection(uri, selection);
3569b5a4add17815167d20a90645779df34cdf45280dFred Quintana                String selectionWithId =
3570b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ")
3571b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        + (selection == null ? "" : " AND (" + selection + ")");
3572b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getSyncState().update(mDb, values,
3573b5a4add17815167d20a90645779df34cdf45280dFred Quintana                        selectionWithId, selectionArgs);
3574b5a4add17815167d20a90645779df34cdf45280dFred Quintana            }
357535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
3576d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
3577dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter);
357800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
357900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
358000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
3581d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
3582dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                count = updateContactOptions(ContentUris.parseId(uri), values, callerIsSyncAdapter);
3583c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar                break;
3584c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar            }
3585c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
35862e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            case CONTACTS_LOOKUP:
35872e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            case CONTACTS_LOOKUP_ID: {
35882e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final List<String> pathSegments = uri.getPathSegments();
35892e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final int segmentCount = pathSegments.size();
35902e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                if (segmentCount < 3) {
3591fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                    throw new IllegalArgumentException(mDbHelper.exceptionMessage(
3592fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                            "Missing a lookup key", uri));
35932e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                }
35942e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final String lookupKey = pathSegments.get(2);
35952e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                final long contactId = lookupContactIdByLookupKey(mDb, lookupKey);
3596dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                count = updateContactOptions(contactId, values, callerIsSyncAdapter);
35972e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey                break;
35982e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey            }
35992e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey
36007d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh            case RAW_CONTACTS_DATA: {
36017d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                final String rawContactId = uri.getPathSegments().get(1);
36027d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ")
36037d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                    + (selection == null ? "" : " AND " + selection);
36047d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh
36057d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter);
36067d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh
36077d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh                break;
36087d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh            }
36097d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh
361020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            case DATA: {
3611944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong                count = updateData(uri, values, appendAccountToSelection(uri, selection),
3612f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                        selectionArgs, callerIsSyncAdapter);
361381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
3614f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
361581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
361620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov                break;
361720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
3618c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar
361948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case DATA_ID:
362048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID:
362148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID:
362248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID: {
3623f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter);
362481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
3625f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
362681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
362700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar                break;
362800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar            }
36297e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
36305ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
36315ac5c70d1165309302ebcc931f51723e37d31e0bJeff Sharkey                selection = appendAccountToSelection(uri, selection);
3632dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                count = updateRawContacts(values, selection, selectionArgs, callerIsSyncAdapter);
36337e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
36347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
36357e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
36365ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
363733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
36384529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                if (selection != null) {
36394da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId));
36404da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    count = updateRawContacts(values, RawContacts._ID + "=?"
3641dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                                    + " AND(" + selection + ")", selectionArgs,
3642dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                            callerIsSyncAdapter);
36434529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                } else {
36444da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    mSelectionArgs1[0] = String.valueOf(rawContactId);
3645dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1,
3646dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                            callerIsSyncAdapter);
36474529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                }
36487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana                break;
36497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana            }
36507e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
3651ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
36525aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                count = updateGroups(uri, values, appendAccountToSelection(uri, selection),
3653f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                        selectionArgs, callerIsSyncAdapter);
365481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
3655f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
365681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
3657ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
3658ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
3659ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3660ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
3661ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                long groupId = ContentUris.parseId(uri);
36624da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId));
36634da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                String selectionWithId = Groups._ID + "=? "
366473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov                        + (selection == null ? "" : " AND " + selection);
36655aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                count = updateGroups(uri, values, selectionWithId, selectionArgs,
36665aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey                        callerIsSyncAdapter);
366781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                if (count > 0) {
3668f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                    mSyncToNetwork |= !callerIsSyncAdapter;
366981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                }
3670ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
3671ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
3672ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3673127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
3674de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov                count = updateAggregationException(mDb, values);
3675b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
3676b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
3677b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
3678eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
3679e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                count = updateSettings(uri, values, appendAccountToSelection(uri, selection),
3680e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                        selectionArgs);
368143880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov                mSyncToNetwork |= !callerIsSyncAdapter;
3682eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
3683eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
3684eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
36859705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            case STATUS_UPDATES: {
36869705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                count = updateStatusUpdate(uri, values, selection, selectionArgs);
36879705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                break;
36889705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            }
36899705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
369072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            case DIRECTORIES: {
369172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                mContactDirectoryManager.scheduleDirectoryUpdateForCaller();
369272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                count = 1;
3693d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                break;
3694d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            }
3695d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
369681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            default: {
369781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov                mSyncToNetwork = true;
3698f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.update(uri, values, selection, selectionArgs);
369981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov            }
370000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        }
370100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
370200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar        return count;
37034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
37044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
37059705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    private int updateStatusUpdate(Uri uri, ContentValues values, String selection,
37069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        String[] selectionArgs) {
37079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        // update status_updates table, if status is provided
37089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        // TODO should account type/name be appended to the where clause?
37099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        int updateCount = 0;
37109705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values);
37119705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        if (settableValues.size() > 0) {
37129705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori          updateCount = mDb.update(Tables.STATUS_UPDATES,
37139705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                    settableValues,
37149705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                    getWhereClauseForStatusUpdatesTable(selection),
37159705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                    selectionArgs);
37169705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        }
37179705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
37189705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        // now update the Presence table
37199705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        settableValues = getSettableColumnsForPresenceTable(values);
37209705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        if (settableValues.size() > 0) {
37219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori          updateCount = mDb.update(Tables.PRESENCE, settableValues,
37229705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori                    selection, selectionArgs);
37239705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        }
37249705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        // TODO updateCount is not entirely a valid count of updated rows because 2 tables could
37259705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        // potentially get updated in this method.
37269705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        return updateCount;
37279705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    }
37289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
37299705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    /**
37309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori     * Build a where clause to select the rows to be updated in status_updates table.
37319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori     */
37329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    private String getWhereClauseForStatusUpdatesTable(String selection) {
37339705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mSb.setLength(0);
37349705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE);
37359705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mSb.append(selection);
37369705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mSb.append(")");
37379705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        return mSb.toString();
37389705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    }
37399705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
37409705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) {
37419705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mValues.clear();
37429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values,
37439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.STATUS);
37449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values,
37459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.STATUS_TIMESTAMP);
37469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values,
37479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.STATUS_RES_PACKAGE);
37489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values,
37499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.STATUS_LABEL);
37509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values,
37519705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.STATUS_ICON);
37529705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        return mValues;
37539705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    }
37549705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
37559705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    private ContentValues getSettableColumnsForPresenceTable(ContentValues values) {
37569705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        mValues.clear();
37579705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values,
37589705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori            StatusUpdates.PRESENCE);
3759aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori        ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.CHAT_CAPABILITY, values,
3760aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori                StatusUpdates.CHAT_CAPABILITY);
37619705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori        return mValues;
37629705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori    }
37639705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori
37645aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey    private int updateGroups(Uri uri, ContentValues values, String selectionWithId,
3765f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            String[] selectionArgs, boolean callerIsSyncAdapter) {
376673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
3767ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        mGroupIdCache.clear();
3768ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov
376973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        ContentValues updatedValues;
3770f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana        if (!callerIsSyncAdapter && !values.containsKey(Groups.DIRTY)) {
377173776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = mValues;
377273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.clear();
377373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.putAll(values);
377473776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues.put(Groups.DIRTY, 1);
377573776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        } else {
377673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov            updatedValues = values;
377773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov        }
377873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
3779ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey        int count = mDb.update(Tables.GROUPS, updatedValues, selectionWithId, selectionArgs);
37801a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) {
37811a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
378294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        }
37836ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi        if (updatedValues.containsKey(Groups.SHOULD_SYNC)
37841129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov                && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) {
37856ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            Cursor c = mDb.query(Tables.GROUPS, new String[]{Groups.ACCOUNT_NAME,
3786e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey                    Groups.ACCOUNT_TYPE}, selectionWithId, selectionArgs, null,
37876ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                    null, null);
37886ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            String accountName;
37896ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            String accountType;
37906ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            try {
37916ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                while (c.moveToNext()) {
37926ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                    accountName = c.getString(0);
37936ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                    accountType = c.getString(1);
37946ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                    if(!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
37956ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                        Account account = new Account(accountName, accountType);
3796ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                        ContentResolver.requestSync(account, ContactsContract.AUTHORITY,
37976ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                                new Bundle());
37986ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                        break;
37996ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                    }
38006ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                }
38016ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            } finally {
38026ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi                c.close();
38036ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi            }
38046ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi        }
380594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana        return count;
380694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana    }
380794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana
3808b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov    private int updateSettings(Uri uri, ContentValues values, String selection,
3809b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            String[] selectionArgs) {
3810e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        final int count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs);
38111a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey        if (values.containsKey(Settings.UNGROUPED_VISIBLE)) {
38121a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey            mVisibleTouched = true;
3813e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        }
3814e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey        return count;
3815e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey    }
3816e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
3817dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs,
3818dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            boolean callerIsSyncAdapter) {
38194529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        if (values.containsKey(RawContacts.CONTACT_ID)) {
38204529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " +
38214529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                    "in content values. Contact IDs are assigned automatically");
38224529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        }
382373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov
382497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov        if (!callerIsSyncAdapter) {
382597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov            selection = DatabaseUtils.concatenateWhere(selection,
382697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov                    RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0");
382797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov        }
382897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov
38294529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        int count = 0;
3830b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        Cursor cursor = mDb.query(mDbHelper.getRawContactView(),
383151bf5ea9531b9da72caff607dbdf35fd6f61cbe2Jeff Sharkey                new String[] { RawContacts._ID }, selection,
38324529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                selectionArgs, null, null, null);
38334529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        try {
38344529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            while (cursor.moveToNext()) {
38354529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                long rawContactId = cursor.getLong(0);
3836dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                updateRawContact(rawContactId, values, callerIsSyncAdapter);
38374529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                count++;
38384529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            }
38394529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        } finally {
38404529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov            cursor.close();
38414529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        }
38424529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov
38434529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov        return count;
38444529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov    }
38454529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov
3846dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private int updateRawContact(long rawContactId, ContentValues values,
3847dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            boolean callerIsSyncAdapter) {
384896b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker        final String selection = RawContacts._ID + " = ?";
384996b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker        mSelectionArgs1[0] = Long.toString(rawContactId);
385019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED)
385119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                && values.getAsInteger(RawContacts.DELETED) == 0);
385219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        int previousDeleted = 0;
3853ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        String accountType = null;
3854ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov        String accountName = null;
385519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        if (requestUndoDelete) {
385619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            Cursor cursor = mDb.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, selection,
385796b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker                    mSelectionArgs1, null, null, null);
385819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            try {
385919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                if (cursor.moveToFirst()) {
386019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                    previousDeleted = cursor.getInt(RawContactsQuery.DELETED);
3861ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    accountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE);
3862ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov                    accountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME);
386319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                }
386419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            } finally {
386519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                cursor.close();
386619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            }
386719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            values.put(ContactsContract.RawContacts.AGGREGATION_MODE,
386819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka                    ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT);
386919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka        }
3870f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov
387196b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker        int count = mDb.update(Tables.RAW_CONTACTS, values, selection, mSelectionArgs1);
38725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (count != 0) {
3873f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov            if (values.containsKey(RawContacts.AGGREGATION_MODE)) {
3874f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov                int aggregationMode = values.getAsInteger(RawContacts.AGGREGATION_MODE);
3875f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov
3876f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov                // As per ContactsContract documentation, changing aggregation mode
3877f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov                // to DEFAULT should not trigger aggregation
3878f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov                if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) {
387969cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov                    mContactAggregator.markForAggregation(rawContactId, aggregationMode, false);
3880f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov                }
3881f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov            }
3882433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey            if (values.containsKey(RawContacts.STARRED)) {
3883dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                if (!callerIsSyncAdapter) {
3884dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    updateFavoritesMembership(rawContactId,
3885dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                            values.getAsLong(RawContacts.STARRED) != 0);
3886dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                }
38874529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov                mContactAggregator.updateStarred(rawContactId);
3888dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            } else {
3889dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                // if this raw contact is being associated with an account, then update the
3890dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                // favorites group membership based on whether or not this contact is starred.
3891dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                // If it is starred, add a group membership, if one doesn't already exist
3892dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                // otherwise delete any matching group memberships.
3893dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) {
3894dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    boolean starred = 0 != DatabaseUtils.longForQuery(mDb,
3895dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                            SELECTION_STARRED_FROM_RAW_CONTACTS,
3896dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                            new String[]{Long.toString(rawContactId)});
3897dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    updateFavoritesMembership(rawContactId, starred);
3898dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                }
3899dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
3900dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
3901dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            // if this raw contact is being associated with an account, then add a
3902dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            // group membership to the group marked as AutoAdd, if any.
3903dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            if (!callerIsSyncAdapter && values.containsKey(RawContacts.ACCOUNT_NAME)) {
3904dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                addAutoAddMembership(rawContactId);
3905433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey            }
3906dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
3907285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            if (values.containsKey(RawContacts.SOURCE_ID)) {
39082b7a632bba423357ae5641f94da6a2f71afc523bDmitri Plotnikov                mContactAggregator.updateLookupKeyForRawContact(mDb, rawContactId);
3909285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov            }
3910f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov            if (values.containsKey(RawContacts.NAME_VERIFIED)) {
3911f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov
3912f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                // If setting NAME_VERIFIED for this raw contact, reset it for all
3913f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                // other raw contacts in the same aggregate
3914f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) {
391578fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov                    mDbHelper.resetNameVerifiedForOtherRawContacts(rawContactId);
3916f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                }
3917f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov                mContactAggregator.updateDisplayNameForRawContact(mDb, rawContactId);
3918f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov            }
391919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            if (requestUndoDelete && previousDeleted == 1) {
3920d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                mTransactionContext.rawContactInserted(rawContactId,
3921d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov                        new Account(accountName, accountType));
392219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka            }
39235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
39245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return count;
392533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov    }
392633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov
3927321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    private int updateData(Uri uri, ContentValues values, String selection,
3928f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana            String[] selectionArgs, boolean callerIsSyncAdapter) {
392920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.clear();
393020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.putAll(values);
393120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data._ID);
39325ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        mValues.remove(Data.RAW_CONTACT_ID);
393320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        mValues.remove(Data.MIMETYPE);
393420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
393520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        String packageName = values.getAsString(Data.RES_PACKAGE);
393620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        if (packageName != null) {
393720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            mValues.remove(Data.RES_PACKAGE);
3938b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov            mValues.put(DataColumns.PACKAGE_ID, mDbHelper.getPackageId(packageName));
393920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
394020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
394197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov        if (!callerIsSyncAdapter) {
394297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov            selection = DatabaseUtils.concatenateWhere(selection,
394397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov                    Data.IS_READ_ONLY + "=0");
394497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov        }
394597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov
3946653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        int count = 0;
394720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
3948653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        // Note that the query will return data according to the access restrictions,
3949653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        // so we don't need to worry about updating data we don't have permission to read.
395014bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        Cursor c = query(uri, DataUpdateQuery.COLUMNS, selection, selectionArgs, null);
3951653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        try {
3952653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            while(c.moveToNext()) {
3953f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana                count += updateData(mValues, c, callerIsSyncAdapter);
395420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov            }
3955653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        } finally {
3956653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            c.close();
395720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov        }
395820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
3959653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        return count;
396020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov    }
396120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov
3962f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana    private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) {
3963653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov        if (values.size() == 0) {
3964653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov            return 0;
3965321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana        }
3966653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov
396714bba94bbe0f2e215ad7b3b9417754a1ba0d95bfDmitri Plotnikov        final String mimeType = c.getString(DataUpdateQuery.MIMETYPE);
3968a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        DataRowHandler rowHandler = getDataRowHandler(mimeType);
3969d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov        if (rowHandler.update(mDb, mTransactionContext, values, c, callerIsSyncAdapter)) {
3970813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return 1;
3971813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov        } else {
3972813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return 0;
3973a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov        }
3974321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana    }
3975321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana
39768c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov    private int updateContactOptions(ContentValues values, String selection,
3977dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            String[] selectionArgs, boolean callerIsSyncAdapter) {
39788c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        int count = 0;
3979b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        Cursor cursor = mDb.query(mDbHelper.getContactView(),
39808c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                new String[] { Contacts._ID }, selection,
39818c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                selectionArgs, null, null, null);
39828c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        try {
39838c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            while (cursor.moveToNext()) {
39848c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                long contactId = cursor.getLong(0);
3985dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                updateContactOptions(contactId, values, callerIsSyncAdapter);
39868c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                count++;
39878c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            }
39888c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        } finally {
39898c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            cursor.close();
39908c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        }
39918c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
39928c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        return count;
39938c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov    }
39948c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
3995dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private int updateContactOptions(long contactId, ContentValues values,
3996dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            boolean callerIsSyncAdapter) {
3997d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
39988c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        mValues.clear();
3999b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE,
4000d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.CUSTOM_RINGTONE);
4001b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL,
4002d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.SEND_TO_VOICEMAIL);
4003b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED,
4004d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.LAST_TIME_CONTACTED);
4005b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED,
4006d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.TIMES_CONTACTED);
4007b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED,
4008d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                values, Contacts.STARRED);
4009d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
4010d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        // Nothing to update - just return
40118c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        if (mValues.size() == 0) {
4012d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov            return 0;
4013d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov        }
4014d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
40158c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        if (mValues.containsKey(RawContacts.STARRED)) {
4016c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey            // Mark dirty when changing starred to trigger sync
40178c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov            mValues.put(RawContacts.DIRTY, 1);
4018c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey        }
4019c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey
40204da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(contactId);
402197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov        mDb.update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?"
402297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov                + " AND " + RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0", mSelectionArgs1);
40238c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
4024dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        if (mValues.containsKey(RawContacts.STARRED) && !callerIsSyncAdapter) {
4025dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            Cursor cursor = mDb.query(mDbHelper.getRawContactView(),
4026dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=?",
4027dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    mSelectionArgs1, null, null, null);
4028dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            try {
4029dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                while (cursor.moveToNext()) {
4030dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    long rawContactId = cursor.getLong(0);
4031dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                    updateFavoritesMembership(rawContactId,
4032dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                            mValues.getAsLong(RawContacts.STARRED) != 0);
4033dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                }
4034dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            } finally {
4035dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                cursor.close();
4036dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            }
4037dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana        }
4038dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana
40398c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        // Copy changeable values to prevent automatically managed fields from
40408c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        // being explicitly updated by clients.
40418c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov        mValues.clear();
4042b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE,
40438c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.CUSTOM_RINGTONE);
4044b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL,
40458c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.SEND_TO_VOICEMAIL);
4046b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED,
40478c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.LAST_TIME_CONTACTED);
4048b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED,
40498c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.TIMES_CONTACTED);
4050b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED,
40518c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov                values, Contacts.STARRED);
40528c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov
40539b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori        int rslt = mDb.update(Tables.CONTACTS, mValues, Contacts._ID + "=?", mSelectionArgs1);
40546e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori
40559b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori        if (values.containsKey(Contacts.LAST_TIME_CONTACTED) &&
40569b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori                !values.containsKey(Contacts.TIMES_CONTACTED)) {
40579b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            mDb.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1);
40589b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori            mDb.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1);
40599b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori        }
40609b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori        return rslt;
4061f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov    }
4062d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov
4063127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov    private int updateAggregationException(SQLiteDatabase db, ContentValues values) {
4064127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        int exceptionType = values.getAsInteger(AggregationExceptions.TYPE);
40650c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1);
40660c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2);
406780c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov
40680c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        long rawContactId1, rawContactId2;
40690c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        if (rcId1 < rcId2) {
40700c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId1 = rcId1;
40710c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId2 = rcId2;
40720c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        } else {
40730c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId2 = rcId1;
40740c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            rawContactId1 = rcId2;
4075b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov        }
4076127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
40770c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) {
40784da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs2[0] = String.valueOf(rawContactId1);
40794da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov            mSelectionArgs2[1] = String.valueOf(rawContactId2);
40800c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            db.delete(Tables.AGGREGATION_EXCEPTIONS,
40814da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    AggregationExceptions.RAW_CONTACT_ID1 + "=? AND "
40824da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                    + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2);
40830c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov        } else {
40846bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov            ContentValues exceptionValues = new ContentValues(3);
40856bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov            exceptionValues.put(AggregationExceptions.TYPE, exceptionType);
40860c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
40870c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
40880c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov            db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID,
40890c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov                    exceptionValues);
4090127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        }
4091127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
40923389f7c7df6c90e48fcb0c27832bc322e5b20bf6Dmitri Plotnikov        mContactAggregator.invalidateAggregationExceptionCache();
409369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov        mContactAggregator.markForAggregation(rawContactId1,
409469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov                RawContacts.AGGREGATION_MODE_DEFAULT, true);
409569cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov        mContactAggregator.markForAggregation(rawContactId2,
409669cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov                RawContacts.AGGREGATION_MODE_DEFAULT, true);
4097dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov
40980dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        mContactAggregator.aggregateContact(db, rawContactId1);
40990dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        mContactAggregator.aggregateContact(db, rawContactId2);
4100127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov
4101127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // The return value is fake - we just confirm that we made a change, not count actual
4102127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        // rows changed.
4103127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov        return 1;
4104b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov    }
4105b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
410670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong    public void onAccountsUpdated(Account[] accounts) {
4107afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov        boolean accountsChanged = updateAccounts(accounts);
4108afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov        if (accountsChanged) {
41091b2a89588e9593756c2627ce1683539f4ffa1e51Dmitri Plotnikov            mContactDirectoryManager.scheduleScanAllPackages(true);
4110afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov        }
4111afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov    }
4112afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov
41133826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov    protected void updateAccounts() {
41143826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        AccountManager.get(getContext()).addOnAccountsUpdatedListener(this, null, false);
41153826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        Account[] accounts = AccountManager.get(getContext()).getAccounts();
41163826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        updateAccounts(accounts);
41173826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        updateContactsAccountCount(accounts);
41183826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov    }
41193826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
4120afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov    private boolean updateAccounts(Account[] accounts) {
4121f8536aaa7a52b9a7a353bc54e158becdbe79ec87Bai Tao        // TODO : Check the unit test.
4122e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov        boolean accountsChanged = false;
4123627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        HashSet<Account> existingAccounts = new HashSet<Account>();
412449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov        mDb = mDbHelper.getWritableDatabase();
412570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        mDb.beginTransaction();
412670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        try {
4127dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana            findValidAccounts(existingAccounts);
4128743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov
4129743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov            // Add a row to the ACCOUNTS table for each new account
4130743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov            for (Account account : accounts) {
4131743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov                if (!existingAccounts.contains(account)) {
4132e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                    accountsChanged = true;
4133743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov                    mDb.execSQL("INSERT INTO " + Tables.ACCOUNTS + " (" + RawContacts.ACCOUNT_NAME
4134743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov                            + ", " + RawContacts.ACCOUNT_TYPE + ") VALUES (?, ?)",
4135743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov                            new String[] {account.name, account.type});
4136743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov                }
4137743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov            }
413848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
4139627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            // Remove all valid accounts from the existing account set. What is left
4140743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov            // in the accountsToDelete set will be extra accounts whose data must be deleted.
4141627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            HashSet<Account> accountsToDelete = new HashSet<Account>(existingAccounts);
4142627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            for (Account account : accounts) {
4143627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                accountsToDelete.remove(account);
414470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            }
414570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong
414633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov            if (!accountsToDelete.isEmpty()) {
4147e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                accountsChanged = true;
4148e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                for (Account account : accountsToDelete) {
4149e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                    Log.d(TAG, "removing data for removed account " + account);
4150e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                    String[] params = new String[] {account.name, account.type};
4151e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                    mDb.execSQL(
4152e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            "DELETE FROM " + Tables.GROUPS +
4153e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            " WHERE " + Groups.ACCOUNT_NAME + " = ?" +
4154e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                                    " AND " + Groups.ACCOUNT_TYPE + " = ?", params);
4155e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                    mDb.execSQL(
4156e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            "DELETE FROM " + Tables.PRESENCE +
4157e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" +
4158e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                                    "SELECT " + RawContacts._ID +
4159e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                                    " FROM " + Tables.RAW_CONTACTS +
4160e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                                    " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" +
4161e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                                    " AND " + RawContacts.ACCOUNT_TYPE + " = ?)", params);
4162e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                    mDb.execSQL(
4163e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            "DELETE FROM " + Tables.RAW_CONTACTS +
4164e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            " WHERE " + RawContacts.ACCOUNT_NAME + " = ?" +
4165e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            " AND " + RawContacts.ACCOUNT_TYPE + " = ?", params);
4166e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                    mDb.execSQL(
4167e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            "DELETE FROM " + Tables.SETTINGS +
4168e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            " WHERE " + Settings.ACCOUNT_NAME + " = ?" +
4169e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            " AND " + Settings.ACCOUNT_TYPE + " = ?", params);
4170e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                    mDb.execSQL(
4171e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            "DELETE FROM " + Tables.ACCOUNTS +
4172e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            " WHERE " + RawContacts.ACCOUNT_NAME + "=?" +
4173e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                            " AND " + RawContacts.ACCOUNT_TYPE + "=?", params);
4174d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                    mDb.execSQL(
4175d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                            "DELETE FROM " + Tables.DIRECTORIES +
4176d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                            " WHERE " + Directory.ACCOUNT_NAME + "=?" +
4177d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                            " AND " + Directory.ACCOUNT_TYPE + "=?", params);
41784458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                    resetDirectoryCache();
4179e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                }
4180e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov
418133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                // Find all aggregated contacts that used to contain the raw contacts
418233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                // we have just deleted and see if they are still referencing the deleted
4183e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                // names or photos.  If so, fix up those contacts.
418433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                HashSet<Long> orphanContactIds = Sets.newHashSet();
418533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                Cursor cursor = mDb.rawQuery("SELECT " + Contacts._ID +
418633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                        " FROM " + Tables.CONTACTS +
418733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                        " WHERE (" + Contacts.NAME_RAW_CONTACT_ID + " NOT NULL AND " +
418869cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov                                Contacts.NAME_RAW_CONTACT_ID + " NOT IN " +
418969cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov                                        "(SELECT " + RawContacts._ID +
419069cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov                                        " FROM " + Tables.RAW_CONTACTS + "))" +
419133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                        " OR (" + Contacts.PHOTO_ID + " NOT NULL AND " +
419233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                                Contacts.PHOTO_ID + " NOT IN " +
419369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov                                        "(SELECT " + Data._ID +
419469cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov                                        " FROM " + Tables.DATA + "))", null);
419533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                try {
419633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                    while (cursor.moveToNext()) {
419733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                        orphanContactIds.add(cursor.getLong(0));
419833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                    }
419933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                } finally {
420033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                    cursor.close();
420133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                }
420233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov
420333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                for (Long contactId : orphanContactIds) {
420433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                    mContactAggregator.updateAggregateData(contactId);
420533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov                }
4206e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                mDbHelper.updateAllVisible();
420733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov            }
420833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov
4209e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov            if (accountsChanged) {
4210e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov                mDbHelper.getSyncState().onAccountsChanged(mDb, accounts);
4211e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov            }
421270d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            mDb.setTransactionSuccessful();
421370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        } finally {
421470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong            mDb.endTransaction();
421549d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov            mDb = null;
421670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong        }
421773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov        mAccountWritability.clear();
42183826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
42193826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        if (accountsChanged) {
42203826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            updateContactsAccountCount(accounts);
42213826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            updateProviderStatus();
42223826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        }
42233826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
4224afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov        return accountsChanged;
422570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong    }
4226619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
42273826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov    private void updateContactsAccountCount(Account[] accounts) {
42283826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        int count = 0;
42293826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        for (Account account : accounts) {
42303826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            if (isContactsAccount(account)) {
42313826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov                count++;
42323826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            }
42333826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        }
42343826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        mContactsAccountCount = count;
42353826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov    }
42363826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
42373826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov    protected boolean isContactsAccount(Account account) {
42383826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        final IContentService cs = ContentResolver.getContentService();
42393826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        try {
42403826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            return cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0;
42413826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        } catch (RemoteException e) {
42423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            Log.e(TAG, "Cannot obtain sync flag for account: " + account, e);
42433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov            return false;
42443826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov        }
42453826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov    }
42463826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov
424772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    public void onPackageChanged(String packageName) {
424872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        mContactDirectoryManager.onPackageChanged(packageName);
4249d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    }
4250d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
4251619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
4252627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov     * Finds all distinct accounts present in the specified table.
4253627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov     */
4254dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana    private void findValidAccounts(Set<Account> validAccounts) {
4255743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov        Cursor c = mDb.rawQuery(
4256743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov                "SELECT " + RawContacts.ACCOUNT_NAME + "," + RawContacts.ACCOUNT_TYPE +
4257743eac356404195f236ad44379fe9d180beb5bf2Dmitri Plotnikov                " FROM " + Tables.ACCOUNTS, null);
4258627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        try {
4259627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            while (c.moveToNext()) {
4260dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana                if (!c.isNull(0) || !c.isNull(1)) {
4261627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                    validAccounts.add(new Account(c.getString(0), c.getString(1)));
4262627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                }
4263627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            }
4264627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        } finally {
4265627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            c.close();
4266627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        }
4267627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov    }
4268627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov
4269627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov    /**
4270622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey     * Test all against {@link TextUtils#isEmpty(CharSequence)}.
4271622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey     */
427267c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov    private static boolean areAllEmpty(ContentValues values, String[] keys) {
427367c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov        for (String key : keys) {
427467c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            if (!TextUtils.isEmpty(values.getAsString(key))) {
427567c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov                return false;
427667c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov            }
427767c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov        }
427867c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov        return true;
427967c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov    }
428067c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov
428167c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov    /**
428267c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov     * Returns true if a value (possibly null) is specified for at least one of the supplied keys.
428367c9ed1cefa5c084d3f373d7f1ecb7122983ff15Dmitri Plotnikov     */
4284dd0e0f44fe403ff201d46d5534f7f1148e5ad729Dmitri Plotnikov    private static boolean areAnySpecified(ContentValues values, String[] keys) {
4285622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        for (String key : keys) {
4286dd0e0f44fe403ff201d46d5534f7f1148e5ad729Dmitri Plotnikov            if (values.containsKey(key)) {
4287dd0e0f44fe403ff201d46d5534f7f1148e5ad729Dmitri Plotnikov                return true;
4288622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey            }
4289622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey        }
4290dd0e0f44fe403ff201d46d5534f7f1148e5ad729Dmitri Plotnikov        return false;
4291622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey    }
4292622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey
42934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
42944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
42954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            String sortOrder) {
4296d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY);
4297385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov        if (directory == null) {
4298385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov            return queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1);
4299385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov        } else if (directory.equals("0")) {
4300385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov            return queryLocal(uri, projection, selection, selectionArgs, sortOrder,
4301385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov                    Directory.DEFAULT);
4302d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        } else if (directory.equals("1")) {
4303385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov            return queryLocal(uri, projection, selection, selectionArgs, sortOrder,
4304385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov                    Directory.LOCAL_INVISIBLE);
4305d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        }
4306d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
4307d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        DirectoryInfo directoryInfo = getDirectoryAuthority(directory);
4308d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        if (directoryInfo == null) {
4309a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov            Log.e(TAG, "Invalid directory ID: " + uri);
4310a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov            return null;
4311d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        }
4312d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
4313d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        Builder builder = new Uri.Builder();
4314d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        builder.scheme(ContentResolver.SCHEME_CONTENT);
4315d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        builder.authority(directoryInfo.authority);
4316d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        builder.encodedPath(uri.getEncodedPath());
4317d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        if (directoryInfo.accountName != null) {
4318d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName);
4319d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        }
4320d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        if (directoryInfo.accountType != null) {
4321d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType);
4322d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        }
43232e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov
43242e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov        String limit = getLimit(uri);
43252e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov        if (limit != null) {
43262e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov            builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit);
43272e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov        }
43282e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov
4329d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        Uri directoryUri = builder.build();
433009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
433109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov        if (projection == null) {
433209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            projection = getDefaultProjection(uri);
433309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov        }
433409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
4335332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov        Cursor cursor = getContext().getContentResolver().query(directoryUri, projection, selection,
4336d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                selectionArgs, sortOrder);
4337332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov        while (cursor instanceof CursorWrapper) {
4338332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov            cursor = ((CursorWrapper)cursor).getWrappedCursor();
4339332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov        }
4340332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov        return cursor;
4341d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    }
4342d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
4343d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    private static final class DirectoryQuery {
4344d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        public static final String[] COLUMNS = new String[] {
4345d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                Directory._ID,
4346d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                Directory.DIRECTORY_AUTHORITY,
4347d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                Directory.ACCOUNT_NAME,
4348d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                Directory.ACCOUNT_TYPE
4349d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        };
4350d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
4351d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        public static final int DIRECTORY_ID = 0;
4352d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        public static final int AUTHORITY = 1;
4353d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        public static final int ACCOUNT_NAME = 2;
4354d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        public static final int ACCOUNT_TYPE = 3;
4355d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    }
4356d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
4357d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    /**
4358d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov     * Reads and caches directory information for the database.
4359d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov     */
4360d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    private DirectoryInfo getDirectoryAuthority(String directoryId) {
43614458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov        synchronized (mDirectoryCache) {
43624458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov            if (!mDirectoryCacheValid) {
43634458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                mDirectoryCache.clear();
436449d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov                SQLiteDatabase db = mDbHelper.getReadableDatabase();
436549d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov                Cursor cursor = db.query(Tables.DIRECTORIES,
43664458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                        DirectoryQuery.COLUMNS,
43674458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                        null, null, null, null, null);
43684458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                try {
43694458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                    while (cursor.moveToNext()) {
43704458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                        DirectoryInfo info = new DirectoryInfo();
43714458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                        String id = cursor.getString(DirectoryQuery.DIRECTORY_ID);
43724458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                        info.authority = cursor.getString(DirectoryQuery.AUTHORITY);
43734458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                        info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME);
43744458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                        info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE);
43754458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                        mDirectoryCache.put(id, info);
43764458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                    }
43774458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                } finally {
43784458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                    cursor.close();
4379d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                }
43804458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov                mDirectoryCacheValid = true;
4381d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            }
4382d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
43834458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov            return mDirectoryCache.get(directoryId);
43844458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov        }
4385d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    }
4386d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
438772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    public void resetDirectoryCache() {
43884458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov        synchronized(mDirectoryCache) {
43894458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov            mDirectoryCacheValid = false;
43904458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov        }
439172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
439272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
4393d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov    public Cursor queryLocal(Uri uri, String[] projection, String selection, String[] selectionArgs,
4394385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov                String sortOrder, long directoryId) {
4395bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        if (VERBOSE_LOGGING) {
4396bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov            Log.v(TAG, "query: " + uri);
4397bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov        }
43980b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov
4399b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        final SQLiteDatabase db = mDbHelper.getReadableDatabase();
440035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
4401d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
44021f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey        String groupBy = null;
4403c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        String limit = getLimit(uri);
4404c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
4405619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // TODO: Consider writing a test case for RestrictionExceptions when you
4406619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        // write a new query() block to make sure it protects restricted data.
4407a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
44084f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
440935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana            case SYNCSTATE:
4410b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getSyncState().query(db, projection, selection,  selectionArgs,
441135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana                        sortOrder);
441235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana
4413d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS: {
4414763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
4415385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov                appendLocalDirectorySelectionIfNeeded(qb, directoryId);
4416619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                break;
4417619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            }
4418619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
4419d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov            case CONTACTS_ID: {
44204a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = ContentUris.parseId(uri);
4421763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
44224da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId));
44234da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(Contacts._ID + "=?");
44246bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
44256bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
44266bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov
44275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            case CONTACTS_LOOKUP:
44285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            case CONTACTS_LOOKUP_ID: {
44295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                List<String> pathSegments = uri.getPathSegments();
44305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int segmentCount = pathSegments.size();
44315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segmentCount < 3) {
4432fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                    throw new IllegalArgumentException(mDbHelper.exceptionMessage(
4433fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                            "Missing a lookup key", uri));
44345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
4435a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
44365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String lookupKey = pathSegments.get(2);
44375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segmentCount == 4) {
44385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    long contactId = Long.parseLong(pathSegments.get(3));
44395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder();
4440763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                    setTablesAndProjectionMapForContacts(lookupQb, uri, projection);
4441a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
4442a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri,
4443a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            projection, selection, selectionArgs, sortOrder, groupBy, limit,
4444a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey);
4445a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    if (c != null) {
44465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        return c;
44475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
44485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
44495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
4450763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
44514da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs,
44524da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        String.valueOf(lookupContactIdByLookupKey(db, lookupKey)));
44534da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(Contacts._ID + "=?");
44545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                break;
44555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
44565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
44572149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov            case CONTACTS_LOOKUP_DATA:
44582149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov            case CONTACTS_LOOKUP_ID_DATA: {
44592149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                List<String> pathSegments = uri.getPathSegments();
44602149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                int segmentCount = pathSegments.size();
44612149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                if (segmentCount < 4) {
44622149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                    throw new IllegalArgumentException(mDbHelper.exceptionMessage(
44632149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                            "Missing a lookup key", uri));
44642149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                }
44652149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                String lookupKey = pathSegments.get(2);
44662149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                if (segmentCount == 5) {
44672149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                    long contactId = Long.parseLong(pathSegments.get(3));
44682149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                    SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder();
44692149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                    setTablesAndProjectionMapForData(lookupQb, uri, projection, false);
4470a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    lookupQb.appendWhere(" AND ");
4471a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri,
4472a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            projection, selection, selectionArgs, sortOrder, groupBy, limit,
4473a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            Data.CONTACT_ID, contactId, Data.LOOKUP_KEY, lookupKey);
4474a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    if (c != null) {
44752149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                        return c;
44762149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                    }
44772149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov
44782149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                    // TODO see if the contact exists but has no data rows (rare)
44792149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                }
44802149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov
44812149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
44822149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs,
44832149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                        String.valueOf(lookupContactIdByLookupKey(db, lookupKey)));
44842149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                qb.appendWhere(" AND " + Data.CONTACT_ID + "=?");
44852149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov                break;
44862149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov            }
44872149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov
4488f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey            case CONTACTS_AS_VCARD: {
4489f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey                // When reading as vCard always use restricted view
449042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                final String lookupKey = Uri.encode(uri.getPathSegments().get(2));
4491763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                qb.setTables(mDbHelper.getContactView(true /* require restricted */));
4492f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey                qb.setProjectionMap(sContactsVCardProjectionMap);
44934da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs,
44944da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        String.valueOf(lookupContactIdByLookupKey(db, lookupKey)));
44954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(Contacts._ID + "=?");
4496f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey                break;
4497f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey            }
4498f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey
449942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann            case CONTACTS_AS_MULTI_VCARD: {
450042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
450142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                String currentDateString = dateFormat.format(new Date()).toString();
450242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                return db.rawQuery(
450342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                    "SELECT" +
450442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                    " 'vcards_' || ? || '.vcf' AS " + OpenableColumns.DISPLAY_NAME + "," +
450542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                    " NULL AS " + OpenableColumns.SIZE,
450642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                    new String[] { currentDateString });
450742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann            }
450842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann
4509ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_FILTER: {
4510916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov                String filterParam = "";
4511ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
4512916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov                    filterParam = uri.getLastPathSegment();
4513ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
4514916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov                setTablesAndProjectionMapForContactsWithSnippet(qb, uri, projection, filterParam);
4515385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov                appendLocalDirectorySelectionIfNeeded(qb, directoryId);
4516ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
4517ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
4518ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
4519ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_STREQUENT_FILTER:
4520ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_STREQUENT: {
45214a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                String filterSql = null;
4522ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov                if (match == CONTACTS_STREQUENT_FILTER
4523d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        && uri.getPathSegments().size() > 3) {
45244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
45254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
4526e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov                    sb.append(Contacts._ID + " IN ");
45275e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    appendContactFilterAsNestedQuery(sb, filterParam);
45284a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    filterSql = sb.toString();
45294a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
45304a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
4531763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
4532ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
45335e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                String[] starredProjection = null;
45345e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                String[] frequentProjection = null;
45355e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                if (projection != null) {
4536dd300fe5f5a1071b1c135af7c76e3ae149edda4dDmitri Plotnikov                    starredProjection =
4537dd300fe5f5a1071b1c135af7c76e3ae149edda4dDmitri Plotnikov                            appendProjectionArg(projection, TIMES_CONTACTED_SORT_COLUMN);
4538dd300fe5f5a1071b1c135af7c76e3ae149edda4dDmitri Plotnikov                    frequentProjection =
4539dd300fe5f5a1071b1c135af7c76e3ae149edda4dDmitri Plotnikov                            appendProjectionArg(projection, TIMES_CONTACTED_SORT_COLUMN);
45405e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                }
45415e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar
45424a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                // Build the first query for starred
45434a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
45444a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
4545d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
45465e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                qb.setProjectionMap(sStrequentStarredProjectionMap);
45475e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                final String starredQuery = qb.buildQuery(starredProjection, Contacts.STARRED + "=1",
45484a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
4549d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
4550d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Build the second query for frequent
4551d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                qb = new SQLiteQueryBuilder();
4552763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
45534a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (filterSql != null) {
45544a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    qb.appendWhere(filterSql);
4555d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
45565e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                qb.setProjectionMap(sStrequentFrequentProjectionMap);
45575e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar                final String frequentQuery = qb.buildQuery(frequentProjection,
4558d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        Contacts.TIMES_CONTACTED + " > 0 AND (" + Contacts.STARRED
4559d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                        + " = 0 OR " + Contacts.STARRED + " IS NULL)",
45604a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                        null, Contacts._ID, null, null, null);
4561d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
4562d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                // Put them together
4563d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                final String query = qb.buildUnionQuery(new String[] {starredQuery, frequentQuery},
4564d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                        STREQUENT_ORDER_BY, STREQUENT_LIMIT);
45654a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                Cursor c = db.rawQuery(query, null);
45664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (c != null) {
4567d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                    c.setNotificationUri(getContext().getContentResolver(),
4568d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                            ContactsContract.AUTHORITY_URI);
4569d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                }
4570d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar                return c;
4571d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar            }
4572d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar
4573ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov            case CONTACTS_GROUP: {
4574763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
4575b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                if (uri.getPathSegments().size() > 2) {
457671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                    qb.appendWhere(CONTACTS_IN_GROUP_SELECT);
45774a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
4578b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                }
4579b67163a1088f09c59f324350662eb18772fac6b6Evan Millar                break;
4580b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            }
4581b67163a1088f09c59f324350662eb18772fac6b6Evan Millar
4582a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            case CONTACTS_ID_DATA: {
45834a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
458482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
45854da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId));
45864da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?");
45876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov                break;
45886bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov            }
458900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar
4590a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            case CONTACTS_ID_PHOTO: {
45913653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
459282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
45934da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId));
45944da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?");
45953653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID);
45963653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov                break;
45973653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov            }
45983653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov
4599a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            case CONTACTS_ID_ENTITIES: {
4600a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
4601a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                setTablesAndProjectionMapForEntities(qb, uri, projection);
4602a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId));
4603a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?");
4604a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                break;
4605a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            }
4606a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
4607a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            case CONTACTS_LOOKUP_ENTITIES:
4608a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            case CONTACTS_LOOKUP_ID_ENTITIES: {
4609a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                List<String> pathSegments = uri.getPathSegments();
4610a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                int segmentCount = pathSegments.size();
4611a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                if (segmentCount < 4) {
4612a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    throw new IllegalArgumentException(mDbHelper.exceptionMessage(
4613a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            "Missing a lookup key", uri));
4614a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                }
4615a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                String lookupKey = pathSegments.get(2);
4616a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                if (segmentCount == 5) {
4617a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    long contactId = Long.parseLong(pathSegments.get(3));
4618a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder();
4619a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    setTablesAndProjectionMapForEntities(lookupQb, uri, projection);
4620a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    lookupQb.appendWhere(" AND ");
4621a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
4622a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri,
4623a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            projection, selection, selectionArgs, sortOrder, groupBy, limit,
4624a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            Contacts.Entity.CONTACT_ID, contactId,
4625a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            Contacts.Entity.LOOKUP_KEY, lookupKey);
4626a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    if (c != null) {
4627a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                        return c;
4628a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    }
4629a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                }
4630a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
4631a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                setTablesAndProjectionMapForEntities(qb, uri, projection);
4632a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs,
4633a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                        String.valueOf(lookupContactIdByLookupKey(db, lookupKey)));
4634a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                qb.appendWhere(" AND " + Contacts.Entity.CONTACT_ID + "=?");
4635a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                break;
4636a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            }
4637a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
46384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case PHONES: {
463982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
464089c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
46412815f58f72f109790585931f601a63ddc02536a5Evan Millar                break;
46422815f58f72f109790585931f601a63ddc02536a5Evan Millar            }
46432815f58f72f109790585931f601a63ddc02536a5Evan Millar
464448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID: {
464582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
46464da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
464748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
46484da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=?");
464948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                break;
465048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            }
465148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
4652ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case PHONES_FILTER: {
465382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, true);
465489c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Phone.CONTENT_ITEM_TYPE + "'");
4655ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                if (uri.getPathSegments().size() > 2) {
46564a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    String filterParam = uri.getLastPathSegment();
46574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    StringBuilder sb = new StringBuilder();
4658a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov                    sb.append(" AND (");
46595e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
466045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov                    boolean hasCondition = false;
46615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    boolean orNeeded = false;
46625e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    String normalizedName = NameNormalizer.normalize(filterParam);
46635e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    if (normalizedName.length() > 0) {
46645e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append(Data.RAW_CONTACT_ID + " IN ");
46657318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov                        appendRawContactsByNormalizedNameFilter(sb, normalizedName, false);
46665e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        orNeeded = true;
466745d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov                        hasCondition = true;
46685e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    }
46695e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
4670892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    String number = PhoneNumberUtils.normalizeNumber(filterParam);
4671892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    if (!TextUtils.isEmpty(number)) {
46725e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        if (orNeeded) {
46735e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                            sb.append(" OR ");
46745e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        }
46755e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                        sb.append(Data._ID +
4676892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                                " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID
4677892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                                + " FROM " + Tables.PHONE_LOOKUP
4678892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                                + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '");
4679892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                        sb.append(number);
4680892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                        sb.append("%')");
468145d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov                        hasCondition = true;
468245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov                    }
468345d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov
468445d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov                    if (!hasCondition) {
468545d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov                        // If it is neither a phone number nor a name, the query should return
468645d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov                        // an empty cursor.  Let's ensure that.
468745d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov                        sb.append("0");
46885e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    }
46895e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    sb.append(")");
4690a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov                    qb.appendWhere(sb);
4691ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                }
46925e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                groupBy = PhoneColumns.NORMALIZED_NUMBER + "," + RawContacts.CONTACT_ID;
4693a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                if (sortOrder == null) {
4694a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                    sortOrder = Contacts.IN_VISIBLE_GROUP + " DESC, " + RawContacts.CONTACT_ID;
4695a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                }
4696ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
4697ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
4698ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
46994a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            case EMAILS: {
470082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
470189c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
47024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                break;
47034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            }
47044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
470548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID: {
470682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
47074da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
47084da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'"
47094da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        + " AND " + Data._ID + "=?");
471048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                break;
471148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            }
471248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
47135e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            case EMAILS_LOOKUP: {
471482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
471589c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'");
47164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                if (uri.getPathSegments().size() > 2) {
471708768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov                    String email = uri.getLastPathSegment();
471808768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov                    String address = mDbHelper.extractAddressFromEmailAddress(email);
471908768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov                    selectionArgs = insertSelectionArg(selectionArgs, address);
472008768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov                    qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)");
47214a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                }
4722ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
4723ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
4724ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
47255e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            case EMAILS_FILTER: {
472682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, true);
472707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                String filterParam = null;
472807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                if (uri.getPathSegments().size() > 3) {
472907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    filterParam = uri.getLastPathSegment();
473007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    if (TextUtils.isEmpty(filterParam)) {
473107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                        filterParam = null;
473207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    }
473307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                }
47345e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
473507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                if (filterParam == null) {
473607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    // If the filter is unspecified, return nothing
473707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    qb.appendWhere(" AND 0");
473807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                } else {
473907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    StringBuilder sb = new StringBuilder();
474007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    sb.append(" AND " + Data._ID + " IN (");
474107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    sb.append(
474207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                            "SELECT " + Data._ID +
474307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                            " FROM " + Tables.DATA +
47442a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov                            " WHERE " + DataColumns.MIMETYPE_ID + "=");
47452a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov                    sb.append(mDbHelper.getMimeTypeIdForEmail());
47462a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov                    sb.append(" AND " + Data.DATA1 + " LIKE ");
474707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                    DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%');
474820938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov                    if (!filterParam.contains("@")) {
474920938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov                        String normalizedName = NameNormalizer.normalize(filterParam);
475020938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov                        if (normalizedName.length() > 0) {
475107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov
475207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                            /*
475307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * Using a UNION instead of an "OR" to make SQLite use the right
475407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * indexes. We need it to use the (mimetype,data1) index for the
475507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * email lookup (see above), but not for the name lookup.
475607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * SQLite is not smart enough to use the index on one side of an OR
475707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * but not on the other. Using two separate nested queries
475807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             * and a UNION between them does the job.
475907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                             */
476007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                            sb.append(
476107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                                    " UNION SELECT " + Data._ID +
476207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov                                    " FROM " + Tables.DATA +
47632a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov                                    " WHERE +" + DataColumns.MIMETYPE_ID + "=");
47642a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov                            sb.append(mDbHelper.getMimeTypeIdForEmail());
47652a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov                            sb.append(" AND " + Data.RAW_CONTACT_ID + " IN ");
47667318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov                            appendRawContactsByNormalizedNameFilter(sb, normalizedName, false);
476720938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov                        }
47685e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    }
47695e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                    sb.append(")");
4770a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov                    qb.appendWhere(sb);
47715e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                }
47725e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                groupBy = Email.DATA + "," + RawContacts.CONTACT_ID;
4773a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                if (sortOrder == null) {
4774c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov                    sortOrder = EMAIL_FILTER_SORT_ORDER;
4775a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov                }
47765e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov                break;
47775e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov            }
47785e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
4779ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            case POSTALS: {
478082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
478189c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '"
478289c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                        + StructuredPostal.CONTENT_ITEM_TYPE + "'");
4783ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar                break;
4784ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar            }
4785ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
478648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID: {
478782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
47884da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
478948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                qb.appendWhere(" AND " + Data.MIMETYPE + " = '"
479048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                        + StructuredPostal.CONTENT_ITEM_TYPE + "'");
47914da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=?");
479248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                break;
479348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            }
479448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov
47955ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS: {
4796763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForRawContacts(qb, uri);
47974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
47984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
47994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
48005ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_ID: {
48015ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = ContentUris.parseId(uri);
4802763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForRawContacts(qb, uri);
48034da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId));
48044da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + RawContacts._ID + "=?");
48054f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton                break;
48064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            }
48074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
48085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            case RAW_CONTACTS_DATA: {
48095ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                long rawContactId = Long.parseLong(uri.getPathSegments().get(1));
481082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
48114da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId));
48124da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?");
4813e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
4814e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
4815e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
4816e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            case DATA: {
481782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
4818e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey                break;
4819e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey            }
4820e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey
48214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            case DATA_ID: {
482282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                setTablesAndProjectionMapForData(qb, uri, projection, false);
48234da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
48244da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + Data._ID + "=?");
4825a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov                break;
4826a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov            }
4827a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov
4828a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            case PHONE_LOOKUP: {
48294a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
4830a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                if (TextUtils.isEmpty(sortOrder)) {
4831a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // Default the sort order to something reasonable so we get consistent
4832a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                    // results when callers don't request an ordering
4833892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                    sortOrder = " length(lookup.normalized_number) DESC";
4834a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                }
4835a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
4836e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                String number = uri.getPathSegments().size() > 1 ? uri.getLastPathSegment() : "";
4837892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                String numberE164 =
4838892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                        PhoneNumberUtils.formatNumberToE164(number, getCurrentCountryIso());
4839892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                String normalizedNumber =
4840892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                        PhoneNumberUtils.normalizeNumber(number);
4841892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov                mDbHelper.buildPhoneLookupAndContactQuery(qb, normalizedNumber, numberE164);
4842e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                qb.setProjectionMap(sPhoneLookupProjectionMap);
4843e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                // Phone lookup cannot be combined with a selection
4844e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                selection = null;
4845e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov                selectionArgs = null;
4846a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton                break;
4847a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton            }
4848a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton
4849ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS: {
4850b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getGroupView());
4851ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
485289c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
4853ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
4854ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
4855ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
4856ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_ID: {
4857b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getGroupView());
4858ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsProjectionMap);
48594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
48604da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(Groups._ID + "=?");
4861ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
4862ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
4863ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
4864ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            case GROUPS_SUMMARY: {
4865b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getGroupView() + " AS groups");
4866ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                qb.setProjectionMap(sGroupsSummaryProjectionMap);
486789c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
486889c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                groupBy = Groups._ID;
4869ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                break;
4870ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            }
4871ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
4872b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            case AGGREGATION_EXCEPTIONS: {
48730c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov                qb.setTables(Tables.AGGREGATION_EXCEPTIONS);
4874b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                qb.setProjectionMap(sAggregationExceptionsProjectionMap);
4875b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov                break;
4876b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov            }
4877b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov
487831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            case AGGREGATION_SUGGESTIONS: {
4879d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                long contactId = Long.parseLong(uri.getPathSegments().get(1));
48802d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                String filter = null;
48812d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                if (uri.getPathSegments().size() > 3) {
48822d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                    filter = uri.getPathSegments().get(3);
48832d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov                }
488431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                final int maxSuggestions;
4885d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                if (limit != null) {
4886d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov                    maxSuggestions = Integer.parseInt(limit);
488731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                } else {
488831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                    maxSuggestions = DEFAULT_MAX_SUGGESTIONS;
488931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov                }
489031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
48915b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                ArrayList<AggregationSuggestionParameter> parameters = null;
48925b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                List<String> query = uri.getQueryParameters("query");
48935b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                if (query != null && !query.isEmpty()) {
48945b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                    parameters = new ArrayList<AggregationSuggestionParameter>(query.size());
48955b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                    for (String parameter : query) {
48965b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                        int offset = parameter.indexOf(':');
48975b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                        parameters.add(offset == -1
48985b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                                ? new AggregationSuggestionParameter(
489976dfa406e2cde19c824983c37fc92c1c5bf63eecDaniel Lehmann                                        AggregationSuggestions.PARAMETER_MATCH_NAME,
49005b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                                        parameter)
49015b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                                : new AggregationSuggestionParameter(
49025b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                                        parameter.substring(0, offset),
49035b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                                        parameter.substring(offset + 1)));
49045b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                    }
49055b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                }
49065b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov
4907763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                setTablesAndProjectionMapForContacts(qb, uri, projection);
49087581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov
49097581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov                return mContactAggregator.queryAggregationSuggestions(qb, projection, contactId,
49105b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov                        maxSuggestions, filter, parameters);
491131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov            }
491231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov
4913eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            case SETTINGS: {
4914eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                qb.setTables(Tables.SETTINGS);
4915eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                qb.setProjectionMap(sSettingsProjectionMap);
491689c626eb655440c86a2e5df076e83708c1b32c17Dmitri Plotnikov                appendAccountFromParameter(qb, uri);
4917e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
4918e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                // When requesting specific columns, this query requires
4919e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                // late-binding of the GroupMembership MIME-type.
4920b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                final String groupMembershipMimetypeId = Long.toString(mDbHelper
4921e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                        .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE));
492282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                if (projection != null && projection.length != 0 &&
4923b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                        mDbHelper.isInProjection(projection, Settings.UNGROUPED_COUNT)) {
4924e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                    selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId);
4925e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                }
492682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov                if (projection != null && projection.length != 0 &&
4927b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                        mDbHelper.isInProjection(projection, Settings.UNGROUPED_WITH_PHONES)) {
4928e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                    selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId);
4929e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey                }
4930e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey
4931eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey                break;
4932eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey            }
4933eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey
493482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES: {
49350a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                setTableAndProjectionMapForStatusUpdates(qb, projection);
49365ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
49375ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
49385ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
493982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            case STATUS_UPDATES_ID: {
49400a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                setTableAndProjectionMapForStatusUpdates(qb, projection);
49414da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
49424da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(DataColumns.CONCRETE_ID + "=?");
49435ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                break;
49445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            }
49455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov
4946c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS: {
4947a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov                return mGlobalSearchSupport.handleSearchSuggestionsQuery(db, uri, limit);
4948c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
4949c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
4950c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT: {
49512d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill                String lookupKey = uri.getLastPathSegment();
49522d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill                return mGlobalSearchSupport.handleSearchShortcutRefresh(db, lookupKey, projection);
4953c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
4954c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
49551b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS:
4956b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getContactView());
49571b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
49581b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
49591b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
49601b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_WITH_PHONES:
4961b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getContactView());
49621b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
49631b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(Contacts.HAS_PHONE_NUMBER + "=1");
49641b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
49651b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
49661b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_FAVORITES:
4967b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getContactView());
49681b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
49691b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.appendWhere(Contacts.STARRED + "=1");
49701b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
49711b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
49721b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov            case LIVE_FOLDERS_CONTACTS_GROUP_NAME:
4973b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                qb.setTables(mDbHelper.getContactView());
49741b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                qb.setProjectionMap(sLiveFoldersProjectionMap);
497571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov                qb.appendWhere(CONTACTS_IN_GROUP_SELECT);
49761b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
49771b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov                break;
49781b7a7947242bb3b8caaed871775e62d486144c9fDmitri Plotnikov
497946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana            case RAW_CONTACT_ENTITIES: {
4980a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                setTablesAndProjectionMapForRawEntities(qb, uri);
498146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                break;
498246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana            }
498346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
498446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana            case RAW_CONTACT_ENTITY_ID: {
498546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                long rawContactId = Long.parseLong(uri.getPathSegments().get(1));
4986a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                setTablesAndProjectionMapForRawEntities(qb, uri);
49874da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId));
49884da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                qb.appendWhere(" AND " + RawContacts._ID + "=?");
498946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana                break;
499046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana            }
499146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
499209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov            case PROVIDER_STATUS: {
499309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov                return queryProviderStatus(uri, projection);
499409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov            }
499509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov
4996d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            case DIRECTORIES : {
4997d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                qb.setTables(Tables.DIRECTORIES);
4998d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                qb.setProjectionMap(sDirectoryProjectionMap);
4999d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                break;
5000d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            }
5001d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
5002d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            case DIRECTORIES_ID : {
5003385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov                long id = ContentUris.parseId(uri);
5004d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                qb.setTables(Tables.DIRECTORIES);
5005d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                qb.setProjectionMap(sDirectoryProjectionMap);
5006385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov                selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(id));
5007d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                qb.appendWhere(Directory._ID + "=?");
5008d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                break;
5009d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            }
5010d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
50117a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov            case COMPLETE_NAME: {
50127a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                return completeName(uri, projection);
50137a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov            }
50147a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov
50154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            default:
5016f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov                return mLegacyApiSupport.query(uri, projection, selection, selectionArgs,
5017c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                        sortOrder, limit);
50184f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
50194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
50207f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov        qb.setStrictProjectionMap(true);
50217f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov
5022ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        Cursor cursor =
5023ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit);
5024ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) {
5025ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            cursor = bundleLetterCountExtras(cursor, db, qb, selection, selectionArgs, sortOrder);
5026ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        }
5027ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        return cursor;
50285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
50295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
50305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection,
50315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            String selection, String[] selectionArgs, String sortOrder, String groupBy,
50325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            String limit) {
5033038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        if (projection != null && projection.length == 1
5034038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana                && BaseColumns._COUNT.equals(projection[0])) {
5035038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana            qb.setProjectionMap(sCountProjectionMap);
5036038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana        }
50375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null,
50385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sortOrder, limit);
50394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        if (c != null) {
50404f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton            c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI);
50414f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
50424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        return c;
50434f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
50444f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton
504509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov    /**
504609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov     * Creates a single-row cursor containing the current status of the provider.
504709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov     */
504809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov    private Cursor queryProviderStatus(Uri uri, String[] projection) {
504909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov        MatrixCursor cursor = new MatrixCursor(projection);
505009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov        RowBuilder row = cursor.newRow();
505109c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov        for (int i = 0; i < projection.length; i++) {
505209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov            if (ProviderStatus.STATUS.equals(projection[i])) {
505309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov                row.add(mProviderStatus);
505409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov            } else if (ProviderStatus.DATA1.equals(projection[i])) {
505509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov                row.add(mEstimatedStorageRequirement);
505609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov            }
505709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov        }
505809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov        return cursor;
505909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov    }
506009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov
5061a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    /**
5062a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov     * Runs the query with the supplied contact ID and lookup ID.  If the query succeeds,
5063a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov     * it returns the resulting cursor, otherwise it returns null and the calling
5064a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov     * method needs to resolve the lookup key and rerun the query.
5065a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov     */
5066a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private Cursor queryWithContactIdAndLookupKey(SQLiteQueryBuilder lookupQb,
5067a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            SQLiteDatabase db, Uri uri,
5068a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            String[] projection, String selection, String[] selectionArgs,
5069a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            String sortOrder, String groupBy, String limit,
5070a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            String contactIdColumn, long contactId, String lookupKeyColumn, String lookupKey) {
5071a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        String[] args;
5072a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        if (selectionArgs == null) {
5073a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            args = new String[2];
5074a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        } else {
5075a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            args = new String[selectionArgs.length + 2];
5076a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length);
5077a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        }
5078a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        args[0] = String.valueOf(contactId);
5079a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        args[1] = Uri.encode(lookupKey);
5080a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        lookupQb.appendWhere(contactIdColumn + "=? AND " + lookupKeyColumn + "=?");
5081a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        Cursor c = query(db, lookupQb, projection, selection, args, sortOrder,
5082a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                groupBy, limit);
5083a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        if (c.getCount() != 0) {
5084a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            return c;
5085a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        }
5086a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
5087a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        c.close();
5088a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        return null;
5089a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    }
509009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov
5091bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov    private static final class AddressBookIndexQuery {
5092bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov        public static final String LETTER = "letter";
5093bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov        public static final String TITLE = "title";
5094bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov        public static final String COUNT = "count";
5095ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
5096bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov        public static final String[] COLUMNS = new String[] {
5097bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                LETTER, TITLE, COUNT
5098ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        };
5099ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
5100bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov        public static final int COLUMN_LETTER = 0;
5101bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov        public static final int COLUMN_TITLE = 1;
5102bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov        public static final int COLUMN_COUNT = 2;
5103bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov
5104de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa        public static final String ORDER_BY = LETTER + " COLLATE " + PHONEBOOK_COLLATOR_NAME;
5105ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov    }
5106ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
5107ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov    /**
5108ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov     * Computes counts by the address book index titles and adds the resulting tally
5109ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov     * to the returned cursor as a bundle of extras.
5110ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov     */
5111ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov    private Cursor bundleLetterCountExtras(Cursor cursor, final SQLiteDatabase db,
5112ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            SQLiteQueryBuilder qb, String selection, String[] selectionArgs, String sortOrder) {
5113ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        String sortKey;
5114ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
5115ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        // The sort order suffix could be something like "DESC".
5116ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        // We want to preserve it in the query even though we will change
5117ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        // the sort column itself.
5118ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        String sortOrderSuffix = "";
5119ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        if (sortOrder != null) {
5120ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            int spaceIndex = sortOrder.indexOf(' ');
5121ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            if (spaceIndex != -1) {
5122ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                sortKey = sortOrder.substring(0, spaceIndex);
5123ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                sortOrderSuffix = sortOrder.substring(spaceIndex);
5124ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            } else {
5125ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                sortKey = sortOrder;
5126ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            }
5127ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        } else {
5128ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            sortKey = Contacts.SORT_KEY_PRIMARY;
5129ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        }
5130ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
5131bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov        String locale = getLocale().toString();
5132ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        HashMap<String, String> projectionMap = Maps.newHashMap();
5133bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov        projectionMap.put(AddressBookIndexQuery.LETTER,
5134bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                "SUBSTR(" + sortKey + ",1,1) AS " + AddressBookIndexQuery.LETTER);
5135bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov
5136bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov        /**
5137bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov         * Use the GET_PHONEBOOK_INDEX function, which is an android extension for SQLite3,
5138bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov         * to map the first letter of the sort key to a character that is traditionally
5139bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov         * used in phonebooks to represent that letter.  For example, in Korean it will
5140bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov         * be the first consonant in the letter; for Japanese it will be Hiragana rather
5141bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov         * than Katakana.
5142bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov         */
5143ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        projectionMap.put(AddressBookIndexQuery.TITLE,
5144bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                "GET_PHONEBOOK_INDEX(SUBSTR(" + sortKey + ",1,1),'" + locale + "')"
5145bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                        + " AS " + AddressBookIndexQuery.TITLE);
5146ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        projectionMap.put(AddressBookIndexQuery.COUNT,
5147ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                "COUNT(" + Contacts._ID + ") AS " + AddressBookIndexQuery.COUNT);
5148ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        qb.setProjectionMap(projectionMap);
5149ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
5150f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov        Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs,
5151ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                AddressBookIndexQuery.ORDER_BY, null /* having */,
5152ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                AddressBookIndexQuery.ORDER_BY + sortOrderSuffix);
5153ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
5154ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        try {
5155f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov            int groupCount = indexCursor.getCount();
5156ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            String titles[] = new String[groupCount];
5157ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            int counts[] = new int[groupCount];
5158bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov            int indexCount = 0;
5159bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov            String currentTitle = null;
5160bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov
5161bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov            // Since GET_PHONEBOOK_INDEX is a many-to-1 function, we may end up
5162bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov            // with multiple entries for the same title.  The following code
5163bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov            // collapses those duplicates.
5164ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            for (int i = 0; i < groupCount; i++) {
5165f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov                indexCursor.moveToNext();
5166bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                String title = indexCursor.getString(AddressBookIndexQuery.COLUMN_TITLE);
5167bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                int count = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT);
5168bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                if (indexCount == 0 || !TextUtils.equals(title, currentTitle)) {
5169bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                    titles[indexCount] = currentTitle = title;
5170bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                    counts[indexCount] = count;
5171bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                    indexCount++;
5172bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                } else {
5173bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                    counts[indexCount - 1] += count;
5174bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                }
5175bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov            }
5176bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov
5177bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov            if (indexCount < groupCount) {
5178bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                String[] newTitles = new String[indexCount];
5179bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                System.arraycopy(titles, 0, newTitles, 0, indexCount);
5180bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                titles = newTitles;
5181bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov
5182bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                int[] newCounts = new int[indexCount];
5183bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                System.arraycopy(counts, 0, newCounts, 0, indexCount);
5184bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov                counts = newCounts;
5185ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            }
5186ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
5187ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            final Bundle bundle = new Bundle();
5188ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            bundle.putStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES, titles);
5189f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov            bundle.putIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, counts);
5190ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            return new CursorWrapper(cursor) {
5191ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
5192ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                @Override
5193ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                public Bundle getExtras() {
5194ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                    return bundle;
5195ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov                }
5196ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov            };
5197ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        } finally {
5198f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov            indexCursor.close();
5199ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov        }
5200ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov    }
5201ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov
52022d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill    /**
520392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov     * Returns the contact Id for the contact identified by the lookupKey.
520492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov     * Robust against changes in the lookup key: if the key has changed, will
520592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov     * look up the contact by the raw contact IDs or name encoded in the lookup
520692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov     * key.
52072d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill     */
52082d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill    public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) {
52095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        ContactLookupKey key = new ContactLookupKey();
52105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        ArrayList<LookupKeySegment> segments = key.parse(lookupKey);
52115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
521292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        long contactId = -1;
521392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_SOURCE_ID)) {
521492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            contactId = lookupContactIdBySourceIds(db, segments);
521592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            if (contactId != -1) {
521692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                return contactId;
521792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            }
521892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        }
521992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov
522092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        boolean hasRawContactIds =
522192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID);
522292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        if (hasRawContactIds) {
522392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            contactId = lookupContactIdByRawContactIds(db, segments);
522492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            if (contactId != -1) {
522592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                return contactId;
522692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            }
522792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        }
522892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov
522992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        if (hasRawContactIds
523092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                || lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME)) {
52315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            contactId = lookupContactIdByDisplayNames(db, segments);
52325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
52335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
52345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return contactId;
52355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
52365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
52375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private interface LookupBySourceIdQuery {
52385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String TABLE = Tables.RAW_CONTACTS;
52395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
52405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String COLUMNS[] = {
52415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.CONTACT_ID,
52425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
52435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
52445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.SOURCE_ID
52455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        };
52465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
52475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int CONTACT_ID = 0;
52485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_TYPE = 1;
52495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_NAME = 2;
52505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int SOURCE_ID = 3;
52515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
52525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
52535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long lookupContactIdBySourceIds(SQLiteDatabase db,
52545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                ArrayList<LookupKeySegment> segments) {
52555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
52565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(RawContacts.SOURCE_ID + " IN (");
52575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
52585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
525992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID) {
52605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(sb, segment.key);
52615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sb.append(",");
52625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
52635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
52645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
52655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL");
52665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
52675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS,
52685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                 sb.toString(), null, null, null, null);
52695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        try {
52705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            while (c.moveToNext()) {
52715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountType = c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE);
52725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME);
52735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int accountHashCode =
52745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
52755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID);
52765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
52775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
527892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                    if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID
527992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                            && accountHashCode == segment.accountHashCode
52805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            && segment.key.equals(sourceId)) {
52815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID);
52825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        break;
52835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
52845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
52855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
52865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } finally {
52875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            c.close();
52885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
52895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
52905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return getMostReferencedContactId(segments);
52915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
52925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
529392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov    private interface LookupByRawContactIdQuery {
529492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        String TABLE = Tables.RAW_CONTACTS;
52955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
52965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        String COLUMNS[] = {
52975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.CONTACT_ID,
52985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
52995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                RawContacts.ACCOUNT_NAME,
530092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                RawContacts._ID,
53015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        };
53025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
53035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int CONTACT_ID = 0;
53045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_TYPE = 1;
53055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int ACCOUNT_NAME = 2;
530692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        int ID = 3;
53075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
53085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
530992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov    private long lookupContactIdByRawContactIds(SQLiteDatabase db,
531092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            ArrayList<LookupKeySegment> segments) {
531192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        StringBuilder sb = new StringBuilder();
531292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        sb.append(RawContacts._ID + " IN (");
53135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
53145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
531592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) {
531692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                sb.append(segment.rawContactId);
531792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                sb.append(",");
53185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
53195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
532092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
532192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL");
53225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
532392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        Cursor c = db.query(LookupByRawContactIdQuery.TABLE, LookupByRawContactIdQuery.COLUMNS,
532492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                 sb.toString(), null, null, null, null);
532592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        try {
532692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            while (c.moveToNext()) {
532792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                String accountType = c.getString(LookupByRawContactIdQuery.ACCOUNT_TYPE);
532892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                String accountName = c.getString(LookupByRawContactIdQuery.ACCOUNT_NAME);
532992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                int accountHashCode =
533092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
533192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                String rawContactId = c.getString(LookupByRawContactIdQuery.ID);
533292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
533392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
533492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                    if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID
533592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                            && accountHashCode == segment.accountHashCode
533692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                            && segment.rawContactId.equals(rawContactId)) {
533792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                        segment.contactId = c.getLong(LookupByRawContactIdQuery.CONTACT_ID);
533892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                        break;
533992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                    }
534092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                }
534192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            }
534292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        } finally {
534392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            c.close();
53445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
53455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
534692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        return getMostReferencedContactId(segments);
534792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov    }
534892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov
534992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov    private interface LookupByDisplayNameQuery {
535092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS;
535192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov
535292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        String COLUMNS[] = {
535392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                RawContacts.CONTACT_ID,
535492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
535592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                RawContacts.ACCOUNT_NAME,
535692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                NameLookupColumns.NORMALIZED_NAME
535792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        };
535892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov
535992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        int CONTACT_ID = 0;
536092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        int ACCOUNT_TYPE = 1;
536192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        int ACCOUNT_NAME = 2;
536292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        int NORMALIZED_NAME = 3;
536392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov    }
536492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov
536592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov    private long lookupContactIdByDisplayNames(SQLiteDatabase db,
536692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                ArrayList<LookupKeySegment> segments) {
53675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
53685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(NameLookupColumns.NORMALIZED_NAME + " IN (");
53695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
53705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
537192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME
537292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                    || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) {
53735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                DatabaseUtils.appendEscapedSQLString(sb, segment.key);
53745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                sb.append(",");
53755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
53765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
53775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.setLength(sb.length() - 1);      // Last comma
53785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY
53795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                + " AND " + RawContacts.CONTACT_ID + " NOT NULL");
53805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
53815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS,
53825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                 sb.toString(), null, null, null, null);
53835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        try {
53845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            while (c.moveToNext()) {
53855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountType = c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE);
53865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME);
53875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                int accountHashCode =
53885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        ContactLookupKey.getAccountHashCode(accountType, accountName);
53895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME);
53905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                for (int i = 0; i < segments.size(); i++) {
53915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    LookupKeySegment segment = segments.get(i);
539292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                    if ((segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME
539392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                            || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID)
539492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                            && accountHashCode == segment.accountHashCode
53955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                            && segment.key.equals(name)) {
53965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID);
53975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        break;
53985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
53995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
54005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
54015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } finally {
54025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            c.close();
54035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
54045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
54055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        return getMostReferencedContactId(segments);
54065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
54075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
540892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov    private boolean lookupKeyContainsType(ArrayList<LookupKeySegment> segments, int lookupType) {
540992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        for (int i = 0; i < segments.size(); i++) {
541092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            LookupKeySegment segment = segments.get(i);
541192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            if (segment.lookupType == lookupType) {
541292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov                return true;
541392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov            }
541492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        }
541592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov
541692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov        return false;
541792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov    }
541892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov
5419ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov    public void updateLookupKeyForRawContact(SQLiteDatabase db, long rawContactId) {
5420ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov        mContactAggregator.updateLookupKeyForRawContact(db, rawContactId);
5421ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov    }
5422ae7733451f6ddf3246efcd7fd4fc6882eefa6657Dmitri Plotnikov
54235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    /**
54245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov     * Returns the contact ID that is mentioned the highest number of times.
54255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov     */
54265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) {
54275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        Collections.sort(segments);
54285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
54295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long bestContactId = -1;
54305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int bestRefCount = 0;
54315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
54325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        long contactId = -1;
54335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int count = 0;
54345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
54355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        int segmentCount = segments.size();
54365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        for (int i = 0; i < segmentCount; i++) {
54375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            LookupKeySegment segment = segments.get(i);
54385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            if (segment.contactId != -1) {
54395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                if (segment.contactId == contactId) {
54405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    count++;
54415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                } else {
54425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    if (count > bestRefCount) {
54435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        bestContactId = contactId;
54445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                        bestRefCount = count;
54455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    }
54465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    contactId = segment.contactId;
54475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                    count = 1;
54485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov                }
54495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            }
54505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
54515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        if (count > bestRefCount) {
54525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return contactId;
54535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        } else {
54545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov            return bestContactId;
54555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov        }
54565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov    }
54575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov
5458763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar    private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri,
5459763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar            String[] projection) {
546082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
5461916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        appendContactsTables(sb, uri, projection);
5462916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        qb.setTables(sb.toString());
5463916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        qb.setProjectionMap(sContactsProjectionMap);
5464916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov    }
5465916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
5466916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov    /**
5467916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov     * Finds name lookup records matching the supplied filter, picks one arbitrary match per
5468916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov     * contact and joins that with other contacts tables.
5469916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov     */
5470916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov    private void setTablesAndProjectionMapForContactsWithSnippet(SQLiteQueryBuilder qb, Uri uri,
5471916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov            String[] projection, String filter) {
5472916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
5473916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        StringBuilder sb = new StringBuilder();
5474916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        appendContactsTables(sb, uri, projection);
5475916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
5476916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        sb.append(" JOIN (SELECT " +
5477916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov                RawContacts.CONTACT_ID + " AS snippet_contact_id");
5478916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
5479916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET_DATA_ID)) {
5480916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov            sb.append(", " + DataColumns.CONCRETE_ID + " AS "
5481916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov                    + SearchSnippetColumns.SNIPPET_DATA_ID);
5482916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        }
5483916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
54849c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov        if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET_DATA1)) {
54859c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov            sb.append(", " + Data.DATA1 + " AS " + SearchSnippetColumns.SNIPPET_DATA1);
5486916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        }
5487916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
54889c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov        if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET_DATA2)) {
54899c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov            sb.append(", " + Data.DATA2 + " AS " + SearchSnippetColumns.SNIPPET_DATA2);
5490916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        }
5491916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
54929c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov        if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET_DATA3)) {
54939c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov            sb.append(", " + Data.DATA3 + " AS " + SearchSnippetColumns.SNIPPET_DATA3);
54949c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov        }
54959c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov
54969c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov        if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET_DATA4)) {
54979c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov            sb.append(", " + Data.DATA4 + " AS " + SearchSnippetColumns.SNIPPET_DATA4);
5498916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        }
5499916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
5500916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        if (mDbHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET_MIMETYPE)) {
5501916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov            sb.append(", (" +
5502916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov                    "SELECT " + MimetypesColumns.MIMETYPE +
5503916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov                    " FROM " + Tables.MIMETYPES +
5504916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov                    " WHERE " + MimetypesColumns._ID + "=" + DataColumns.MIMETYPE_ID +
5505916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov                    ") AS " + SearchSnippetColumns.SNIPPET_MIMETYPE);
5506916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        }
5507916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
5508c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov        sb.append(" FROM " + Tables.DATA_JOIN_RAW_CONTACTS + " WHERE ");
5509c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov
5510c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov        if (!TextUtils.isEmpty(filter)) {
55116b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov            String normalizedFilter = NameNormalizer.normalize(filter);
55126b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov            if (!TextUtils.isEmpty(normalizedFilter)) {
55136b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                sb.append(DataColumns.CONCRETE_ID + " IN (");
55146b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov
55156b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                // Construct a query that gives us exactly one data _id per matching contact.
55166b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                // MIN stands in for ANY in this context.
55176b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                sb.append(
55186b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                        "SELECT MIN(" + Tables.NAME_LOOKUP + "." + NameLookupColumns.DATA_ID + ")" +
55196b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                        " FROM " + Tables.NAME_LOOKUP +
55206b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                        " JOIN " + Tables.RAW_CONTACTS +
55216b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                        " ON (" + RawContactsColumns.CONCRETE_ID
55226b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                                + "=" + Tables.NAME_LOOKUP + "."
55236b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                                        + NameLookupColumns.RAW_CONTACT_ID + ")" +
55246b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                        " WHERE " + NameLookupColumns.NORMALIZED_NAME + " GLOB '");
55256b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                sb.append(normalizedFilter);
55266b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                sb.append("*' AND " + NameLookupColumns.NAME_TYPE +
55276b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                            " IN(" + CONTACT_LOOKUP_NAME_TYPES + ")" +
55286b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                        " GROUP BY " + RawContactsColumns.CONCRETE_CONTACT_ID +
55296b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                        ")");
55306b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov            } else {
55316b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov                sb.append("0");     // Empty filter - return an empty set
55326b759a2b977a29c3c4abe1eb6d2ba242f937a923Dmitri Plotnikov            }
5533c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov        } else {
5534c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov            sb.append("0");     // Empty filter - return an empty set
5535c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov        }
5536c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov
5537c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov        sb.append(") ON (" + Contacts._ID + "=snippet_contact_id)");
5538916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
5539916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        qb.setTables(sb.toString());
5540916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        qb.setProjectionMap(sContactsProjectionWithSnippetMap);
5541916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov    }
5542916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov
5543916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov    private void appendContactsTables(StringBuilder sb, Uri uri, String[] projection) {
5544763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        boolean excludeRestrictedData = false;
5545f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String requestingPackage = getQueryParameter(uri,
5546763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                ContactsContract.REQUESTING_PACKAGE_PARAM_KEY);
5547763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        if (requestingPackage != null) {
5548d91272b48f97243533c6580981e12a4847b5783fJeff Hamilton            excludeRestrictedData = !mDbHelper.hasAccessToRestrictedData(requestingPackage);
5549763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        }
5550763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        sb.append(mDbHelper.getContactView(excludeRestrictedData));
5551a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendContactPresenceJoin(sb, projection, Contacts._ID);
5552a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID);
555382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    }
5554ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
5555763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar    private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) {
5556763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        StringBuilder sb = new StringBuilder();
5557763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        boolean excludeRestrictedData = false;
5558f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String requestingPackage = getQueryParameter(uri,
5559763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar                ContactsContract.REQUESTING_PACKAGE_PARAM_KEY);
5560763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        if (requestingPackage != null) {
5561d91272b48f97243533c6580981e12a4847b5783fJeff Hamilton            excludeRestrictedData = !mDbHelper.hasAccessToRestrictedData(requestingPackage);
5562763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        }
5563763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        sb.append(mDbHelper.getRawContactView(excludeRestrictedData));
5564763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        qb.setTables(sb.toString());
5565763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        qb.setProjectionMap(sRawContactsProjectionMap);
5566763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar        appendAccountFromParameter(qb, uri);
5567763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar    }
5568763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar
5569a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private void setTablesAndProjectionMapForRawEntities(SQLiteQueryBuilder qb, Uri uri) {
5570a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        qb.setTables(mDbHelper.getRawEntitiesView(shouldExcludeRestrictedData(uri)));
5571a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        qb.setProjectionMap(sRawEntityProjectionMap);
557246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana        appendAccountFromParameter(qb, uri);
557346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana    }
557446b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana
557582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov    private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri,
557682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov            String[] projection, boolean distinct) {
557782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        StringBuilder sb = new StringBuilder();
5578a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        sb.append(mDbHelper.getDataView(shouldExcludeRestrictedData(uri)));
557982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        sb.append(" data");
558082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov
5581a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID);
5582a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID);
5583a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID);
5584a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID);
55853296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey
558682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        qb.setTables(sb.toString());
5587f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov
5588f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov        boolean useDistinct = distinct
5589f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov                || !mDbHelper.isInProjection(projection, DISTINCT_DATA_PROHIBITING_COLUMNS);
5590f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov        qb.setDistinct(useDistinct);
5591f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov        qb.setProjectionMap(useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap);
559282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov        appendAccountFromParameter(qb, uri);
5593ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov    }
5594ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov
55950a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov    private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb,
55960a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            String[] projection) {
55970a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        StringBuilder sb = new StringBuilder();
5598b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        sb.append(mDbHelper.getDataView());
55990a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        sb.append(" data");
5600a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID);
5601a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID);
56020a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
5603a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        qb.setTables(sb.toString());
5604a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        qb.setProjectionMap(sStatusUpdatesProjectionMap);
5605a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    }
5606a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
5607a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private void setTablesAndProjectionMapForEntities(SQLiteQueryBuilder qb, Uri uri,
5608a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            String[] projection) {
5609a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        StringBuilder sb = new StringBuilder();
5610a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        sb.append(mDbHelper.getEntitiesView(shouldExcludeRestrictedData(uri)));
5611a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        sb.append(" data");
5612a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
5613a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendContactPresenceJoin(sb, projection, Contacts.Entity.CONTACT_ID);
5614a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID);
5615a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendDataPresenceJoin(sb, projection, Contacts.Entity.DATA_ID);
5616a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendDataStatusUpdateJoin(sb, projection, Contacts.Entity.DATA_ID);
5617a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
5618a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        qb.setTables(sb.toString());
5619a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        qb.setProjectionMap(sEntityProjectionMap);
5620a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        appendAccountFromParameter(qb, uri);
5621a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    }
5622a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
5623a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private void appendContactStatusUpdateJoin(StringBuilder sb, String[] projection,
5624a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            String lastStatusUpdateIdColumn) {
5625a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        if (mDbHelper.isInProjection(projection,
5626a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                Contacts.CONTACT_STATUS,
5627a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                Contacts.CONTACT_STATUS_RES_PACKAGE,
5628a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                Contacts.CONTACT_STATUS_ICON,
5629a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                Contacts.CONTACT_STATUS_LABEL,
5630a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                Contacts.CONTACT_STATUS_TIMESTAMP)) {
5631a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " "
5632a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    + ContactsStatusUpdatesColumns.ALIAS +
5633a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    " ON (" + lastStatusUpdateIdColumn + "="
5634a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")");
56350a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        }
5636a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    }
56370a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
5638a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private void appendDataStatusUpdateJoin(StringBuilder sb, String[] projection,
5639a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            String dataIdColumn) {
5640b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov        if (mDbHelper.isInProjection(projection,
56410a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                StatusUpdates.STATUS,
56420a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                StatusUpdates.STATUS_RES_PACKAGE,
56430a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                StatusUpdates.STATUS_ICON,
56440a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                StatusUpdates.STATUS_LABEL,
56450a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov                StatusUpdates.STATUS_TIMESTAMP)) {
56460a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES +
5647a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "="
5648a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            + dataIdColumn + ")");
56490a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov        }
5650a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    }
5651a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
5652a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private void appendContactPresenceJoin(StringBuilder sb, String[] projection,
5653a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            String contactIdColumn) {
5654a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        if (mDbHelper.isInProjection(projection,
5655a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                Contacts.CONTACT_PRESENCE, Contacts.CONTACT_CHAT_CAPABILITY)) {
5656a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE +
5657a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    " ON (" + contactIdColumn + " = "
5658a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                            + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + ")");
5659a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        }
5660a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    }
5661a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
5662a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private void appendDataPresenceJoin(StringBuilder sb, String[] projection,
5663a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            String dataIdColumn) {
5664a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        if (mDbHelper.isInProjection(projection, Data.PRESENCE, Data.CHAT_CAPABILITY)) {
5665a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE +
5666a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                    " ON (" + StatusUpdates.DATA_ID + "=" + dataIdColumn + ")");
5667a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        }
5668a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    }
5669a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
5670385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov    private void appendLocalDirectorySelectionIfNeeded(SQLiteQueryBuilder qb, long directoryId) {
5671385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov        if (directoryId == Directory.DEFAULT) {
5672385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov            qb.appendWhere(Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY);
5673385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov        } else if (directoryId == Directory.LOCAL_INVISIBLE){
5674385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov            qb.appendWhere(Contacts._ID + " NOT IN " + Tables.DEFAULT_DIRECTORY);
5675385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov        }
5676385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov    }
5677385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov
5678a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov    private boolean shouldExcludeRestrictedData(Uri uri) {
5679a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        // Note: currently, "export only" equals to "restricted", but may not in the future.
5680a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        boolean excludeRestrictedData = readBooleanQueryParameter(uri,
5681a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                Data.FOR_EXPORT_ONLY, false);
5682a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        if (excludeRestrictedData) {
5683a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            return true;
5684a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        }
5685a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
5686a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        String requestingPackage = getQueryParameter(uri,
5687a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov                ContactsContract.REQUESTING_PACKAGE_PARAM_KEY);
5688a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        if (requestingPackage != null) {
5689a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            return !mDbHelper.hasAccessToRestrictedData(requestingPackage);
5690a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        }
5691a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov
5692a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov        return false;
56930a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov    }
56940a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov
56954a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) {
5696f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME);
5697f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE);
5698e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
5699e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType);
5700e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (partialUri) {
5701e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            // Throw when either account is incomplete
5702fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov            throw new IllegalArgumentException(mDbHelper.exceptionMessage(
5703fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                    "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri));
5704e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        }
5705e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
5706e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // Accounts are valid by only checking one parameter, since we've
5707e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // already ruled out partial accounts.
5708e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean validAccount = !TextUtils.isEmpty(accountName);
5709e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (validAccount) {
57104a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
57114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
57124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + RawContacts.ACCOUNT_TYPE + "="
57134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov                    + DatabaseUtils.sqlEscapeString(accountType));
57144a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        } else {
57154a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            qb.appendWhere("1");
57164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov        }
57174a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    }
57184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov
5719e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong    private String appendAccountToSelection(Uri uri, String selection) {
5720f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME);
5721f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE);
5722e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
5723e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType);
5724e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (partialUri) {
5725e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey            // Throw when either account is incomplete
5726fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov            throw new IllegalArgumentException(mDbHelper.exceptionMessage(
5727fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                    "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri));
5728e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        }
5729e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey
5730e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // Accounts are valid by only checking one parameter, since we've
5731e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        // already ruled out partial accounts.
5732e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        final boolean validAccount = !TextUtils.isEmpty(accountName);
5733e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey        if (validAccount) {
5734e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "="
5735e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + DatabaseUtils.sqlEscapeString(accountName) + " AND "
5736e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + RawContacts.ACCOUNT_TYPE + "="
5737e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                    + DatabaseUtils.sqlEscapeString(accountType));
5738e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            if (!TextUtils.isEmpty(selection)) {
5739e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(" AND (");
5740e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(selection);
5741e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong                selectionSb.append(')');
5742e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            }
5743e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            return selectionSb.toString();
5744e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        } else {
5745e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong            return selection;
5746e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong        }
5747e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong    }
5748e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong
57497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana    /**
5750c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * Gets the value of the "limit" URI query parameter.
5751c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *
5752c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     * @return A string containing a non-negative integer, or <code>null</code> if
5753c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     *         the parameter is not set, or is set to an invalid value.
5754c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov     */
5755f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    private String getLimit(Uri uri) {
57562e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov        String limitParam = getQueryParameter(uri, ContactsContract.LIMIT_PARAM_KEY);
5757c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        if (limitParam == null) {
5758c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
5759c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
5760c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        // make sure that the limit is a non-negative integer
5761c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        try {
5762c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            int l = Integer.parseInt(limitParam);
5763c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            if (l < 0) {
5764c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                Log.w(TAG, "Invalid limit parameter: " + limitParam);
5765c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return null;
5766c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            }
5767c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return String.valueOf(l);
5768c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        } catch (NumberFormatException ex) {
5769c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            Log.w(TAG, "Invalid limit parameter: " + limitParam);
5770c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            return null;
5771c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        }
5772c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
5773c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
577400ec508630251d6c6e3746469c9428f5a8cd5996Jeff Sharkey    String getContactsRestrictions() {
5775d91272b48f97243533c6580981e12a4847b5783fJeff Hamilton        if (mDbHelper.hasAccessToRestrictedData()) {
577670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
577770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        } else {
5778fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov            return RawContactsColumns.CONCRETE_IS_RESTRICTED + "=0";
577970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov        }
578070b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    }
578170b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov
578270b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov    public String getContactsRestrictionExceptionAsNestedQuery(String contactIdColumn) {
5783d91272b48f97243533c6580981e12a4847b5783fJeff Hamilton        if (mDbHelper.hasAccessToRestrictedData()) {
578470b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov            return "1";
578567dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        } else {
57865ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov            return "(SELECT " + RawContacts.IS_RESTRICTED + " FROM " + Tables.RAW_CONTACTS
57875ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                    + " WHERE " + RawContactsColumns.CONCRETE_ID + "=" + contactIdColumn + ")=0";
5788619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
5789619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
5790619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
5791b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    @Override
5792f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
5793b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        int match = sUriMatcher.match(uri);
5794b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        switch (match) {
5795a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov            case CONTACTS_ID_PHOTO: {
5796f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert                return openPhotoAssetFile(uri, mode,
5797e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov                        Data._ID + "=" + Contacts.PHOTO_ID + " AND " + RawContacts.CONTACT_ID + "=?",
5798e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov                        new String[]{uri.getPathSegments().get(1)});
5799e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov            }
5800b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
5801e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov            case DATA_ID: {
5802f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert                return openPhotoAssetFile(uri, mode,
5803e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov                        Data._ID + "=? AND " + Data.MIMETYPE + "='" + Photo.CONTENT_ITEM_TYPE + "'",
58044da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov                        new String[]{uri.getPathSegments().get(1)});
5805d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            }
5806d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
5807f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey            case CONTACTS_AS_VCARD: {
580849d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov                SQLiteDatabase db = mDbHelper.getReadableDatabase();
580942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                final String lookupKey = Uri.encode(uri.getPathSegments().get(2));
581049d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov                mSelectionArgs1[0] = String.valueOf(lookupContactIdByLookupKey(db, lookupKey));
581142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                final String selection = Contacts._ID + "=?";
581242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann
581342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                // When opening a contact as file, we pass back contents as a
581442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                // vCard-encoded stream. We build into a local buffer first,
581542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                // then pipe into MemoryFile once the exact size is known.
581642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                final ByteArrayOutputStream localStream = new ByteArrayOutputStream();
581742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                outputRawContactsAsVCard(localStream, selection, mSelectionArgs1);
5818f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert                return buildAssetFileDescriptor(localStream);
581942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann            }
582042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann
582142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann            case CONTACTS_AS_MULTI_VCARD: {
582249d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov                SQLiteDatabase db = mDbHelper.getReadableDatabase();
582342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                final String lookupKeys = uri.getPathSegments().get(2);
582442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                final String[] loopupKeyList = lookupKeys.split(":");
582542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                final StringBuilder inBuilder = new StringBuilder();
582642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                int index = 0;
5827d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann                // SQLite has limits on how many parameters can be used
5828d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann                // so the IDs are concatenated to a query string here instead
582942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                for (String lookupKey : loopupKeyList) {
583042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                    if (index == 0) {
5831d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann                        inBuilder.append("(");
583242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                    } else {
5833d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann                        inBuilder.append(",");
583442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                    }
583549d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov                    inBuilder.append(lookupContactIdByLookupKey(db, lookupKey));
583642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                    index++;
583742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                }
583842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                inBuilder.append(')');
583942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann                final String selection = Contacts._ID + " IN " + inBuilder.toString();
5840d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
5841d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                // When opening a contact as file, we pass back contents as a
5842d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                // vCard-encoded stream. We build into a local buffer first,
5843d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                // then pipe into MemoryFile once the exact size is known.
5844d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                final ByteArrayOutputStream localStream = new ByteArrayOutputStream();
5845d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann                outputRawContactsAsVCard(localStream, selection, null);
5846f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert                return buildAssetFileDescriptor(localStream);
5847d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            }
5848b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
5849b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov            default:
5850fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                throw new FileNotFoundException(mDbHelper.exceptionMessage("File does not exist",
5851fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov                        uri));
5852b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov        }
5853b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov    }
5854b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
5855f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert    private AssetFileDescriptor openPhotoAssetFile(Uri uri, String mode, String selection,
5856e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov            String[] selectionArgs)
5857e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov            throws FileNotFoundException {
5858e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov        if (!"r".equals(mode)) {
5859e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov            throw new FileNotFoundException(mDbHelper.exceptionMessage("Mode " + mode
5860e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov                    + " not supported.", uri));
5861e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov        }
5862e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov
5863e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov        String sql =
5864e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov                "SELECT " + Photo.PHOTO + " FROM " + mDbHelper.getDataView() +
5865e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov                " WHERE " + selection;
5866e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov        SQLiteDatabase db = mDbHelper.getReadableDatabase();
586708ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood        try {
5868f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert            return makeAssetFileDescriptor(
5869f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert                    DatabaseUtils.blobFileDescriptorForQuery(db, sql, selectionArgs));
587008ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood        } catch (SQLiteDoneException e) {
587108ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood            // this will happen if the DB query returns no rows (i.e. contact does not exist)
587208ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood            throw new FileNotFoundException(uri.toString());
587308ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood        }
5874e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov    }
5875e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov
5876d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile";
5877d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
5878d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    /**
5879f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert     * Returns an {@link AssetFileDescriptor} backed by the
5880d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * contents of the given {@link ByteArrayOutputStream}.
5881d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     */
5882f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert    private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) {
5883d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        try {
5884d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            stream.flush();
5885d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
5886d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            final byte[] byteData = stream.toByteArray();
5887d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
5888f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert            return makeAssetFileDescriptor(
5889f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert                    ParcelFileDescriptor.fromData(byteData, CONTACT_MEMORY_FILE_NAME),
5890f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert                    byteData.length);
5891d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        } catch (IOException e) {
5892ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert            Log.w(TAG, "Problem writing stream into an ParcelFileDescriptor: " + e.toString());
5893ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert            return null;
5894d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        }
5895d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    }
5896d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
5897f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert    private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd) {
5898f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert        return makeAssetFileDescriptor(fd, AssetFileDescriptor.UNKNOWN_LENGTH);
5899f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert    }
5900f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert
5901f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert    private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd, long length) {
5902f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert        return fd != null ? new AssetFileDescriptor(fd, 0, length) : null;
5903f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert    }
5904f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert
5905d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    /**
5906d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * Output {@link RawContacts} matching the requested selection in the vCard
5907d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * format to the given {@link OutputStream}. This method returns silently if
5908d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     * any errors encountered.
5909d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey     */
5910d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    private void outputRawContactsAsVCard(OutputStream stream, String selection,
5911d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            String[] selectionArgs) {
5912d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        final Context context = this.getContext();
59137a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa        final VCardComposer composer =
59147a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa                new VCardComposer(context, VCardConfig.VCARD_TYPE_DEFAULT, false);
5915d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        composer.addHandler(composer.new HandlerForOutputStream(stream));
5916d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
5917f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey        // No extra checks since composer always uses restricted views
59187a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa        if (!composer.init(selection, selectionArgs)) {
59197a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa            Log.w(TAG, "Failed to init VCardComposer");
5920d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            return;
59217a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa        }
5922d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey
5923d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        while (!composer.isAfterLast()) {
5924d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            if (!composer.createOneEntry()) {
5925d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey                Log.w(TAG, "Failed to output a contact.");
5926d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey            }
5927d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        }
5928d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey        composer.terminate();
5929d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey    }
5930b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov
59314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    @Override
59324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    public String getType(Uri uri) {
5933a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton        final int match = sUriMatcher.match(uri);
59344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        switch (match) {
5935b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS:
5936be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov                return Contacts.CONTENT_TYPE;
59372d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill            case CONTACTS_LOOKUP:
5938b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS_ID:
5939b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case CONTACTS_LOOKUP_ID:
5940b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Contacts.CONTENT_ITEM_TYPE;
5941f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey            case CONTACTS_AS_VCARD:
594242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann            case CONTACTS_AS_MULTI_VCARD:
5943f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey                return Contacts.CONTENT_VCARD_TYPE;
5944f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov            case CONTACTS_ID_PHOTO:
5945f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov                return "image/png";
5946b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case RAW_CONTACTS:
5947be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov                return RawContacts.CONTENT_TYPE;
5948b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case RAW_CONTACTS_ID:
5949b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return RawContacts.CONTENT_ITEM_TYPE;
5950f481f22a9323fe338672f99b88b26c5f0725cd42David Brown            case DATA:
5951f481f22a9323fe338672f99b88b26c5f0725cd42David Brown                return Data.CONTENT_TYPE;
5952508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey            case DATA_ID:
5953b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov                return mDbHelper.getDataMimeType(ContentUris.parseId(uri));
595448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES:
595548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Phone.CONTENT_TYPE;
595648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case PHONES_ID:
595748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Phone.CONTENT_ITEM_TYPE;
59589005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov            case PHONE_LOOKUP:
59599005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov                return PhoneLookup.CONTENT_TYPE;
596048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS:
596148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Email.CONTENT_TYPE;
596248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case EMAILS_ID:
596348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return Email.CONTENT_ITEM_TYPE;
596448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS:
596548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return StructuredPostal.CONTENT_TYPE;
596648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov            case POSTALS_ID:
596748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov                return StructuredPostal.CONTENT_ITEM_TYPE;
5968b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_EXCEPTIONS:
5969b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return AggregationExceptions.CONTENT_TYPE;
5970b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_EXCEPTION_ID:
5971b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return AggregationExceptions.CONTENT_ITEM_TYPE;
5972b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case SETTINGS:
5973b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Settings.CONTENT_TYPE;
5974b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov            case AGGREGATION_SUGGESTIONS:
5975b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov                return Contacts.CONTENT_TYPE;
5976c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SUGGESTIONS:
5977c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SUGGEST_MIME_TYPE;
5978c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov            case SEARCH_SHORTCUT:
5979c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov                return SearchManager.SHORTCUT_MIME_TYPE;
5980d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            case DIRECTORIES:
5981d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                return Directory.CONTENT_TYPE;
5982d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            case DIRECTORIES_ID:
5983d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov                return Directory.CONTENT_ITEM_TYPE;
598461efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov            default:
598561efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov                return mLegacyApiSupport.getType(uri);
59864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton        }
59874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton    }
59887e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana
598909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov    public String[] getDefaultProjection(Uri uri) {
599009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov        final int match = sUriMatcher.match(uri);
599109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov        switch (match) {
599209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case CONTACTS:
599309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case CONTACTS_LOOKUP:
599409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case CONTACTS_ID:
599509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case CONTACTS_LOOKUP_ID:
599609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case AGGREGATION_SUGGESTIONS:
599709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov                return sContactsProjectionMap.getColumnNames();
599809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
59998727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov            case CONTACTS_ID_ENTITIES:
60008727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov                return sEntityProjectionMap.getColumnNames();
60018727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov
600209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case CONTACTS_AS_VCARD:
600309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case CONTACTS_AS_MULTI_VCARD:
600409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov                return sContactsVCardProjectionMap.getColumnNames();
600509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
600609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case RAW_CONTACTS:
600709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case RAW_CONTACTS_ID:
600809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov                return sRawContactsProjectionMap.getColumnNames();
600909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
601009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case DATA_ID:
601109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case PHONES:
601209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case PHONES_ID:
601309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case EMAILS:
601409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case EMAILS_ID:
601509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case POSTALS:
601609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case POSTALS_ID:
601709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov                return sDataProjectionMap.getColumnNames();
601809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
601909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case PHONE_LOOKUP:
602009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov                return sPhoneLookupProjectionMap.getColumnNames();
602109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
602209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case AGGREGATION_EXCEPTIONS:
602309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case AGGREGATION_EXCEPTION_ID:
602409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov                return sAggregationExceptionsProjectionMap.getColumnNames();
602509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
602609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case SETTINGS:
602709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov                return sSettingsProjectionMap.getColumnNames();
602809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
602909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case DIRECTORIES:
603009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            case DIRECTORIES_ID:
603109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov                return sDirectoryProjectionMap.getColumnNames();
603209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
603309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov            default:
603409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov                return null;
603509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov        }
603609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov    }
603709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov
6038813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov    public String insertNameLookupForEmail(long rawContactId, long dataId, String email) {
6039f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (TextUtils.isEmpty(email)) {
6040813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return null;
6041f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
6042f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
6043b06484032125877d1a89785a1a912ca58c12d448Dmitri Plotnikov        String address = mDbHelper.extractHandleFromEmailAddress(email);
6044b06484032125877d1a89785a1a912ca58c12d448Dmitri Plotnikov        if (address == null) {
6045813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov            return null;
6046f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
6047f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
604878fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov        mDbHelper.insertNameLookup(rawContactId, dataId,
6049f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                NameLookupType.EMAIL_BASED_NICKNAME, NameNormalizer.normalize(address));
6050813fd5712e0ad264ff6907c85d68a01fb1255d28Dmitri Plotnikov        return address;
6051f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
6052f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
6053f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    /**
6054f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     * Normalizes the nickname and inserts it in the name lookup table.
6055f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov     */
6056f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    public void insertNameLookupForNickname(long rawContactId, long dataId, String nickname) {
6057f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        if (TextUtils.isEmpty(nickname)) {
6058f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            return;
6059f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
6060f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
606178fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov        mDbHelper.insertNameLookup(rawContactId, dataId,
6062f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                NameLookupType.NICKNAME, NameNormalizer.normalize(nickname));
6063f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
6064f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
6065a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka    public void insertNameLookupForOrganization(long rawContactId, long dataId, String company,
6066a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka            String title) {
6067a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        if (!TextUtils.isEmpty(company)) {
606878fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov            mDbHelper.insertNameLookup(rawContactId, dataId,
6069a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    NameLookupType.ORGANIZATION, NameNormalizer.normalize(company));
6070a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        }
6071a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        if (!TextUtils.isEmpty(title)) {
607278fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov            mDbHelper.insertNameLookup(rawContactId, dataId,
6073a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka                    NameLookupType.ORGANIZATION, NameNormalizer.normalize(title));
6074a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka        }
6075a5d05d90333a70d471d78e82caeb5cfa2e4d4c59Tadashi G. Takaoka    }
6076f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
6077d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov    public void insertNameLookupForStructuredName(long rawContactId, long dataId, String name,
6078d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov            int fullNameStyle) {
6079d806946b6561dca3f34ded156c6ee89a5113996eDmitri Plotnikov        mNameLookupBuilder.insertNameLookup(rawContactId, dataId, name, fullNameStyle);
6080f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
6081f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
6082f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    private class StructuredNameLookupBuilder extends NameLookupBuilder {
6083f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
6084f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        public StructuredNameLookupBuilder(NameSplitter splitter) {
6085f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov            super(splitter);
6086f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
6087f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
6088f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        @Override
6089f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        protected void insertNameLookup(long rawContactId, long dataId, int lookupType,
6090f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov                String name) {
609178fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov            mDbHelper.insertNameLookup(rawContactId, dataId, lookupType, name);
6092f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
6093f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
6094f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        @Override
6095f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        protected String[] getCommonNicknameClusters(String normalizedName) {
6096d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov            return mCommonNicknameCache.getCommonNicknameClusters(normalizedName);
6097f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov        }
6098f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov    }
6099f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov
610048786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov    public void insertNameLookupForPhoneticName(long rawContactId, long dataId,
610148786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov            ContentValues values) {
610248786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        if (values.containsKey(StructuredName.PHONETIC_FAMILY_NAME)
610348786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov                || values.containsKey(StructuredName.PHONETIC_GIVEN_NAME)
610448786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov                || values.containsKey(StructuredName.PHONETIC_MIDDLE_NAME)) {
610548786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov            insertNameLookupForPhoneticName(rawContactId, dataId,
610648786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov                    values.getAsString(StructuredName.PHONETIC_FAMILY_NAME),
610748786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov                    values.getAsString(StructuredName.PHONETIC_MIDDLE_NAME),
610848786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov                    values.getAsString(StructuredName.PHONETIC_GIVEN_NAME));
610948786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        }
611048786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov    }
611148786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov
611248786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov    public void insertNameLookupForPhoneticName(long rawContactId, long dataId, String familyName,
611348786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov            String middleName, String givenName) {
611448786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        mSb.setLength(0);
611548786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        if (familyName != null) {
611648786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov            mSb.append(familyName.trim());
611748786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        }
611848786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        if (middleName != null) {
611948786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov            mSb.append(middleName.trim());
612048786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        }
612148786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        if (givenName != null) {
612248786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov            mSb.append(givenName.trim());
612348786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        }
612448786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov
612548786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        if (mSb.length() > 0) {
612678fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov            mDbHelper.insertNameLookup(rawContactId, dataId, NameLookupType.NAME_COLLATION_KEY,
612748786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov                    NameNormalizer.normalize(mSb.toString()));
612848786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov        }
61293b10d3a1ed1052dcdf529da370cb71b74164b158Dmitri Plotnikov
61303b10d3a1ed1052dcdf529da370cb71b74164b158Dmitri Plotnikov        if (givenName != null) {
61313b10d3a1ed1052dcdf529da370cb71b74164b158Dmitri Plotnikov            // We want the phonetic given name to be used for search, but not for aggregation,
61323b10d3a1ed1052dcdf529da370cb71b74164b158Dmitri Plotnikov            // which is why we are using NAME_SHORTHAND rather than NAME_COLLATION_KEY
613378fb53bfd973760996fe3a5fe260b1d367574de6Dmitri Plotnikov            mDbHelper.insertNameLookup(rawContactId, dataId, NameLookupType.NAME_SHORTHAND,
61343b10d3a1ed1052dcdf529da370cb71b74164b158Dmitri Plotnikov                    NameNormalizer.normalize(givenName.trim()));
61353b10d3a1ed1052dcdf529da370cb71b74164b158Dmitri Plotnikov        }
613648786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov    }
613748786768751cdd9868fb3cf3c82d63f277a54b6fDmitri Plotnikov
61382d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov    public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) {
6139d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov        sb.append("(" +
6140d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                "SELECT DISTINCT " + RawContacts.CONTACT_ID +
6141d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " FROM " + Tables.RAW_CONTACTS +
6142d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " JOIN " + Tables.NAME_LOOKUP +
6143d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " ON(" + RawContactsColumns.CONCRETE_ID + "="
6144d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                        + NameLookupColumns.RAW_CONTACT_ID + ")" +
6145d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov                " WHERE normalized_name GLOB '");
6146e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov        sb.append(NameNormalizer.normalize(filterParam));
6147916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov        sb.append("*' AND " + NameLookupColumns.NAME_TYPE +
6148916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov                    " IN(" + CONTACT_LOOKUP_NAME_TYPES + "))");
6149e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov    }
6150e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov
61515ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public String getRawContactsByFilterAsNestedQuery(String filterParam) {
6152c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        StringBuilder sb = new StringBuilder();
61537318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov        appendRawContactsByFilterAsNestedQuery(sb, filterParam);
6154c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov        return sb.toString();
6155c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov    }
6156c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov
61577318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov    public void appendRawContactsByFilterAsNestedQuery(StringBuilder sb, String filterParam) {
61587318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov        appendRawContactsByNormalizedNameFilter(sb, NameNormalizer.normalize(filterParam), true);
61595e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    }
61605e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov
61615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov    private void appendRawContactsByNormalizedNameFilter(StringBuilder sb, String normalizedName,
61627318f9e11bdac5ea1ff5e6a8143b90c4e5c497f6Dmitri Plotnikov            boolean allowEmailMatch) {
616323061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov        if (TextUtils.isEmpty(normalizedName)) {
616423061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov            // Effectively an empty IN clause - SQL syntax does not allow an actual empty list here
616523061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov            sb.append("(0)");
616623061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov        } else {
616723061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov            sb.append("(" +
616823061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov                    "SELECT " + NameLookupColumns.RAW_CONTACT_ID +
616923061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov                    " FROM " + Tables.NAME_LOOKUP +
617023061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov                    " WHERE " + NameLookupColumns.NORMALIZED_NAME +
617123061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov                    " GLOB '");
617223061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov            // Should not use a "?" argument placeholder here, because
617323061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov            // that would prevent the SQL optimizer from using the index on NORMALIZED_NAME.
617423061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov            sb.append(normalizedName);
617523061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov            sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN ("
617623061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov                    + NameLookupType.NAME_COLLATION_KEY + ","
617723061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov                    + NameLookupType.NICKNAME + ","
617823061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov                    + NameLookupType.NAME_SHORTHAND + ","
617923061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov                    + NameLookupType.ORGANIZATION + ","
618023061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov                    + NameLookupType.NAME_CONSONANTS);
618123061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov            if (allowEmailMatch) {
618223061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov                sb.append("," + NameLookupType.EMAIL_BASED_NICKNAME);
618323061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov            }
618423061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov            sb.append("))");
618523061012b777c607100ce30250c3542b4fc8c1c8Dmitri Plotnikov        }
6186ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar    }
6187ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar
61884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    /**
61897a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov     * Takes components of a name from the query parameters and returns a cursor with those
61907a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov     * components as well as all missing components.  There is no database activity involved
61917a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov     * in this so the call can be made on the UI thread.
61927a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov     */
61937a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov    private Cursor completeName(Uri uri, String[] projection) {
61947a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        if (projection == null) {
61957a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov            projection = sDataProjectionMap.getColumnNames();
61967a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        }
61977a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov
61987a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        ContentValues values = new ContentValues();
61997a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        StructuredNameRowHandler handler =
62007a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                (StructuredNameRowHandler) getDataRowHandler(StructuredName.CONTENT_ITEM_TYPE);
62017a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov
62027a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        copyQueryParamsToContentValues(values, uri,
62037a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                StructuredName.DISPLAY_NAME,
62047a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                StructuredName.PREFIX,
62057a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                StructuredName.GIVEN_NAME,
62067a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                StructuredName.MIDDLE_NAME,
62077a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                StructuredName.FAMILY_NAME,
62087a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                StructuredName.SUFFIX,
62097a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                StructuredName.PHONETIC_NAME,
62107a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                StructuredName.PHONETIC_FAMILY_NAME,
62117a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                StructuredName.PHONETIC_MIDDLE_NAME,
62127a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                StructuredName.PHONETIC_GIVEN_NAME
62137a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        );
62147a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov
62157a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        handler.fixStructuredNameComponents(values, values);
62167a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov
62177a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        MatrixCursor cursor = new MatrixCursor(projection);
62187a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        Object[] row = new Object[projection.length];
62197a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        for (int i = 0; i < projection.length; i++) {
62207a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov            row[i] = values.get(projection[i]);
62217a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        }
62227a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        cursor.addRow(row);
62237a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        return cursor;
62247a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov    }
62257a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov
62267a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov    private void copyQueryParamsToContentValues(ContentValues values, Uri uri, String... columns) {
62277a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        for (String column : columns) {
62287a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov            String param = uri.getQueryParameter(column);
62297a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov            if (param != null) {
62307a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov                values.put(column, param);
62317a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov            }
62327a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov        }
62337a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov    }
62347a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov
62357a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov
62367a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov    /**
62374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     * Inserts an argument at the beginning of the selection arg list.
62384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov     */
62394a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov    private String[] insertSelectionArg(String[] selectionArgs, String arg) {
6240b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        if (selectionArgs == null) {
6241b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return new String[] {arg};
6242b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        } else {
6243b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            int newLength = selectionArgs.length + 1;
6244b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            String[] newSelectionArgs = new String[newLength];
62454a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            newSelectionArgs[0] = arg;
62464a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov            System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length);
6247b67163a1088f09c59f324350662eb18772fac6b6Evan Millar            return newSelectionArgs;
6248b67163a1088f09c59f324350662eb18772fac6b6Evan Millar        }
6249b67163a1088f09c59f324350662eb18772fac6b6Evan Millar    }
6250caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov
62515e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar    private String[] appendProjectionArg(String[] projection, String arg) {
62525e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        if (projection == null) {
62535e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar            return null;
62545e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        }
62555e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        final int length = projection.length;
62565e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        String[] newProjection = new String[length + 1];
62575e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        System.arraycopy(projection, 0, newProjection, 0, length);
62585e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        newProjection[length] = arg;
62595e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar        return newProjection;
62605e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar    }
62615e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar
6262caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    protected Account getDefaultAccount() {
6263caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        AccountManager accountManager = AccountManager.get(getContext());
6264caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        try {
6265df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana            Account[] accounts = accountManager.getAccountsByTypeAndFeatures(DEFAULT_ACCOUNT_TYPE,
6266df9fd6b239de5829b04cb413e4dfa3e6da649c38Fred Quintana                    new String[] {FEATURE_LEGACY_HOSTED_OR_GOOGLE}, null, null).getResult();
6267caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            if (accounts != null && accounts.length > 0) {
6268caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov                return accounts[0];
6269caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov            }
6270caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        } catch (Throwable e) {
62716f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov            Log.e(TAG, "Cannot determine the default account for contacts compatibility", e);
6272caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov        }
62736f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov        return null;
6274caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov    }
6275f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
627673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov    /**
627773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov     * Returns true if the specified account type is writable.
627873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov     */
627973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov    protected boolean isWritableAccount(String accountType) {
6280bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov        if (accountType == null) {
6281bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov            return true;
6282bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov        }
6283bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov
628473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov        Boolean writable = mAccountWritability.get(accountType);
628573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov        if (writable != null) {
628673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov            return writable;
628773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov        }
628873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov
6289627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        IContentService contentService = ContentResolver.getContentService();
6290627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        try {
6291627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) {
6292627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                if (ContactsContract.AUTHORITY.equals(sync.authority) &&
629373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov                        accountType.equals(sync.accountType)) {
629473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov                    writable = sync.supportsUploading();
629573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov                    break;
6296627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov                }
6297627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            }
6298627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        } catch (RemoteException e) {
6299627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov            Log.e(TAG, "Could not acquire sync adapter types");
6300627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov        }
630173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov
630273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov        if (writable == null) {
630373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov            writable = false;
630473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov        }
630573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov
630673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov        mAccountWritability.put(accountType, writable);
630773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov        return writable;
6308627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov    }
6309b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov
6310d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
6311f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter,
6312f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            boolean defaultValue) {
6313f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6314f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        // Manually parse the query, which is much faster than calling uri.getQueryParameter
6315f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String query = uri.getEncodedQuery();
6316f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (query == null) {
6317f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            return defaultValue;
6318f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
6319f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6320f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int index = query.indexOf(parameter);
6321f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (index == -1) {
6322f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            return defaultValue;
6323f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
6324f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6325f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        index += parameter.length();
6326f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6327f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        return !matchQueryParameter(query, index, "=0", false)
6328f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                && !matchQueryParameter(query, index, "=false", true);
6329f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    }
6330f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6331f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    private static boolean matchQueryParameter(String query, int index, String value,
6332f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            boolean ignoreCase) {
6333f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int length = value.length();
6334f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        return query.regionMatches(ignoreCase, index, value, 0, length)
6335f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                && (query.length() == index + length || query.charAt(index + length) == '&');
6336f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    }
6337f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6338f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    /**
6339f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov     * A fast re-implementation of {@link Uri#getQueryParameter}
6340f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov     */
6341f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    /* package */ static String getQueryParameter(Uri uri, String parameter) {
6342f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String query = uri.getEncodedQuery();
6343f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (query == null) {
6344f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            return null;
6345f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
6346f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6347f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int queryLength = query.length();
6348f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int parameterLength = parameter.length();
6349f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6350f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        String value;
6351f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int index = 0;
6352f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        while (true) {
6353f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            index = query.indexOf(parameter, index);
6354f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            if (index == -1) {
6355f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                return null;
6356f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            }
6357f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6358f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            index += parameterLength;
6359f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6360f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            if (queryLength == index) {
6361f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                return null;
6362f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            }
6363f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6364f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            if (query.charAt(index) == '=') {
6365f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                index++;
6366f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov                break;
6367f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            }
6368f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
6369f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6370f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        int ampIndex = query.indexOf('&', index);
6371f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        if (ampIndex == -1) {
6372f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            value = query.substring(index);
6373f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        } else {
6374f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov            value = query.substring(index, ampIndex);
6375f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        }
6376f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov
6377f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov        return Uri.decode(value);
6378f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov    }
63795dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov
63800dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov    protected boolean isAggregationUpgradeNeeded() {
63810dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        if (!mContactAggregator.isEnabled()) {
63820dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            return false;
63830dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        }
63840dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov
63850dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        int version = Integer.parseInt(mDbHelper.getProperty(PROPERTY_AGGREGATION_ALGORITHM, "1"));
63860dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        return version < PROPERTY_AGGREGATION_ALGORITHM_VERSION;
63870dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov    }
63880dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov
63890dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov    protected void upgradeAggregationAlgorithm() {
63900dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        // This upgrade will affect very few contacts, so it can be performed on the
63910dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        // main thread during the initial boot after an OTA
63920dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov
63930dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        Log.i(TAG, "Upgrading aggregation algorithm");
63940dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        int count = 0;
63950dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        long start = SystemClock.currentThreadTimeMillis();
63960dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        try {
639749d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov            mDb = mDbHelper.getWritableDatabase();
63980dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            mDb.beginTransaction();
63990dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            Cursor cursor = mDb.query(true,
64000dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    Tables.RAW_CONTACTS + " r1 JOIN " + Tables.RAW_CONTACTS + " r2",
64010dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    new String[]{"r1." + RawContacts._ID},
64020dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    "r1." + RawContacts._ID + "!=r2." + RawContacts._ID +
64030dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    " AND r1." + RawContacts.CONTACT_ID + "=r2." + RawContacts.CONTACT_ID +
64040dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    " AND r1." + RawContacts.ACCOUNT_NAME + "=r2." + RawContacts.ACCOUNT_NAME +
64050dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    " AND r1." + RawContacts.ACCOUNT_TYPE + "=r2." + RawContacts.ACCOUNT_TYPE,
64060dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    null, null, null, null, null);
64070dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            try {
64080dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                while (cursor.moveToNext()) {
64090dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    long rawContactId = cursor.getLong(0);
64100dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    mContactAggregator.markForAggregation(rawContactId,
64110dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                            RawContacts.AGGREGATION_MODE_DEFAULT, true);
64120dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    count++;
64130dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                }
64140dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            } finally {
64150dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                cursor.close();
64160dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            }
64170dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            mContactAggregator.aggregateInTransaction(mDb);
64180dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            mDb.setTransactionSuccessful();
64190dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            mDbHelper.setProperty(PROPERTY_AGGREGATION_ALGORITHM,
64200dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    String.valueOf(PROPERTY_AGGREGATION_ALGORITHM_VERSION));
64210dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        } finally {
64220dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            mDb.endTransaction();
642349d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov            mDb = null;
64240dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            long end = SystemClock.currentThreadTimeMillis();
64250dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov            Log.i(TAG, "Aggregation algorithm upgraded for " + count
64260dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov                    + " contacts, in " + (end - start) + "ms");
64270dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov        }
64280dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov    }
64294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton}
6430