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