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