DataRowHandler.java revision 08fb8384ccb36de3d3d046e287fe5c43c1f85faf
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;
2938210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns;
3038210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns;
3138210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns;
3238210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Tables;
33aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fuimport com.android.providers.contacts.aggregation.AbstractContactAggregator;
3438210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki
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;
76aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu    protected final AbstractContactAggregator 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,
83aa18c233fdec3359c5231d4a5f61188446bf5d6fZheng Fu            AbstractContactAggregator 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);
11708fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu            txContext.markRawContactMetadataDirty(rawContactId, /* isMetadataSyncAdapter =*/false);
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,
15008fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu            ContentValues values, Cursor c, boolean callerIsSyncAdapter,
15108fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu            boolean callerIsMetadataSyncAdapter) {
152f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long dataId = c.getLong(DataUpdateQuery._ID);
153f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
154f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
15508fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu        handlePrimaryAndSuperPrimary(txContext, values, dataId, rawContactId,
15608fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu                callerIsMetadataSyncAdapter);
157f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
158f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (values.size() > 0) {
159f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(dataId);
160f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            db.update(Tables.DATA, values, Data._ID + " =?", mSelectionArgs1);
161f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
162f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
163f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        if (containsSearchableColumns(values)) {
164f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            txContext.invalidateSearchIndexForRawContact(rawContactId);
165f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
166f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
1678ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng        txContext.markRawContactDirtyAndChanged(rawContactId, callerIsSyncAdapter);
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     */
18708fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu    private void handlePrimaryAndSuperPrimary(TransactionContext txContext, ContentValues values,
18808fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu            long dataId, long rawContactId, boolean callerIsMetadataSyncAdapter) {
189ee1267f05b98218d26f39875949cbc66a8a9b71dJay Shrauner        final boolean hasPrimary = values.getAsInteger(Data.IS_PRIMARY) != null;
190ee1267f05b98218d26f39875949cbc66a8a9b71dJay Shrauner        final boolean hasSuperPrimary = values.getAsInteger(Data.IS_SUPER_PRIMARY) != null;
191f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
192f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        // Nothing to do? Bail out early
193f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (!hasPrimary && !hasSuperPrimary) return;
194f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
19508fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu        txContext.markRawContactMetadataDirty(rawContactId, callerIsMetadataSyncAdapter);
19608fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu
197f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final long mimeTypeId = getMimeTypeId();
198f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
199f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        // Check if we want to clear values
200f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final boolean clearPrimary = hasPrimary &&
201f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                values.getAsInteger(Data.IS_PRIMARY) == 0;
202f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final boolean clearSuperPrimary = hasSuperPrimary &&
203f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                values.getAsInteger(Data.IS_SUPER_PRIMARY) == 0;
204f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
205f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (clearPrimary || clearSuperPrimary) {
206f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            // Test whether these values are currently set
207f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(dataId);
208f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final String[] cols = new String[] { Data.IS_PRIMARY, Data.IS_SUPER_PRIMARY };
209f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final Cursor c = mDbHelper.getReadableDatabase().query(Tables.DATA,
210f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    cols, Data._ID + "=?", mSelectionArgs1, null, null, null);
211f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            try {
212f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                if (c.moveToFirst()) {
213f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    final boolean isPrimary = c.getInt(0) != 0;
214f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    final boolean isSuperPrimary = c.getInt(1) != 0;
215f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    // Clear values if they are currently set
216f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    if (isSuperPrimary) {
217f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        mDbHelper.clearSuperPrimary(rawContactId, mimeTypeId);
218f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    }
219f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    if (clearPrimary && isPrimary) {
220f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        mDbHelper.setIsPrimary(rawContactId, -1, mimeTypeId);
221f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    }
222f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
223f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            } finally {
224f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                c.close();
225f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
226f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        } else {
227f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            // Check if we want to set values
228f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final boolean setPrimary = hasPrimary &&
229f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    values.getAsInteger(Data.IS_PRIMARY) != 0;
230f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final boolean setSuperPrimary = hasSuperPrimary &&
231f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    values.getAsInteger(Data.IS_SUPER_PRIMARY) != 0;
232f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (setSuperPrimary) {
233f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                // Set both super primary and primary
234f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
235f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId);
236f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            } else if (setPrimary) {
237f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                // Primary was explicitly set, but super-primary was not.
238f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                // In this case we set super-primary on this data item, if
239f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                // any data item of the same raw-contact already is super-primary
240f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                if (mDbHelper.rawContactHasSuperPrimary(rawContactId, mimeTypeId)) {
241f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    mDbHelper.setIsSuperPrimary(rawContactId, dataId, mimeTypeId);
242f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
243f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                mDbHelper.setIsPrimary(rawContactId, dataId, mimeTypeId);
244f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
245f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
246f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
247f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        // Now that we've taken care of clearing this, remove it from "values".
248f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        values.remove(Data.IS_SUPER_PRIMARY);
249f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        values.remove(Data.IS_PRIMARY);
250f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
251f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
252f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
253f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long dataId = c.getLong(DataDeleteQuery._ID);
254f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
255f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean primary = c.getInt(DataDeleteQuery.IS_PRIMARY) != 0;
256f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(dataId);
257f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int count = db.delete(Tables.DATA, Data._ID + "=?", mSelectionArgs1);
258f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(rawContactId);
259f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        db.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=?", mSelectionArgs1);
260f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (count != 0 && primary) {
261f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            fixPrimary(db, rawContactId);
26208fb8384ccb36de3d3d046e287fe5c43c1f85fafZheng Fu            txContext.markRawContactMetadataDirty(rawContactId, /* isMetadataSyncAdapter =*/false);
263f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
264f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
265f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        if (hasSearchableData()) {
266f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            txContext.invalidateSearchIndexForRawContact(rawContactId);
267f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
268f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
269f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return count;
270f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
271f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
272f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private void fixPrimary(SQLiteDatabase db, long rawContactId) {
273f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long mimeTypeId = getMimeTypeId();
274f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long primaryId = -1;
275f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int primaryType = -1;
276f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(rawContactId);
277f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        Cursor c = db.query(DataDeleteQuery.TABLE,
278f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                DataDeleteQuery.CONCRETE_COLUMNS,
279f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                Data.RAW_CONTACT_ID + "=?" +
280f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    " AND " + DataColumns.MIMETYPE_ID + "=" + mimeTypeId,
281f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                mSelectionArgs1, null, null, null);
282f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        try {
283f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            while (c.moveToNext()) {
284f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                long dataId = c.getLong(DataDeleteQuery._ID);
285f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                int type = c.getInt(DataDeleteQuery.DATA1);
286f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) {
287f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    primaryId = dataId;
288f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    primaryType = type;
289f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
290f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
291f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        } finally {
292f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            c.close();
293f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
294f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (primaryId != -1) {
295f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mDbHelper.setIsPrimary(rawContactId, primaryId, mimeTypeId);
296f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
297f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
298f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
299f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
300f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Returns the rank of a specific record type to be used in determining the primary
301f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * row. Lower number represents higher priority.
302f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
303f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    protected int getTypeRank(int type) {
304f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return 0;
305f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
306f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
307f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    protected void fixRawContactDisplayName(SQLiteDatabase db, TransactionContext txContext,
308f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            long rawContactId) {
309f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (!isNewRawContact(txContext, rawContactId)) {
3108ab0b7a48efe540226253567bcf6fdbc487186a2Dmitri Plotnikov            mDbHelper.updateRawContactDisplayName(db, rawContactId);
311f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mContactAggregator.updateDisplayNameForRawContact(db, rawContactId);
312f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
313f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
314f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
315f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private boolean isNewRawContact(TransactionContext txContext, long rawContactId) {
316f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return txContext.isNewRawContact(rawContactId);
317f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
318f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
319f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
320f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Return set of values, using current values at given {@link Data#_ID}
321f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * as baseline, but augmented with any updates.  Returns null if there is
322f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * no change.
323f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
324f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public ContentValues getAugmentedValues(SQLiteDatabase db, long dataId,
325f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            ContentValues update) {
326f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean changing = false;
327f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final ContentValues values = new ContentValues();
328f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mSelectionArgs1[0] = String.valueOf(dataId);
329f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final Cursor cursor = db.query(Tables.DATA, null, Data._ID + "=?",
330f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                mSelectionArgs1, null, null, null);
331f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        try {
332f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (cursor.moveToFirst()) {
333f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                for (int i = 0; i < cursor.getColumnCount(); i++) {
334f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    final String key = cursor.getColumnName(i);
335f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    final String value = cursor.getString(i);
336f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    if (!changing && update.containsKey(key)) {
337f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        Object newValue = update.get(key);
338f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        String newString = newValue == null ? null : newValue.toString();
339f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        changing |= !TextUtils.equals(newString, value);
340f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    }
341f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    values.put(key, value);
342f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
343f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
344f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        } finally {
345f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            cursor.close();
346f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
347f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (!changing) {
348f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            return null;
349f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
350f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
351f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        values.putAll(update);
352f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return values;
353f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
354f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
355bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov    public void triggerAggregation(TransactionContext txContext, long rawContactId) {
356bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov        mContactAggregator.triggerAggregation(txContext, rawContactId);
357f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
358f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
359f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
360f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Test all against {@link TextUtils#isEmpty(CharSequence)}.
361f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
362f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public boolean areAllEmpty(ContentValues values, String[] keys) {
363f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        for (String key : keys) {
364f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (!TextUtils.isEmpty(values.getAsString(key))) {
365f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                return false;
366f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
367f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
368f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return true;
369f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
370f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
371f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
372f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Returns true if a value (possibly null) is specified for at least one of the supplied keys.
373f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
374f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public boolean areAnySpecified(ContentValues values, String[] keys) {
375f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        for (String key : keys) {
376f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (values.containsKey(key)) {
377f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                return true;
378f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
379f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
380f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return false;
381f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
382f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov}
383