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