DataRowHandlerForGroupMembership.java revision 6d9702cec82fd27a1c3093c64df9dcc22744899a
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.Clauses;
19f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns;
20f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns;
21f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables;
22f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport com.android.providers.contacts.ContactsProvider2.GroupIdCacheEntry;
23f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
24f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.accounts.Account;
25f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.content.ContentValues;
266d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikovimport android.content.Context;
27f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.database.Cursor;
28f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.database.DatabaseUtils;
29f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.database.sqlite.SQLiteDatabase;
30f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
31f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.Groups;
32f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
33f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport android.text.TextUtils;
34f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
35f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport java.util.ArrayList;
36f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovimport java.util.HashMap;
37f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
38f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov/**
39f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov * Handler for group membership data rows.
40f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov */
41f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikovpublic class DataRowHandlerForGroupMembership extends DataRowHandler {
42f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
43f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    interface RawContactsQuery {
44f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        String TABLE = Tables.RAW_CONTACTS;
45f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
46f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        String[] COLUMNS = new String[] {
47f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                RawContacts.DELETED,
48f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                RawContacts.ACCOUNT_TYPE,
49f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                RawContacts.ACCOUNT_NAME,
50f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        };
51f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
52f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int DELETED = 0;
53f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int ACCOUNT_TYPE = 1;
54f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int ACCOUNT_NAME = 2;
55f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
56f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
57f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private static final String SELECTION_RAW_CONTACT_ID = RawContacts._ID + "=?";
58f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
59f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private static final String QUERY_COUNT_FAVORITES_GROUP_MEMBERSHIPS_BY_RAW_CONTACT_ID =
60f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            "SELECT COUNT(*) FROM " + Tables.DATA + " LEFT OUTER JOIN " + Tables .GROUPS
61f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    + " ON " + Tables.DATA + "." + GroupMembership.GROUP_ROW_ID
62f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    + "=" + GroupsColumns.CONCRETE_ID
63f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    + " WHERE " + DataColumns.MIMETYPE_ID + "=?"
64f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    + " AND " + Tables.DATA + "." + GroupMembership.RAW_CONTACT_ID + "=?"
65f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    + " AND " + Groups.FAVORITES + "!=0";
66f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
67f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private final HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache;
68f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
696d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov    public DataRowHandlerForGroupMembership(Context context, ContactsDatabaseHelper dbHelper,
70f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            ContactAggregator aggregator,
71f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            HashMap<String, ArrayList<GroupIdCacheEntry>> groupIdCache) {
726d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov        super(context, dbHelper, aggregator, GroupMembership.CONTENT_ITEM_TYPE);
73f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        mGroupIdCache = groupIdCache;
74f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
75f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
76f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    @Override
77f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public long insert(SQLiteDatabase db, TransactionContext txContext, long rawContactId,
78f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            ContentValues values) {
79f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        resolveGroupSourceIdInValues(txContext, rawContactId, db, values, true);
80f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long dataId = super.insert(db, txContext, rawContactId, values);
81f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (hasFavoritesGroupMembership(db, rawContactId)) {
82f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            updateRawContactsStar(db, rawContactId, true /* starred */);
83f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
84f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        updateVisibility(rawContactId);
85f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return dataId;
86f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
87f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
88f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    @Override
89f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public boolean update(SQLiteDatabase db, TransactionContext txContext, ContentValues values,
90f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            Cursor c, boolean callerIsSyncAdapter) {
91f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
92f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean wasStarred = hasFavoritesGroupMembership(db, rawContactId);
93f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        resolveGroupSourceIdInValues(txContext, rawContactId, db, values, false);
94f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (!super.update(db, txContext, values, c, callerIsSyncAdapter)) {
95f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            return false;
96f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
97f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean isStarred = hasFavoritesGroupMembership(db, rawContactId);
98f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (wasStarred != isStarred) {
99f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            updateRawContactsStar(db, rawContactId, isStarred);
100f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
101f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        updateVisibility(rawContactId);
102f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return true;
103f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
104f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
105f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private void updateRawContactsStar(SQLiteDatabase db, long rawContactId, boolean starred) {
106f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        ContentValues rawContactValues = new ContentValues();
107f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        rawContactValues.put(RawContacts.STARRED, starred ? 1 : 0);
108f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (db.update(Tables.RAW_CONTACTS, rawContactValues, SELECTION_RAW_CONTACT_ID,
109f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                new String[]{Long.toString(rawContactId)}) > 0) {
110f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mContactAggregator.updateStarred(rawContactId);
111f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
112f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
113f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
114f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private boolean hasFavoritesGroupMembership(SQLiteDatabase db, long rawContactId) {
115f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        // TODO compiled SQL statement
116f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        final long groupMembershipMimetypeId = mDbHelper
117f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
118f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean isStarred = 0 < DatabaseUtils
119f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                .longForQuery(db, QUERY_COUNT_FAVORITES_GROUP_MEMBERSHIPS_BY_RAW_CONTACT_ID,
120f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                new String[]{Long.toString(groupMembershipMimetypeId), Long.toString(rawContactId)});
121f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return isStarred;
122f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
123f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
124f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    @Override
125f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    public int delete(SQLiteDatabase db, TransactionContext txContext, Cursor c) {
126f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
127f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean wasStarred = hasFavoritesGroupMembership(db, rawContactId);
128f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int count = super.delete(db, txContext, c);
129f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean isStarred = hasFavoritesGroupMembership(db, rawContactId);
130f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (wasStarred && !isStarred) {
131f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            updateRawContactsStar(db, rawContactId, false /* starred */);
132f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
133f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        updateVisibility(rawContactId);
134f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return count;
135f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
136f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
137f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private void updateVisibility(long rawContactId) {
138f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        long contactId = mDbHelper.getContactId(rawContactId);
139f266e8c568905337960b1fec5379841585af92a7Dmitri Plotnikov        if (contactId == 0) {
140f266e8c568905337960b1fec5379841585af92a7Dmitri Plotnikov            return;
141f266e8c568905337960b1fec5379841585af92a7Dmitri Plotnikov        }
142f266e8c568905337960b1fec5379841585af92a7Dmitri Plotnikov
143f266e8c568905337960b1fec5379841585af92a7Dmitri Plotnikov        if (mDbHelper.updateContactVisibleOnlyIfChanged(contactId)) {
144f266e8c568905337960b1fec5379841585af92a7Dmitri Plotnikov            mContactAggregator.updateAggregationAfterVisibilityChange(contactId);
145f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
146f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
147f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
148f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private void resolveGroupSourceIdInValues(TransactionContext txContext,
149f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            long rawContactId, SQLiteDatabase db, ContentValues values, boolean isInsert) {
150f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean containsGroupSourceId = values.containsKey(GroupMembership.GROUP_SOURCE_ID);
151f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        boolean containsGroupId = values.containsKey(GroupMembership.GROUP_ROW_ID);
152f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (containsGroupSourceId && containsGroupId) {
153f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            throw new IllegalArgumentException(
154f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    "you are not allowed to set both the GroupMembership.GROUP_SOURCE_ID "
155f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                            + "and GroupMembership.GROUP_ROW_ID");
156f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
157f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
158f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (!containsGroupSourceId && !containsGroupId) {
159f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (isInsert) {
160f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                throw new IllegalArgumentException(
161f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        "you must set exactly one of GroupMembership.GROUP_SOURCE_ID "
162f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                                + "and GroupMembership.GROUP_ROW_ID");
163f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            } else {
164f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                return;
165f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
166f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
167f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
168f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (containsGroupSourceId) {
169f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final String sourceId = values.getAsString(GroupMembership.GROUP_SOURCE_ID);
170f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            final long groupId = getOrMakeGroup(db, rawContactId, sourceId,
171f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    txContext.getAccountForRawContact(rawContactId));
172f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            values.remove(GroupMembership.GROUP_SOURCE_ID);
173f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            values.put(GroupMembership.GROUP_ROW_ID, groupId);
174f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
175f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
176f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
177f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    /**
178f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * Returns the group id of the group with sourceId and the same account as rawContactId.
179f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * If the group doesn't already exist then it is first created,
180f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * @param db SQLiteDatabase to use for this operation
181f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * @param rawContactId the contact this group is associated with
182f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * @param sourceId the sourceIf of the group to query or create
183f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * @return the group id of the existing or created group
184f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * @throws IllegalArgumentException if the contact is not associated with an account
185f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     * @throws IllegalStateException if a group needs to be created but the creation failed
186f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov     */
187f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    private long getOrMakeGroup(SQLiteDatabase db, long rawContactId, String sourceId,
188f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            Account account) {
189f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
190f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (account == null) {
191f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(rawContactId);
192f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            Cursor c = db.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS,
193f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    RawContacts._ID + "=?", mSelectionArgs1, null, null, null);
194f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            try {
195f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                if (c.moveToFirst()) {
196f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    String accountName = c.getString(RawContactsQuery.ACCOUNT_NAME);
197f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    String accountType = c.getString(RawContactsQuery.ACCOUNT_TYPE);
198f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
199f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                        account = new Account(accountName, accountType);
200f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    }
201f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
202f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            } finally {
203f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                c.close();
204f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
205f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
206f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
207f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (account == null) {
208f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            throw new IllegalArgumentException("if the groupmembership only "
209f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    + "has a sourceid the the contact must be associated with "
210f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    + "an account");
211f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
212f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
213f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        ArrayList<GroupIdCacheEntry> entries = mGroupIdCache.get(sourceId);
214f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        if (entries == null) {
215f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            entries = new ArrayList<GroupIdCacheEntry>(1);
216f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            mGroupIdCache.put(sourceId, entries);
217f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
218f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
219f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        int count = entries.size();
220f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        for (int i = 0; i < count; i++) {
221f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            GroupIdCacheEntry entry = entries.get(i);
222f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (entry.accountName.equals(account.name) && entry.accountType.equals(account.type)) {
223f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                return entry.groupId;
224f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
225f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
226f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
227f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        GroupIdCacheEntry entry = new GroupIdCacheEntry();
228f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        entry.accountName = account.name;
229f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        entry.accountType = account.type;
230f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        entry.sourceId = sourceId;
231f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        entries.add(0, entry);
232f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
233f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        // look up the group that contains this sourceId and has the same account name and type
234f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        // as the contact refered to by rawContactId
235f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        Cursor c = db.query(Tables.GROUPS, new String[]{RawContacts._ID},
236f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                Clauses.GROUP_HAS_ACCOUNT_AND_SOURCE_ID,
237f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                new String[]{sourceId, account.name, account.type}, null, null, null);
238f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        try {
239f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            if (c.moveToFirst()) {
240f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                entry.groupId = c.getLong(0);
241f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            } else {
242f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                ContentValues groupValues = new ContentValues();
243f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                groupValues.put(Groups.ACCOUNT_NAME, account.name);
244f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                groupValues.put(Groups.ACCOUNT_TYPE, account.type);
245f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                groupValues.put(Groups.SOURCE_ID, sourceId);
246f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                long groupId = db.insert(Tables.GROUPS, Groups.ACCOUNT_NAME, groupValues);
247f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                if (groupId < 0) {
248f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                    throw new IllegalStateException("unable to create a new group with "
249f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                            + "this sourceid: " + groupValues);
250f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                }
251f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov                entry.groupId = groupId;
252f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            }
253f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        } finally {
254f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov            c.close();
255f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        }
256f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov
257f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov        return entry.groupId;
258f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov    }
259f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov}
260