1f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov/* 2f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Copyright (C) 2010 The Android Open Source Project 3f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * 4f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * use this file except in compliance with the License. You may obtain a copy of 6f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * the License at 7f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * 8f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * http://www.apache.org/licenses/LICENSE-2.0 9f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * 10f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software 11f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * License for the specific language governing permissions and limitations under 14f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * the License 15f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */ 16f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovpackage com.android.providers.contacts; 17f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 18f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.content.ContentValues; 196d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikovimport android.content.Context; 20f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.database.Cursor; 21f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.database.sqlite.SQLiteDatabase; 22f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email; 23f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname; 24f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization; 25f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone; 26f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 27f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.Data; 28f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.text.TextUtils; 29f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 3038210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; 3138210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns; 3238210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 3338210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Tables; 3438210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.aggregation.ContactAggregator; 3538210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki 36f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov/** 37f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Handles inserts and update for a specific Data type. 38f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */ 39f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovpublic abstract class DataRowHandler { 40f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 41f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public interface DataDeleteQuery { 42f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public static final String TABLE = Tables.DATA_JOIN_MIMETYPES; 43f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 44f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public static final String[] CONCRETE_COLUMNS = new String[] { 45f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataColumns.CONCRETE_ID, 46f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov MimetypesColumns.MIMETYPE, 47f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Data.RAW_CONTACT_ID, 48f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Data.IS_PRIMARY, 49f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Data.DATA1, 50f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov }; 51f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 52f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public static final String[] COLUMNS = new String[] { 53f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Data._ID, 54f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov MimetypesColumns.MIMETYPE, 55f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Data.RAW_CONTACT_ID, 56f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Data.IS_PRIMARY, 57f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Data.DATA1, 58f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov }; 59f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 60f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public static final int _ID = 0; 61f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public static final int MIMETYPE = 1; 62f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public static final int RAW_CONTACT_ID = 2; 63f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public static final int IS_PRIMARY = 3; 64f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public static final int DATA1 = 4; 65f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 66f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 67f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public interface DataUpdateQuery { 68f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String[] COLUMNS = { Data._ID, Data.RAW_CONTACT_ID, Data.MIMETYPE }; 69f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 70f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov int _ID = 0; 71f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov int RAW_CONTACT_ID = 1; 72f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov int MIMETYPE = 2; 73f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 74f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 756d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov protected final Context mContext; 76f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov protected final ContactsDatabaseHelper mDbHelper; 77f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov protected final ContactAggregator mContactAggregator; 78f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov protected String[] mSelectionArgs1 = new String[1]; 79f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov protected final String mMimetype; 80f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov protected long mMimetypeId; 81f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 82f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov @SuppressWarnings("all") 836d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov public DataRowHandler(Context context, ContactsDatabaseHelper dbHelper, 846d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov ContactAggregator aggregator, String mimetype) { 856d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov mContext = context; 86f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper = dbHelper; 87f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mContactAggregator = aggregator; 88f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mMimetype = mimetype; 89f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 90f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // To ensure the data column position. This is dead code if properly configured. 91f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (StructuredName.DISPLAY_NAME != Data.DATA1 || Nickname.NAME != Data.DATA1 92f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov || Organization.COMPANY != Data.DATA1 || Phone.NUMBER != Data.DATA1 93f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov || Email.DATA != Data.DATA1) { 94f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov throw new AssertionError("Some of ContactsContract.CommonDataKinds class primary" 95f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov + " data is not in DATA1 column"); 96f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 97f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 98f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 99f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov protected long getMimeTypeId() { 100f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (mMimetypeId == 0) { 101f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mMimetypeId = mDbHelper.getMimeTypeId(mMimetype); 102f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 103f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return mMimetypeId; 104f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 105f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 106f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov /** 107f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Inserts a row into the {@link Data} table. 108f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */ 109f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId, 110f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov ContentValues values) { 111f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final long dataId = db.insert(Tables.DATA, null, values); 112f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 113f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final Integer primary = values.getAsInteger(Data.IS_PRIMARY); 114f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final Integer superPrimary = values.getAsInteger(Data.IS_SUPER_PRIMARY); 115f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if ((primary != null && primary != 0) || (superPrimary != null && superPrimary != 0)) { 116f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final long mimeTypeId = getMimeTypeId(); 117f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId); 118f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 119f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // We also have to make sure that no other data item on this raw_contact is 120f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // configured super primary 121f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (superPrimary != null) { 122f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (superPrimary != 0) { 123f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId); 124f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } else { 125f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.clearSuperPrimary(rawContactId, mimeTypeId); 126f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 127f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } else { 128f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // if there is already another data item configured as super-primary, 129f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // take over the flag (which will automatically remove it from the other item) 130f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (mDbHelper.rawContactHasSuperPrimary(rawContactId, mimeTypeId)) { 131f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId); 132f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 133f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 134f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 135f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 136f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov if (containsSearchableColumns(values)) { 137f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov txContext.invalidateSearchIndexForRawContact(rawContactId); 138f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov } 139f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov 140f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return dataId; 141f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 142f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 143f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov /** 144f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Validates data and updates a {@link Data} row using the cursor, which contains 145f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * the current data. 146f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * 147f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * @return true if update changed something 148f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */ 149f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public boolean update(SQLiteDatabase db, TransactionContext txContext, 150f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov ContentValues values, Cursor c, boolean callerIsSyncAdapter) { 151f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long dataId = c.getLong(DataUpdateQuery._ID); 152f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID); 153f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 154f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov handlePrimaryAndSuperPrimary(values, dataId, rawContactId); 155f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 156f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (values.size() > 0) { 157f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 158f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov db.update(Tables.DATA, values, Data._ID + " =?", mSelectionArgs1); 159f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 160f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 161f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov if (containsSearchableColumns(values)) { 162f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov txContext.invalidateSearchIndexForRawContact(rawContactId); 163f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov } 164f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov 165f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (!callerIsSyncAdapter) { 166f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov txContext.markRawContactDirty(rawContactId); 167f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 168f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 169f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return true; 170f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 171f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 172f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public boolean hasSearchableData() { 173f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov return false; 174f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov } 175f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov 176f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public boolean containsSearchableColumns(ContentValues values) { 177f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov return false; 178f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov } 179f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov 180f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public void appendSearchableData(SearchIndexManager.IndexBuilder builder) { 181f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov } 182f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov 183f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov /** 184f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Ensures that all super-primary and primary flags of this raw_contact are 185f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * configured correctly 186f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */ 187f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov private void handlePrimaryAndSuperPrimary(ContentValues values, long dataId, 188f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId) { 189f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final boolean hasPrimary = values.containsKey(Data.IS_PRIMARY); 190f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final boolean hasSuperPrimary = values.containsKey(Data.IS_SUPER_PRIMARY); 191f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 192f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // Nothing to do? Bail out early 193f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (!hasPrimary && !hasSuperPrimary) return; 194f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 195f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final long mimeTypeId = getMimeTypeId(); 196f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 197f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // Check if we want to clear values 198f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final boolean clearPrimary = hasPrimary && 199f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov values.getAsInteger(Data.IS_PRIMARY) == 0; 200f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final boolean clearSuperPrimary = hasSuperPrimary && 201f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov values.getAsInteger(Data.IS_SUPER_PRIMARY) == 0; 202f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 203f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (clearPrimary || clearSuperPrimary) { 204f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // Test whether these values are currently set 205f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 206f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String[] cols = new String[] { Data.IS_PRIMARY, Data.IS_SUPER_PRIMARY }; 207f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final Cursor c = mDbHelper.getReadableDatabase().query(Tables.DATA, 208f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov cols, Data._ID + "=?", mSelectionArgs1, null, null, null); 209f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov try { 210f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (c.moveToFirst()) { 211f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final boolean isPrimary = c.getInt(0) != 0; 212f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final boolean isSuperPrimary = c.getInt(1) != 0; 213f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // Clear values if they are currently set 214f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (isSuperPrimary) { 215f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.clearSuperPrimary(rawContactId, mimeTypeId); 216f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 217f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (clearPrimary && isPrimary) { 218f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.setIsPrimary(rawContactId, -1, mimeTypeId); 219f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 220f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 221f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } finally { 222f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov c.close(); 223f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 224f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } else { 225f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // Check if we want to set values 226f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final boolean setPrimary = hasPrimary && 227f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov values.getAsInteger(Data.IS_PRIMARY) != 0; 228f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final boolean setSuperPrimary = hasSuperPrimary && 229f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov values.getAsInteger(Data.IS_SUPER_PRIMARY) != 0; 230f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (setSuperPrimary) { 231f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // Set both super primary and primary 232f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId); 233f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId); 234f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } else if (setPrimary) { 235f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // Primary was explicitly set, but super-primary was not. 236f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // In this case we set super-primary on this data item, if 237f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // any data item of the same raw-contact already is super-primary 238f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (mDbHelper.rawContactHasSuperPrimary(rawContactId, mimeTypeId)) { 239f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId); 240f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 241f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId); 242f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 243f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 244f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 245f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov // Now that we've taken care of clearing this, remove it from "values". 246f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov values.remove(Data.IS_SUPER_PRIMARY); 247f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov values.remove(Data.IS_PRIMARY); 248f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 249f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 250f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) { 251f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long dataId = c.getLong(DataDeleteQuery._ID); 252f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID); 253f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov boolean primary = c.getInt(DataDeleteQuery.IS_PRIMARY) != 0; 254f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 255f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov int count = db.delete(Tables.DATA, Data._ID + "=?", mSelectionArgs1); 256f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 257f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov db.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=?", mSelectionArgs1); 258f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (count != 0 && primary) { 259f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov fixPrimary(db, rawContactId); 260f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 261f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov 262f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov if (hasSearchableData()) { 263f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov txContext.invalidateSearchIndexForRawContact(rawContactId); 264f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov } 265f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov 266f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return count; 267f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 268f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 269f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov private void fixPrimary(SQLiteDatabase db, long rawContactId) { 270f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long mimeTypeId = getMimeTypeId(); 271f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long primaryId = -1; 272f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov int primaryType = -1; 273f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 274f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = db.query(DataDeleteQuery.TABLE, 275f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataDeleteQuery.CONCRETE_COLUMNS, 276f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Data.RAW_CONTACT_ID + "=?" + 277f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov " AND " + DataColumns.MIMETYPE_ID + "=" + mimeTypeId, 278f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mSelectionArgs1, null, null, null); 279f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov try { 280f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov while (c.moveToNext()) { 281f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long dataId = c.getLong(DataDeleteQuery._ID); 282f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov int type = c.getInt(DataDeleteQuery.DATA1); 283f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) { 284f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov primaryId = dataId; 285f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov primaryType = type; 286f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 287f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 288f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } finally { 289f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov c.close(); 290f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 291f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (primaryId != -1) { 292f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mDbHelper.setIsPrimary(rawContactId, primaryId, mimeTypeId); 293f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 294f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 295f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 296f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov /** 297f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Returns the rank of a specific record type to be used in determining the primary 298f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * row. Lower number represents higher priority. 299f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */ 300f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov protected int getTypeRank(int type) { 301f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return 0; 302f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 303f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 304f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov protected void fixRawContactDisplayName(SQLiteDatabase db, TransactionContext txContext, 305f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId) { 306f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (!isNewRawContact(txContext, rawContactId)) { 3078ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov mDbHelper.updateRawContactDisplayName(db, rawContactId); 308f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mContactAggregator.updateDisplayNameForRawContact(db, rawContactId); 309f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 310f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 311f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 312f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov private boolean isNewRawContact(TransactionContext txContext, long rawContactId) { 313f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return txContext.isNewRawContact(rawContactId); 314f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 315f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 316f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov /** 317f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Return set of values, using current values at given {@link Data#_ID} 318f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * as baseline, but augmented with any updates. Returns null if there is 319f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * no change. 320f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */ 321f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public ContentValues getAugmentedValues(SQLiteDatabase db, long dataId, 322f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov ContentValues update) { 323f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov boolean changing = false; 324f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final ContentValues values = new ContentValues(); 325f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 326f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final Cursor cursor = db.query(Tables.DATA, null, Data._ID + "=?", 327f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov mSelectionArgs1, null, null, null); 328f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov try { 329f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (cursor.moveToFirst()) { 330f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov for (int i = 0; i < cursor.getColumnCount(); i++) { 331f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String key = cursor.getColumnName(i); 332f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String value = cursor.getString(i); 333f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (!changing && update.containsKey(key)) { 334f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Object newValue = update.get(key); 335f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String newString = newValue == null ? null : newValue.toString(); 336f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov changing |= !TextUtils.equals(newString, value); 337f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 338f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov values.put(key, value); 339f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 340f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 341f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } finally { 342f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov cursor.close(); 343f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 344f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (!changing) { 345f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return null; 346f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 347f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 348f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov values.putAll(update); 349f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return values; 350f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 351f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 352bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov public void triggerAggregation(TransactionContext txContext, long rawContactId) { 353bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mContactAggregator.triggerAggregation(txContext, rawContactId); 354f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 355f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 356f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov /** 357f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Test all against {@link TextUtils#isEmpty(CharSequence)}. 358f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */ 359f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public boolean areAllEmpty(ContentValues values, String[] keys) { 360f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov for (String key : keys) { 361f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (!TextUtils.isEmpty(values.getAsString(key))) { 362f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return false; 363f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 364f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 365f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return true; 366f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 367f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov 368f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov /** 369f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Returns true if a value (possibly null) is specified for at least one of the supplied keys. 370f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */ 371f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov public boolean areAnySpecified(ContentValues values, String[] keys) { 372f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov for (String key : keys) { 373f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov if (values.containsKey(key)) { 374f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return true; 375f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 376f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 377f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov return false; 378f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov } 379f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov} 380