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;
22e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wangimport android.provider.ContactsContract;
23f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email;
24f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname;
25f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization;
26f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone;
27f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
28f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.Data;
29f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.text.TextUtils;
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;
34aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fuimport com.android.providers.contacts.aggregation.AbstractContactAggregator;
3538210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki
36f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov/**
37f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Handles inserts and update for a specific Data type.
38f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */
39f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovpublic abstract class DataRowHandler {
40f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
41b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang    private static final String[] HASH_INPUT_COLUMNS = new String[] {
42e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang            Data.DATA1, Data.DATA2};
43b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang
44f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public interface DataDeleteQuery {
45f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
46f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
47f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        public static final String[] CONCRETE_COLUMNS = new String[] {
48f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            DataColumns.CONCRETE_ID,
49f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            MimetypesColumns.MIMETYPE,
50f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            Data.RAW_CONTACT_ID,
51f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            Data.IS_PRIMARY,
52f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            Data.DATA1,
53f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        };
54f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
55f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        public static final String[] COLUMNS = new String[] {
56f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            Data._ID,
57f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            MimetypesColumns.MIMETYPE,
58f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            Data.RAW_CONTACT_ID,
59f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            Data.IS_PRIMARY,
60f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            Data.DATA1,
61f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        };
62f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
63f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        public static final int _ID = 0;
64f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        public static final int MIMETYPE = 1;
65f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        public static final int RAW_CONTACT_ID = 2;
66f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        public static final int IS_PRIMARY = 3;
67f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        public static final int DATA1 = 4;
68f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
69f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
70f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public interface DataUpdateQuery {
71f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        String[] COLUMNS = { Data._ID, Data.RAW_CONTACT_ID, Data.MIMETYPE };
72f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
73f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int _ID = 0;
74f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int RAW_CONTACT_ID = 1;
75f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int MIMETYPE = 2;
76f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
77f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
786d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov    protected final Context mContext;
79f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    protected final ContactsDatabaseHelper mDbHelper;
80aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu    protected final AbstractContactAggregator mContactAggregator;
81f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    protected String[] mSelectionArgs1 = new String[1];
82f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    protected final String mMimetype;
83f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    protected long mMimetypeId;
84f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
85f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    @SuppressWarnings("all")
866d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov    public DataRowHandler(Context context, ContactsDatabaseHelper dbHelper,
87aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu            AbstractContactAggregator aggregator, String mimetype) {
886d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov        mContext = context;
89f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mDbHelper = dbHelper;
90f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mContactAggregator = aggregator;
91f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mMimetype = mimetype;
92f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
93f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        // To ensure the data column position. This is dead code if properly configured.
94f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (StructuredName.DISPLAY_NAME != Data.DATA1 || Nickname.NAME != Data.DATA1
95f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                || Organization.COMPANY != Data.DATA1 || Phone.NUMBER != Data.DATA1
96f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                || Email.DATA != Data.DATA1) {
97f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            throw new AssertionError("Some of ContactsContract.CommonDataKinds class primary"
98f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    + " data is not in DATA1 column");
99f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
100f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
101f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
102f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    protected long getMimeTypeId() {
103f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (mMimetypeId == 0) {
104f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mMimetypeId = mDbHelper.getMimeTypeId(mMimetype);
105f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
106f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return mMimetypeId;
107f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
108f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
109f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
110f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Inserts a row into the {@link Data} table.
111f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
112f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
113f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            ContentValues values) {
114b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang        // Generate hash_id from data1 and data2 columns.
115b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang        // For photo, use data15 column instead of data1 and data2 to generate hash_id.
116b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang        handleHashIdForInsert(values);
117f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final long dataId = db.insert(Tables.DATA, null, values);
118f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
119f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final Integer primary = values.getAsInteger(Data.IS_PRIMARY);
120f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final Integer superPrimary = values.getAsInteger(Data.IS_SUPER_PRIMARY);
121f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if ((primary != null && primary != 0) || (superPrimary != null && superPrimary != 0)) {
122f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final long mimeTypeId = getMimeTypeId();
123f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId);
12408fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu            txContext.markRawContactMetadataDirty(rawContactId, /* isMetadataSyncAdapter =*/false);
125f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
126f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            // We also have to make sure that no other data item on this raw_contact is
127f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            // configured super primary
128f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (superPrimary != null) {
129f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                if (superPrimary != 0) {
130f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
131f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                } else {
132f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    mDbHelper.clearSuperPrimary(rawContactId, mimeTypeId);
133f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
134f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            } else {
135f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                // if there is already another data item configured as super-primary,
136f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                // take over the flag (which will automatically remove it from the other item)
137f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                if (mDbHelper.rawContactHasSuperPrimary(rawContactId, mimeTypeId)) {
138f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
139f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
140f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
141f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
142f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
143f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        if (containsSearchableColumns(values)) {
144f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            txContext.invalidateSearchIndexForRawContact(rawContactId);
145f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
146f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
147f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return dataId;
148f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
149f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
150f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
151f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Validates data and updates a {@link Data} row using the cursor, which contains
152f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * the current data.
153f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     *
154f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * @return true if update changed something
155f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
156f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public boolean update(SQLiteDatabase db, TransactionContext txContext,
15708fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu            ContentValues values, Cursor c, boolean callerIsSyncAdapter,
15808fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu            boolean callerIsMetadataSyncAdapter) {
159f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long dataId = c.getLong(DataUpdateQuery._ID);
160f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
161f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
16208fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu        handlePrimaryAndSuperPrimary(txContext, values, dataId, rawContactId,
16308fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu                callerIsMetadataSyncAdapter);
164b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang        handleHashIdForUpdate(values, dataId);
165f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
166f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (values.size() > 0) {
167f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(dataId);
168f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            db.update(Tables.DATA, values, Data._ID + " =?", mSelectionArgs1);
169f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
170f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
171f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        if (containsSearchableColumns(values)) {
172f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            txContext.invalidateSearchIndexForRawContact(rawContactId);
173f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
174f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
1758ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng        txContext.markRawContactDirtyAndChanged(rawContactId, callerIsSyncAdapter);
176f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
177f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return true;
178f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
179f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
180f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    public boolean hasSearchableData() {
181f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        return false;
182f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    }
183f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
184f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    public boolean containsSearchableColumns(ContentValues values) {
185f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        return false;
186f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    }
187f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
188f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    public void appendSearchableData(SearchIndexManager.IndexBuilder builder) {
189f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    }
190f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
191f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
192b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang     * Fetch data1, data2, and data15 from values if they exist, and generate hash_id
193b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang     * if one of data1 and data2 columns is set, otherwise using data15 instead.
194b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang     * hash_id is null if all of these three field is null.
195b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang     * Add hash_id key to values.
196b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang     */
197b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang    public void handleHashIdForInsert(ContentValues values) {
198b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang        final String data1 = values.getAsString(Data.DATA1);
199b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang        final String data2 = values.getAsString(Data.DATA2);
200e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang        final String photoHashId= mDbHelper.getPhotoHashId();
201e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang
202e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang        String hashId;
203e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang        if (ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE.equals(mMimetype)) {
204e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang            hashId = photoHashId;
205e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang        } else if (!TextUtils.isEmpty(data1) || !TextUtils.isEmpty(data2)) {
206e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang            hashId = mDbHelper.generateHashId(data1, data2);
207e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang        } else {
208e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang            hashId = null;
209e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang        }
210b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang        if (TextUtils.isEmpty(hashId)) {
211b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang            values.putNull(Data.HASH_ID);
212b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang        } else {
213b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang            values.put(Data.HASH_ID, hashId);
214b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang        }
215b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang    }
216b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang
217b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang    /**
218b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang     * Compute hash_id column and add it to values.
219e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang     * If this is not a photo field, and one of data1 and data2 changed, re-compute hash_id with new
220e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang     * data1 and data2.
221e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang     * If this is a photo field, no need to change hash_id.
222b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang     */
223b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang    private void handleHashIdForUpdate(ContentValues values, long dataId) {
224e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang        if (!ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE.equals(mMimetype)
225e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang                && (values.containsKey(Data.DATA1) || values.containsKey(Data.DATA2))) {
22651cb9cf6158b7e077110f3d5a704a3b3673795b1Tingting Wang            String data1 = values.getAsString(Data.DATA1);
22751cb9cf6158b7e077110f3d5a704a3b3673795b1Tingting Wang            String data2 = values.getAsString(Data.DATA2);
228b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang            mSelectionArgs1[0] = String.valueOf(dataId);
229b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang            final Cursor c = mDbHelper.getReadableDatabase().query(Tables.DATA,
230b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang                    HASH_INPUT_COLUMNS, Data._ID + "=?", mSelectionArgs1, null, null, null);
231b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang            try {
232b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang                if (c.moveToFirst()) {
233b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang                    data1 = values.containsKey(Data.DATA1) ? data1 : c.getString(0);
234b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang                    data2 = values.containsKey(Data.DATA2) ? data2 : c.getString(1);
235b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang                }
236b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang            } finally {
237b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang                c.close();
238b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang            }
239e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang
240e8cdd9c437177da67ec41e24bc81e3c2d0a3efb3Tingting Wang            String hashId = mDbHelper.generateHashId(data1, data2);
24151cb9cf6158b7e077110f3d5a704a3b3673795b1Tingting Wang            if (TextUtils.isEmpty(hashId)) {
24251cb9cf6158b7e077110f3d5a704a3b3673795b1Tingting Wang                values.putNull(Data.HASH_ID);
24351cb9cf6158b7e077110f3d5a704a3b3673795b1Tingting Wang            } else {
24451cb9cf6158b7e077110f3d5a704a3b3673795b1Tingting Wang                values.put(Data.HASH_ID, hashId);
24551cb9cf6158b7e077110f3d5a704a3b3673795b1Tingting Wang            }
246b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang        }
247b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang    }
248b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang
249b712e3c95a1add30937dee5dddab429ce5247269Tingting Wang    /**
250f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Ensures that all super-primary and primary flags of this raw_contact are
251f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * configured correctly
252f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
25308fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu    private void handlePrimaryAndSuperPrimary(TransactionContext txContext, ContentValues values,
25408fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu            long dataId, long rawContactId, boolean callerIsMetadataSyncAdapter) {
255ee1267f05b98218d26f39875949cbc66a8a9b71dJay Shrauner        final boolean hasPrimary = values.getAsInteger(Data.IS_PRIMARY) != null;
256ee1267f05b98218d26f39875949cbc66a8a9b71dJay Shrauner        final boolean hasSuperPrimary = values.getAsInteger(Data.IS_SUPER_PRIMARY) != null;
257f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
258f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        // Nothing to do? Bail out early
259f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (!hasPrimary && !hasSuperPrimary) return;
260f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
26108fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu        txContext.markRawContactMetadataDirty(rawContactId, callerIsMetadataSyncAdapter);
26208fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu
263f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final long mimeTypeId = getMimeTypeId();
264f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
265f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        // Check if we want to clear values
266f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final boolean clearPrimary = hasPrimary &&
267f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                values.getAsInteger(Data.IS_PRIMARY) == 0;
268f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final boolean clearSuperPrimary = hasSuperPrimary &&
269f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                values.getAsInteger(Data.IS_SUPER_PRIMARY) == 0;
270f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
271f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (clearPrimary || clearSuperPrimary) {
272f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            // Test whether these values are currently set
273f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(dataId);
274f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final String[] cols = new String[] { Data.IS_PRIMARY, Data.IS_SUPER_PRIMARY };
275f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final Cursor c = mDbHelper.getReadableDatabase().query(Tables.DATA,
276f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    cols, Data._ID + "=?", mSelectionArgs1, null, null, null);
277f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            try {
278f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                if (c.moveToFirst()) {
279f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    final boolean isPrimary = c.getInt(0) != 0;
280f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    final boolean isSuperPrimary = c.getInt(1) != 0;
281f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    // Clear values if they are currently set
282f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    if (isSuperPrimary) {
283f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        mDbHelper.clearSuperPrimary(rawContactId, mimeTypeId);
284f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    }
285f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    if (clearPrimary && isPrimary) {
286f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        mDbHelper.setIsPrimary(rawContactId, -1, mimeTypeId);
287f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    }
288f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
289f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            } finally {
290f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                c.close();
291f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
292f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        } else {
293f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            // Check if we want to set values
294f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final boolean setPrimary = hasPrimary &&
295f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    values.getAsInteger(Data.IS_PRIMARY) != 0;
296f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final boolean setSuperPrimary = hasSuperPrimary &&
297f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    values.getAsInteger(Data.IS_SUPER_PRIMARY) != 0;
298f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (setSuperPrimary) {
299f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                // Set both super primary and primary
300f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
301f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId);
302f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            } else if (setPrimary) {
303f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                // Primary was explicitly set, but super-primary was not.
304f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                // In this case we set super-primary on this data item, if
305f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                // any data item of the same raw-contact already is super-primary
306f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                if (mDbHelper.rawContactHasSuperPrimary(rawContactId, mimeTypeId)) {
307f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
308f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
309f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId);
310f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
311f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
312f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
313f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        // Now that we've taken care of clearing this, remove it from "values".
314f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        values.remove(Data.IS_SUPER_PRIMARY);
315f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        values.remove(Data.IS_PRIMARY);
316f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
317f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
318f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
319f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long dataId = c.getLong(DataDeleteQuery._ID);
320f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
321f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean primary = c.getInt(DataDeleteQuery.IS_PRIMARY) != 0;
322f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(dataId);
323f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int count = db.delete(Tables.DATA, Data._ID + "=?", mSelectionArgs1);
324f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(rawContactId);
325f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        db.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=?", mSelectionArgs1);
326f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (count != 0 && primary) {
327f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            fixPrimary(db, rawContactId);
32808fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu            txContext.markRawContactMetadataDirty(rawContactId, /* isMetadataSyncAdapter =*/false);
329f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
330f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
331f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        if (hasSearchableData()) {
332f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            txContext.invalidateSearchIndexForRawContact(rawContactId);
333f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
334f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
335f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return count;
336f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
337f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
338f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private void fixPrimary(SQLiteDatabase db, long rawContactId) {
339f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long mimeTypeId = getMimeTypeId();
340f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long primaryId = -1;
341f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int primaryType = -1;
342f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(rawContactId);
343f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        Cursor c = db.query(DataDeleteQuery.TABLE,
344f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                DataDeleteQuery.CONCRETE_COLUMNS,
345f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                Data.RAW_CONTACT_ID + "=?" +
346f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    " AND " + DataColumns.MIMETYPE_ID + "=" + mimeTypeId,
347f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                mSelectionArgs1, null, null, null);
348f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        try {
349f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            while (c.moveToNext()) {
350f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                long dataId = c.getLong(DataDeleteQuery._ID);
351f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                int type = c.getInt(DataDeleteQuery.DATA1);
352f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) {
353f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    primaryId = dataId;
354f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    primaryType = type;
355f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
356f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
357f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        } finally {
358f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            c.close();
359f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
360f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (primaryId != -1) {
361f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mDbHelper.setIsPrimary(rawContactId, primaryId, mimeTypeId);
362f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
363f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
364f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
365f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
366f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Returns the rank of a specific record type to be used in determining the primary
367f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * row. Lower number represents higher priority.
368f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
369f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    protected int getTypeRank(int type) {
370f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return 0;
371f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
372f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
373f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    protected void fixRawContactDisplayName(SQLiteDatabase db, TransactionContext txContext,
374f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            long rawContactId) {
375f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (!isNewRawContact(txContext, rawContactId)) {
3768ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov            mDbHelper.updateRawContactDisplayName(db, rawContactId);
377f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mContactAggregator.updateDisplayNameForRawContact(db, rawContactId);
378f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
379f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
380f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
381f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private boolean isNewRawContact(TransactionContext txContext, long rawContactId) {
382f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return txContext.isNewRawContact(rawContactId);
383f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
384f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
385f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
386f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Return set of values, using current values at given {@link Data#_ID}
387f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * as baseline, but augmented with any updates.  Returns null if there is
388f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * no change.
389f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
390f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public ContentValues getAugmentedValues(SQLiteDatabase db, long dataId,
391f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            ContentValues update) {
392f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean changing = false;
393f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final ContentValues values = new ContentValues();
394f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(dataId);
395f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final Cursor cursor = db.query(Tables.DATA, null, Data._ID + "=?",
396f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                mSelectionArgs1, null, null, null);
397f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        try {
398f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (cursor.moveToFirst()) {
399f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                for (int i = 0; i < cursor.getColumnCount(); i++) {
400f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    final String key = cursor.getColumnName(i);
401f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    final String value = cursor.getString(i);
402f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    if (!changing && update.containsKey(key)) {
403f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        Object newValue = update.get(key);
404f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        String newString = newValue == null ? null : newValue.toString();
405f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        changing |= !TextUtils.equals(newString, value);
406f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    }
407f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    values.put(key, value);
408f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
409f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
410f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        } finally {
411f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            cursor.close();
412f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
413f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (!changing) {
414f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            return null;
415f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
416f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
417f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        values.putAll(update);
418f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return values;
419f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
420f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
421bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov    public void triggerAggregation(TransactionContext txContext, long rawContactId) {
422bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov        mContactAggregator.triggerAggregation(txContext, rawContactId);
423f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
424f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
425f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
426f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Test all against {@link TextUtils#isEmpty(CharSequence)}.
427f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
428f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public boolean areAllEmpty(ContentValues values, String[] keys) {
429f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        for (String key : keys) {
430f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (!TextUtils.isEmpty(values.getAsString(key))) {
431f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                return false;
432f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
433f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
434f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return true;
435f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
436f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
437f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
438f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Returns true if a value (possibly null) is specified for at least one of the supplied keys.
439f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
440f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public boolean areAnySpecified(ContentValues values, String[] keys) {
441f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        for (String key : keys) {
442f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (values.containsKey(key)) {
443f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                return true;
444f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
445f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
446f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return false;
447f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
448f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov}
449