BaseContactsProvider2Test.java revision 7d82ae92714f2132e3a0971d844ae8cdf10d76e7
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.providers.contacts;
18
19import static com.android.providers.contacts.ContactsActor.PACKAGE_GREY;
20
21import com.google.android.collect.Sets;
22
23import android.accounts.Account;
24import android.content.ContentProvider;
25import android.content.ContentResolver;
26import android.content.ContentUris;
27import android.content.ContentValues;
28import android.content.Context;
29import android.content.Entity;
30import android.content.res.Resources;
31import android.database.Cursor;
32import android.net.Uri;
33import android.provider.ContactsContract;
34import android.provider.ContactsContract.AggregationExceptions;
35import android.provider.ContactsContract.CommonDataKinds.Email;
36import android.provider.ContactsContract.CommonDataKinds.Event;
37import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
38import android.provider.ContactsContract.CommonDataKinds.Im;
39import android.provider.ContactsContract.CommonDataKinds.Nickname;
40import android.provider.ContactsContract.CommonDataKinds.Note;
41import android.provider.ContactsContract.CommonDataKinds.Organization;
42import android.provider.ContactsContract.CommonDataKinds.Phone;
43import android.provider.ContactsContract.CommonDataKinds.Photo;
44import android.provider.ContactsContract.CommonDataKinds.StructuredName;
45import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
46import android.provider.ContactsContract.Contacts;
47import android.provider.ContactsContract.Data;
48import android.provider.ContactsContract.Groups;
49import android.provider.ContactsContract.RawContacts;
50import android.provider.ContactsContract.Settings;
51import android.provider.ContactsContract.StatusUpdates;
52import android.test.AndroidTestCase;
53import android.test.MoreAsserts;
54import android.test.mock.MockContentResolver;
55import android.util.Log;
56
57import java.io.ByteArrayOutputStream;
58import java.io.IOException;
59import java.io.InputStream;
60import java.util.ArrayList;
61import java.util.Arrays;
62import java.util.Comparator;
63import java.util.Iterator;
64import java.util.Map;
65import java.util.Map.Entry;
66import java.util.Set;
67
68/**
69 * A common superclass for {@link ContactsProvider2}-related tests.
70 */
71public abstract class BaseContactsProvider2Test extends AndroidTestCase {
72
73    protected static final String PACKAGE = "ContactsProvider2Test";
74    public static final String READ_ONLY_ACCOUNT_TYPE =
75            SynchronousContactsProvider2.READ_ONLY_ACCOUNT_TYPE;
76
77    protected ContactsActor mActor;
78    protected MockContentResolver mResolver;
79    protected Account mAccount = new Account("account1", "account type1");
80    protected Account mAccountTwo = new Account("account2", "account type2");
81
82    private byte[] mTestPhoto;
83
84    protected final static Long NO_LONG = new Long(0);
85    protected final static String NO_STRING = new String("");
86    protected final static Account NO_ACCOUNT = new Account("a", "b");
87
88    protected Class<? extends ContentProvider> getProviderClass() {
89        return SynchronousContactsProvider2.class;
90    }
91
92    protected String getAuthority() {
93        return ContactsContract.AUTHORITY;
94    }
95
96    @Override
97    protected void setUp() throws Exception {
98        super.setUp();
99
100        mActor = new ContactsActor(getContext(), PACKAGE_GREY, getProviderClass(), getAuthority());
101        mResolver = mActor.resolver;
102        if (mActor.provider instanceof SynchronousContactsProvider2) {
103            getContactsProvider().wipeData();
104        }
105    }
106
107    @Override
108    protected void tearDown() throws Exception {
109        if (mActor.provider instanceof SynchronousContactsProvider2) {
110            getContactsProvider().getDatabaseHelper(mActor.context).close();
111        }
112        super.tearDown();
113    }
114
115    public SynchronousContactsProvider2 getContactsProvider() {
116        return (SynchronousContactsProvider2) mActor.provider;
117    }
118
119    public Context getMockContext() {
120        return mActor.context;
121    }
122
123    public void addAuthority(String authority) {
124        mActor.addAuthority(authority);
125    }
126
127    public ContentProvider addProvider(Class<? extends ContentProvider> providerClass,
128            String authority) throws Exception {
129        return mActor.addProvider(providerClass, authority);
130    }
131
132    public ContentProvider getProvider() {
133        return mActor.provider;
134    }
135
136    protected Uri maybeAddAccountQueryParameters(Uri uri, Account account) {
137        if (account == null) {
138            return uri;
139        }
140        return uri.buildUpon()
141                .appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
142                .appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type)
143                .build();
144    }
145
146    protected long createRawContact() {
147        return createRawContact(null);
148    }
149
150    protected long createRawContactWithName() {
151        return createRawContactWithName(null);
152    }
153
154    protected long createRawContactWithName(Account account) {
155        return createRawContactWithName("John", "Doe", account);
156    }
157
158    protected long createRawContactWithName(String firstName, String lastName) {
159        return createRawContactWithName(firstName, lastName, null);
160    }
161
162    protected long createRawContactWithName(String firstName, String lastName, Account account) {
163        long rawContactId = createRawContact(account);
164        insertStructuredName(rawContactId, firstName, lastName);
165        return rawContactId;
166    }
167
168    protected Uri setCallerIsSyncAdapter(Uri uri, Account account) {
169        if (account == null) {
170            return uri;
171        }
172        final Uri.Builder builder = uri.buildUpon();
173        builder.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, account.name);
174        builder.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type);
175        builder.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true");
176        return builder.build();
177    }
178
179    protected long createRawContact(Account account, String... extras) {
180        ContentValues values = new ContentValues();
181        extrasVarArgsToValues(values, extras);
182        final Uri uri = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account);
183        Uri contactUri = mResolver.insert(uri, values);
184        return ContentUris.parseId(contactUri);
185    }
186
187    protected int updateItem(Uri uri, long id, String... extras) {
188        Uri itemUri = ContentUris.withAppendedId(uri, id);
189        return updateItem(itemUri, extras);
190    }
191
192    protected int updateItem(Uri uri, String... extras) {
193        ContentValues values = new ContentValues();
194        extrasVarArgsToValues(values, extras);
195        return mResolver.update(uri, values, null, null);
196    }
197
198    private static void extrasVarArgsToValues(ContentValues values, String... extras) {
199        for (int i = 0; i < extras.length; ) {
200            values.put(extras[i], extras[i + 1]);
201            i += 2;
202        }
203    }
204
205    protected long createGroup(Account account, String sourceId, String title) {
206        return createGroup(account, sourceId, title, 1, false, false);
207    }
208
209    protected long createGroup(Account account, String sourceId, String title, int visible) {
210        return createGroup(account, sourceId, title, visible, false, false);
211    }
212
213    protected long createAutoAddGroup(Account account) {
214        return createGroup(account, "auto", "auto",
215                0 /* visible */,  true /* auto-add */, false /* fav */);
216    }
217
218    protected long createGroup(Account account, String sourceId, String title,
219            int visible, boolean autoAdd, boolean favorite) {
220        ContentValues values = new ContentValues();
221        values.put(Groups.SOURCE_ID, sourceId);
222        values.put(Groups.TITLE, title);
223        values.put(Groups.GROUP_VISIBLE, visible);
224        values.put(Groups.AUTO_ADD, autoAdd ? 1 : 0);
225        values.put(Groups.FAVORITES, favorite ? 1 : 0);
226        final Uri uri = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account);
227        return ContentUris.parseId(mResolver.insert(uri, values));
228    }
229
230    protected void createSettings(Account account, String shouldSync, String ungroupedVisible) {
231        ContentValues values = new ContentValues();
232        values.put(Settings.ACCOUNT_NAME, account.name);
233        values.put(Settings.ACCOUNT_TYPE, account.type);
234        values.put(Settings.SHOULD_SYNC, shouldSync);
235        values.put(Settings.UNGROUPED_VISIBLE, ungroupedVisible);
236        mResolver.insert(Settings.CONTENT_URI, values);
237    }
238
239    protected Uri insertStructuredName(long rawContactId, String givenName, String familyName) {
240        ContentValues values = new ContentValues();
241        StringBuilder sb = new StringBuilder();
242        if (givenName != null) {
243            sb.append(givenName);
244        }
245        if (givenName != null && familyName != null) {
246            sb.append(" ");
247        }
248        if (familyName != null) {
249            sb.append(familyName);
250        }
251        values.put(StructuredName.DISPLAY_NAME, sb.toString());
252        values.put(StructuredName.GIVEN_NAME, givenName);
253        values.put(StructuredName.FAMILY_NAME, familyName);
254
255        return insertStructuredName(rawContactId, values);
256    }
257
258    protected Uri insertStructuredName(long rawContactId, ContentValues values) {
259        values.put(Data.RAW_CONTACT_ID, rawContactId);
260        values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
261        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
262        return resultUri;
263    }
264
265    protected Uri insertOrganization(long rawContactId, ContentValues values) {
266        return insertOrganization(rawContactId, values, false);
267    }
268
269    protected Uri insertOrganization(long rawContactId, ContentValues values, boolean primary) {
270        values.put(Data.RAW_CONTACT_ID, rawContactId);
271        values.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
272        values.put(Organization.TYPE, Organization.TYPE_WORK);
273        if (primary) {
274            values.put(Data.IS_PRIMARY, 1);
275        }
276
277        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
278        return resultUri;
279    }
280
281    protected Uri insertPhoneNumber(long rawContactId, String phoneNumber) {
282        return insertPhoneNumber(rawContactId, phoneNumber, false);
283    }
284
285    protected Uri insertPhoneNumber(long rawContactId, String phoneNumber, boolean primary) {
286        ContentValues values = new ContentValues();
287        values.put(Data.RAW_CONTACT_ID, rawContactId);
288        values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
289        values.put(Phone.NUMBER, phoneNumber);
290        values.put(Phone.TYPE, Phone.TYPE_HOME);
291        if (primary) {
292            values.put(Data.IS_PRIMARY, 1);
293        }
294
295        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
296        return resultUri;
297    }
298
299    protected Uri insertEmail(long rawContactId, String email) {
300        return insertEmail(rawContactId, email, false);
301    }
302
303    protected Uri insertEmail(long rawContactId, String email, boolean primary) {
304        return insertEmail(rawContactId, email, primary, Email.TYPE_HOME, null);
305    }
306
307    protected Uri insertEmail(long rawContactId, String email, boolean primary, int type,
308            String label) {
309        ContentValues values = new ContentValues();
310        values.put(Data.RAW_CONTACT_ID, rawContactId);
311        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
312        values.put(Email.DATA, email);
313        values.put(Email.TYPE, type);
314        values.put(Email.LABEL, label);
315        if (primary) {
316            values.put(Data.IS_PRIMARY, 1);
317        }
318
319        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
320        return resultUri;
321    }
322
323    protected Uri insertNickname(long rawContactId, String nickname) {
324        ContentValues values = new ContentValues();
325        values.put(Data.RAW_CONTACT_ID, rawContactId);
326        values.put(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE);
327        values.put(Nickname.NAME, nickname);
328        values.put(Nickname.TYPE, Nickname.TYPE_OTHER_NAME);
329
330        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
331        return resultUri;
332    }
333
334    protected Uri insertPostalAddress(long rawContactId, String formattedAddress) {
335        ContentValues values = new ContentValues();
336        values.put(Data.RAW_CONTACT_ID, rawContactId);
337        values.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
338        values.put(StructuredPostal.FORMATTED_ADDRESS, formattedAddress);
339
340        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
341        return resultUri;
342    }
343
344    protected Uri insertPostalAddress(long rawContactId, ContentValues values) {
345        values.put(Data.RAW_CONTACT_ID, rawContactId);
346        values.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
347        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
348        return resultUri;
349    }
350
351    protected Uri insertPhoto(long rawContactId) {
352        ContentValues values = new ContentValues();
353        values.put(Data.RAW_CONTACT_ID, rawContactId);
354        values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
355        values.put(Photo.PHOTO, loadTestPhoto());
356        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
357        return resultUri;
358    }
359
360    protected Uri insertGroupMembership(long rawContactId, String sourceId) {
361        ContentValues values = new ContentValues();
362        values.put(Data.RAW_CONTACT_ID, rawContactId);
363        values.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
364        values.put(GroupMembership.GROUP_SOURCE_ID, sourceId);
365        return mResolver.insert(Data.CONTENT_URI, values);
366    }
367
368    protected Uri insertGroupMembership(long rawContactId, Long groupId) {
369        ContentValues values = new ContentValues();
370        values.put(Data.RAW_CONTACT_ID, rawContactId);
371        values.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
372        values.put(GroupMembership.GROUP_ROW_ID, groupId);
373        return mResolver.insert(Data.CONTENT_URI, values);
374    }
375
376    public void removeGroupMemberships(long rawContactId) {
377        mResolver.delete(Data.CONTENT_URI,
378                Data.MIMETYPE + "=? AND " + GroupMembership.RAW_CONTACT_ID + "=?",
379                new String[] { GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(rawContactId) });
380    }
381
382    protected Uri insertStatusUpdate(int protocol, String customProtocol, String handle,
383            int presence, String status, int chatMode) {
384        return insertStatusUpdate(protocol, customProtocol, handle, presence, status, 0, chatMode);
385    }
386
387    protected Uri insertStatusUpdate(int protocol, String customProtocol, String handle,
388            int presence, String status, long timestamp, int chatMode) {
389        ContentValues values = new ContentValues();
390        values.put(StatusUpdates.PROTOCOL, protocol);
391        values.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol);
392        values.put(StatusUpdates.IM_HANDLE, handle);
393        return insertStatusUpdate(values, presence, status, timestamp, chatMode);
394    }
395
396    protected Uri insertStatusUpdate(
397            long dataId, int presence, String status, long timestamp, int chatMode) {
398        ContentValues values = new ContentValues();
399        values.put(StatusUpdates.DATA_ID, dataId);
400        return insertStatusUpdate(values, presence, status, timestamp, chatMode);
401    }
402
403    private Uri insertStatusUpdate(
404            ContentValues values, int presence, String status, long timestamp, int chatMode) {
405        if (presence != 0) {
406            values.put(StatusUpdates.PRESENCE, presence);
407            values.put(StatusUpdates.CHAT_CAPABILITY, chatMode);
408        }
409        if (status != null) {
410            values.put(StatusUpdates.STATUS, status);
411        }
412        if (timestamp != 0) {
413            values.put(StatusUpdates.STATUS_TIMESTAMP, timestamp);
414        }
415
416        Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values);
417        return resultUri;
418    }
419
420    protected Uri insertImHandle(long rawContactId, int protocol, String customProtocol,
421            String handle) {
422        ContentValues values = new ContentValues();
423        values.put(Data.RAW_CONTACT_ID, rawContactId);
424        values.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
425        values.put(Im.PROTOCOL, protocol);
426        values.put(Im.CUSTOM_PROTOCOL, customProtocol);
427        values.put(Im.DATA, handle);
428        values.put(Im.TYPE, Im.TYPE_HOME);
429
430        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
431        return resultUri;
432    }
433
434    protected Uri insertEvent(long rawContactId, int type, String date) {
435        ContentValues values = new ContentValues();
436        values.put(Data.RAW_CONTACT_ID, rawContactId);
437        values.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
438        values.put(Event.TYPE, type);
439        values.put(Event.START_DATE, date);
440        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
441        return resultUri;
442    }
443
444    protected Uri insertNote(long rawContactId, String note) {
445        ContentValues values = new ContentValues();
446        values.put(Data.RAW_CONTACT_ID, rawContactId);
447        values.put(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
448        values.put(Note.NOTE, note);
449        Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
450        return resultUri;
451    }
452
453    protected void setContactAccount(long rawContactId, String accountType, String accountName) {
454        ContentValues values = new ContentValues();
455        values.put(RawContacts.ACCOUNT_TYPE, accountType);
456        values.put(RawContacts.ACCOUNT_NAME, accountName);
457
458        mResolver.update(ContentUris.withAppendedId(
459                RawContacts.CONTENT_URI, rawContactId), values, null, null);
460    }
461
462    protected void setAggregationException(int type, long rawContactId1, long rawContactId2) {
463        ContentValues values = new ContentValues();
464        values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
465        values.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
466        values.put(AggregationExceptions.TYPE, type);
467        assertEquals(1, mResolver.update(AggregationExceptions.CONTENT_URI, values, null, null));
468    }
469
470    protected Cursor queryRawContact(long rawContactId) {
471        return mResolver.query(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
472                null, null, null, null);
473    }
474
475    protected Cursor queryContact(long contactId) {
476        return mResolver.query(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
477                null, null, null, null);
478    }
479
480    protected Cursor queryContact(long contactId, String[] projection) {
481        return mResolver.query(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
482                projection, null, null, null);
483    }
484
485    protected Uri getContactUriForRawContact(long rawContactId) {
486        return ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(rawContactId));
487    }
488
489    protected long queryContactId(long rawContactId) {
490        Cursor c = queryRawContact(rawContactId);
491        assertTrue(c.moveToFirst());
492        long contactId = c.getLong(c.getColumnIndex(RawContacts.CONTACT_ID));
493        c.close();
494        return contactId;
495    }
496
497    protected long queryPhotoId(long contactId) {
498        Cursor c = queryContact(contactId);
499        assertTrue(c.moveToFirst());
500        long photoId = c.getInt(c.getColumnIndex(Contacts.PHOTO_ID));
501        c.close();
502        return photoId;
503    }
504
505    protected boolean queryRawContactIsStarred(long rawContactId) {
506        Cursor c = queryRawContact(rawContactId);
507        try {
508            assertTrue(c.moveToFirst());
509            return c.getLong(c.getColumnIndex(RawContacts.STARRED)) != 0;
510        } finally {
511            c.close();
512        }
513    }
514
515    protected String queryDisplayName(long contactId) {
516        Cursor c = queryContact(contactId);
517        assertTrue(c.moveToFirst());
518        String displayName = c.getString(c.getColumnIndex(Contacts.DISPLAY_NAME));
519        c.close();
520        return displayName;
521    }
522
523    protected String queryLookupKey(long contactId) {
524        Cursor c = queryContact(contactId);
525        assertTrue(c.moveToFirst());
526        String lookupKey = c.getString(c.getColumnIndex(Contacts.LOOKUP_KEY));
527        c.close();
528        return lookupKey;
529    }
530
531    protected void assertAggregated(long rawContactId1, long rawContactId2) {
532        long contactId1 = queryContactId(rawContactId1);
533        long contactId2 = queryContactId(rawContactId2);
534        assertTrue(contactId1 == contactId2);
535    }
536
537    protected void assertAggregated(long rawContactId1, long rawContactId2,
538            String expectedDisplayName) {
539        long contactId1 = queryContactId(rawContactId1);
540        long contactId2 = queryContactId(rawContactId2);
541        assertTrue(contactId1 == contactId2);
542
543        String displayName = queryDisplayName(contactId1);
544        assertEquals(expectedDisplayName, displayName);
545    }
546
547    protected void assertNotAggregated(long rawContactId1, long rawContactId2) {
548        long contactId1 = queryContactId(rawContactId1);
549        long contactId2 = queryContactId(rawContactId2);
550        assertTrue(contactId1 != contactId2);
551    }
552
553    protected void assertStructuredName(long rawContactId, String prefix, String givenName,
554            String middleName, String familyName, String suffix) {
555        Uri uri = Uri.withAppendedPath(
556                ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
557                RawContacts.Data.CONTENT_DIRECTORY);
558
559        final String[] projection = new String[] {
560                StructuredName.PREFIX, StructuredName.GIVEN_NAME, StructuredName.MIDDLE_NAME,
561                StructuredName.FAMILY_NAME, StructuredName.SUFFIX
562        };
563
564        Cursor c = mResolver.query(uri, projection, Data.MIMETYPE + "='"
565                + StructuredName.CONTENT_ITEM_TYPE + "'", null, null);
566
567        assertTrue(c.moveToFirst());
568        assertEquals(prefix, c.getString(0));
569        assertEquals(givenName, c.getString(1));
570        assertEquals(middleName, c.getString(2));
571        assertEquals(familyName, c.getString(3));
572        assertEquals(suffix, c.getString(4));
573        c.close();
574    }
575
576    protected long assertSingleGroup(Long rowId, Account account, String sourceId, String title) {
577        Cursor c = mResolver.query(Groups.CONTENT_URI, null, null, null, null);
578        try {
579            assertTrue(c.moveToNext());
580            long actualRowId = assertGroup(c, rowId, account, sourceId, title);
581            assertFalse(c.moveToNext());
582            return actualRowId;
583        } finally {
584            c.close();
585        }
586    }
587
588    protected long assertSingleGroupMembership(Long rowId, Long rawContactId, Long groupRowId,
589            String sourceId) {
590        Cursor c = mResolver.query(ContactsContract.Data.CONTENT_URI, null, null, null, null);
591        try {
592            assertTrue(c.moveToNext());
593            long actualRowId = assertGroupMembership(c, rowId, rawContactId, groupRowId, sourceId);
594            assertFalse(c.moveToNext());
595            return actualRowId;
596        } finally {
597            c.close();
598        }
599    }
600
601    protected long assertGroupMembership(Cursor c, Long rowId, Long rawContactId, Long groupRowId,
602            String sourceId) {
603        assertNullOrEquals(c, rowId, Data._ID);
604        assertNullOrEquals(c, rawContactId, GroupMembership.RAW_CONTACT_ID);
605        assertNullOrEquals(c, groupRowId, GroupMembership.GROUP_ROW_ID);
606        assertNullOrEquals(c, sourceId, GroupMembership.GROUP_SOURCE_ID);
607        return c.getLong(c.getColumnIndexOrThrow("_id"));
608    }
609
610    protected long assertGroup(Cursor c, Long rowId, Account account, String sourceId, String title) {
611        assertNullOrEquals(c, rowId, Groups._ID);
612        assertNullOrEquals(c, account);
613        assertNullOrEquals(c, sourceId, Groups.SOURCE_ID);
614        assertNullOrEquals(c, title, Groups.TITLE);
615        return c.getLong(c.getColumnIndexOrThrow("_id"));
616    }
617
618    private void assertNullOrEquals(Cursor c, Account account) {
619        if (account == NO_ACCOUNT) {
620            return;
621        }
622        if (account == null) {
623            assertTrue(c.isNull(c.getColumnIndexOrThrow(Groups.ACCOUNT_NAME)));
624            assertTrue(c.isNull(c.getColumnIndexOrThrow(Groups.ACCOUNT_TYPE)));
625        } else {
626            assertEquals(account.name, c.getString(c.getColumnIndexOrThrow(Groups.ACCOUNT_NAME)));
627            assertEquals(account.type, c.getString(c.getColumnIndexOrThrow(Groups.ACCOUNT_TYPE)));
628        }
629    }
630
631    private void assertNullOrEquals(Cursor c, Long value, String columnName) {
632        if (value != NO_LONG) {
633            if (value == null) assertTrue(c.isNull(c.getColumnIndexOrThrow(columnName)));
634            else assertEquals((long) value, c.getLong(c.getColumnIndexOrThrow(columnName)));
635        }
636    }
637
638    private void assertNullOrEquals(Cursor c, String value, String columnName) {
639        if (value != NO_STRING) {
640            if (value == null) assertTrue(c.isNull(c.getColumnIndexOrThrow(columnName)));
641            else assertEquals(value, c.getString(c.getColumnIndexOrThrow(columnName)));
642        }
643    }
644
645    protected void assertDataRow(ContentValues actual, String expectedMimetype,
646            Object... expectedArguments) {
647        assertEquals(actual.toString(), expectedMimetype, actual.getAsString(Data.MIMETYPE));
648        for (int i = 0; i < expectedArguments.length; i += 2) {
649            String columnName = (String) expectedArguments[i];
650            Object expectedValue = expectedArguments[i + 1];
651            if (expectedValue instanceof Uri) {
652                expectedValue = ContentUris.parseId((Uri) expectedValue);
653            }
654            if (expectedValue == null) {
655                assertNull(actual.toString(), actual.get(columnName));
656            }
657            if (expectedValue instanceof Long) {
658                assertEquals("mismatch at " + columnName + " from " + actual.toString(),
659                        expectedValue, actual.getAsLong(columnName));
660            } else if (expectedValue instanceof Integer) {
661                assertEquals("mismatch at " + columnName + " from " + actual.toString(),
662                        expectedValue, actual.getAsInteger(columnName));
663            } else if (expectedValue instanceof String) {
664                assertEquals("mismatch at " + columnName + " from " + actual.toString(),
665                        expectedValue, actual.getAsString(columnName));
666            } else {
667                assertEquals("mismatch at " + columnName + " from " + actual.toString(),
668                        expectedValue, actual.get(columnName));
669            }
670        }
671    }
672
673    protected void assertNoRowsAndClose(Cursor c) {
674        try {
675            assertFalse(c.moveToNext());
676        } finally {
677            c.close();
678        }
679    }
680
681    protected static class IdComparator implements Comparator<ContentValues> {
682        public int compare(ContentValues o1, ContentValues o2) {
683            long id1 = o1.getAsLong(ContactsContract.Data._ID);
684            long id2 = o2.getAsLong(ContactsContract.Data._ID);
685            if (id1 == id2) return 0;
686            return (id1 < id2) ? -1 : 1;
687        }
688    }
689
690    protected ContentValues[] asSortedContentValuesArray(
691            ArrayList<Entity.NamedContentValues> subValues) {
692        ContentValues[] result = new ContentValues[subValues.size()];
693        int i = 0;
694        for (Entity.NamedContentValues subValue : subValues) {
695            result[i] = subValue.values;
696            i++;
697        }
698        Arrays.sort(result, new IdComparator());
699        return result;
700    }
701
702    protected void assertDirty(Uri uri, boolean state) {
703        Cursor c = mResolver.query(uri, new String[]{"dirty"}, null, null, null);
704        assertTrue(c.moveToNext());
705        assertEquals(state, c.getLong(0) != 0);
706        assertFalse(c.moveToNext());
707        c.close();
708    }
709
710    protected long getVersion(Uri uri) {
711        Cursor c = mResolver.query(uri, new String[]{"version"}, null, null, null);
712        assertTrue(c.moveToNext());
713        long version = c.getLong(0);
714        assertFalse(c.moveToNext());
715        c.close();
716        return version;
717    }
718
719    protected void clearDirty(Uri uri) {
720        ContentValues values = new ContentValues();
721        values.put("dirty", 0);
722        mResolver.update(uri, values, null, null);
723    }
724
725    protected void storeValue(Uri contentUri, long id, String column, String value) {
726        storeValue(ContentUris.withAppendedId(contentUri, id), column, value);
727    }
728
729    protected void storeValue(Uri contentUri, String column, String value) {
730        ContentValues values = new ContentValues();
731        values.put(column, value);
732
733        mResolver.update(contentUri, values, null, null);
734    }
735
736    protected void storeValue(Uri contentUri, long id, String column, long value) {
737        storeValue(ContentUris.withAppendedId(contentUri, id), column, value);
738    }
739
740    protected void storeValue(Uri contentUri, String column, long value) {
741        ContentValues values = new ContentValues();
742        values.put(column, value);
743
744        mResolver.update(contentUri, values, null, null);
745    }
746
747    protected void assertStoredValue(Uri contentUri, long id, String column, Object expectedValue) {
748        assertStoredValue(ContentUris.withAppendedId(contentUri, id), column, expectedValue);
749    }
750
751    protected void assertStoredValue(Uri rowUri, String column, Object expectedValue) {
752        String value = getStoredValue(rowUri, column);
753        if (expectedValue == null) {
754            assertNull("Column value " + column, value);
755        } else {
756            assertEquals("Column value " + column, String.valueOf(expectedValue), value);
757        }
758    }
759
760    protected void assertStoredValue(Uri rowUri, String selection, String[] selectionArgs,
761            String column, Object expectedValue) {
762        String value = getStoredValue(rowUri, selection, selectionArgs, column);
763        if (expectedValue == null) {
764            assertNull("Column value " + column, value);
765        } else {
766            assertEquals("Column value " + column, String.valueOf(expectedValue), value);
767        }
768    }
769
770    protected String getStoredValue(Uri rowUri, String column) {
771        return getStoredValue(rowUri, null, null, column);
772    }
773
774    protected String getStoredValue(Uri uri, String selection, String[] selectionArgs,
775            String column) {
776        String value = null;
777        Cursor c = mResolver.query(uri, new String[] { column }, selection, selectionArgs, null);
778        try {
779            assertEquals("Record count", 1, c.getCount());
780
781            if (c.moveToFirst()) {
782                value = c.getString(c.getColumnIndex(column));
783            }
784        } finally {
785            c.close();
786        }
787        return value;
788    }
789
790    protected void assertStoredValues(Uri rowUri, ContentValues expectedValues) {
791        assertStoredValues(rowUri, null, null, expectedValues);
792    }
793
794    protected void assertStoredValues(Uri rowUri, ContentValues[] expectedValues) {
795        assertStoredValues(rowUri, null, null, expectedValues);
796    }
797
798    protected void assertStoredValues(Uri rowUri, String selection, String[] selectionArgs,
799            ContentValues expectedValues) {
800        Cursor c = mResolver.query(rowUri, null, selection, selectionArgs, null);
801        try {
802            assertEquals("Record count", 1, c.getCount());
803            c.moveToFirst();
804            assertCursorValues(c, expectedValues);
805        } finally {
806            c.close();
807        }
808    }
809
810    protected void assertStoredValuesWithProjection(Uri rowUri, ContentValues expectedValues) {
811        Cursor c = mResolver.query(rowUri, buildProjection(expectedValues), null, null, null);
812        try {
813            assertEquals("Record count", 1, c.getCount());
814            c.moveToFirst();
815            assertCursorValues(c, expectedValues);
816        } finally {
817            c.close();
818        }
819    }
820
821    protected void assertStoredValues(
822            Uri rowUri, String selection, String[] selectionArgs, ContentValues[] expectedValues) {
823        Cursor c = mResolver.query(rowUri, null, selection, selectionArgs, null);
824        try {
825            assertEquals("Record count", expectedValues.length, c.getCount());
826            assertCursorValues(c, expectedValues);
827        } finally {
828            c.close();
829        }
830    }
831
832    protected void assertStoredValuesOrderly(Uri rowUri, ContentValues[] expectedValues) {
833        assertStoredValuesOrderly(rowUri, null, null, expectedValues);
834    }
835
836    protected void assertStoredValuesOrderly(Uri rowUri, String selection,
837            String[] selectionArgs, ContentValues[] expectedValues) {
838        Cursor c = mResolver.query(rowUri, null, selection, selectionArgs, null);
839        try {
840            assertEquals("Record count", expectedValues.length, c.getCount());
841            assertCursorValuesOrderly(c, expectedValues);
842        } finally {
843            c.close();
844        }
845    }
846
847    /**
848     * Constructs a selection (where clause) out of all supplied values, uses it
849     * to query the provider and verifies that a single row is returned and it
850     * has the same values as requested.
851     */
852    protected void assertSelection(Uri uri, ContentValues values, String idColumn, long id) {
853        assertSelection(uri, values, idColumn, id, null);
854    }
855
856    public void assertSelectionWithProjection(Uri uri, ContentValues values, String idColumn,
857            long id) {
858        assertSelection(uri, values, idColumn, id, buildProjection(values));
859    }
860
861    private void assertSelection(Uri uri, ContentValues values, String idColumn, long id,
862            String[] projection) {
863        StringBuilder sb = new StringBuilder();
864        ArrayList<String> selectionArgs = new ArrayList<String>(values.size());
865        if (idColumn != null) {
866            sb.append(idColumn).append("=").append(id);
867        }
868        Set<Map.Entry<String, Object>> entries = values.valueSet();
869        for (Map.Entry<String, Object> entry : entries) {
870            String column = entry.getKey();
871            Object value = entry.getValue();
872            if (sb.length() != 0) {
873                sb.append(" AND ");
874            }
875            sb.append(column);
876            if (value == null) {
877                sb.append(" IS NULL");
878            } else {
879                sb.append("=?");
880                selectionArgs.add(String.valueOf(value));
881            }
882        }
883
884        Cursor c = mResolver.query(uri, projection, sb.toString(), selectionArgs.toArray(new String[0]),
885                null);
886        try {
887            assertEquals("Record count", 1, c.getCount());
888            c.moveToFirst();
889            assertCursorValues(c, values);
890        } finally {
891            c.close();
892        }
893    }
894
895    protected void assertCursorValue(Cursor cursor, String column, Object expectedValue) {
896        String actualValue = cursor.getString(cursor.getColumnIndex(column));
897        assertEquals("Column " + column, String.valueOf(expectedValue),
898                String.valueOf(actualValue));
899    }
900
901    protected void assertCursorValues(Cursor cursor, ContentValues expectedValues) {
902        StringBuilder message = new StringBuilder();
903        boolean result = equalsWithExpectedValues(cursor, expectedValues, message);
904        assertTrue(message.toString(), result);
905    }
906
907    protected void assertCursorValues(Cursor cursor, ContentValues[] expectedValues) {
908        StringBuilder message = new StringBuilder();
909        for (ContentValues v : expectedValues) {
910            boolean found = false;
911            cursor.moveToPosition(-1);
912            while (cursor.moveToNext()) {
913                found = equalsWithExpectedValues(cursor, v, message);
914                if (found) {
915                    break;
916                }
917            }
918            assertTrue("Expected values can not be found " + v + message.toString(), found);
919        }
920    }
921
922    protected void assertCursorValuesOrderly(Cursor cursor, ContentValues[] expectedValues) {
923        StringBuilder message = new StringBuilder();
924        cursor.moveToPosition(-1);
925        for (ContentValues v : expectedValues) {
926            assertTrue(cursor.moveToNext());
927            assertTrue("ContentValues didn't match " + v + message.toString(),
928                    equalsWithExpectedValues(cursor, v, message));
929        }
930    }
931
932    private boolean equalsWithExpectedValues(Cursor cursor, ContentValues expectedValues,
933            StringBuilder msgBuffer) {
934        Set<Map.Entry<String, Object>> entries = expectedValues.valueSet();
935        for (Map.Entry<String, Object> entry : entries) {
936            String column = entry.getKey();
937            int index = cursor.getColumnIndex(column);
938            if (index == -1) {
939                msgBuffer.append("No such column: ").append(column);
940                return false;
941            }
942            Object expectedValue = expectedValues.get(column);
943            String value;
944            if (expectedValue instanceof byte[]) {
945                expectedValue = Hex.encodeHex((byte[])expectedValue, false);
946                value = Hex.encodeHex(cursor.getBlob(index), false);
947            } else {
948                expectedValue = expectedValues.getAsString(column);
949                value = cursor.getString(index);
950            }
951            if (expectedValue != null && !expectedValue.equals(value) || value != null
952                    && !value.equals(expectedValue)) {
953                msgBuffer
954                        .append("Column value ")
955                        .append(column)
956                        .append(" expected <")
957                        .append(expectedValue)
958                        .append(">, but was <")
959                        .append(value)
960                        .append('>');
961                return false;
962            }
963        }
964        return true;
965    }
966
967    private String[] buildProjection(ContentValues values) {
968        String[] projection = new String[values.size()];
969        Iterator<Entry<String, Object>> iter = values.valueSet().iterator();
970        for (int i = 0; i < projection.length; i++) {
971            projection[i] = iter.next().getKey();
972        }
973        return projection;
974    }
975
976    protected int getCount(Uri uri, String selection, String[] selectionArgs) {
977        Cursor c = mResolver.query(uri, null, selection, selectionArgs, null);
978        try {
979            return c.getCount();
980        } finally {
981            c.close();
982        }
983    }
984
985    protected byte[] loadTestPhoto() {
986        if (mTestPhoto == null) {
987            final Resources resources = getContext().getResources();
988            InputStream is = resources
989                    .openRawResource(com.android.internal.R.drawable.ic_contact_picture);
990            ByteArrayOutputStream os = new ByteArrayOutputStream();
991            byte[] buffer = new byte[1000];
992            int count;
993            try {
994                while ((count = is.read(buffer)) != -1) {
995                    os.write(buffer, 0, count);
996                }
997            } catch (IOException e) {
998                throw new RuntimeException(e);
999            }
1000            mTestPhoto = os.toByteArray();
1001        }
1002        return mTestPhoto;
1003    }
1004
1005    public static void dump(ContentResolver resolver, boolean aggregatedOnly) {
1006        String[] projection = new String[] {
1007                Contacts._ID,
1008                Contacts.DISPLAY_NAME
1009        };
1010        String selection = null;
1011        if (aggregatedOnly) {
1012            selection = Contacts._ID
1013                    + " IN (SELECT contact_id" +
1014                    		" FROM raw_contacts GROUP BY contact_id HAVING count(*) > 1)";
1015        }
1016
1017        Cursor c = resolver.query(Contacts.CONTENT_URI, projection, selection, null,
1018                Contacts.DISPLAY_NAME);
1019        while(c.moveToNext()) {
1020            long contactId = c.getLong(0);
1021            Log.i("Contact   ", String.format("%5d %s", contactId, c.getString(1)));
1022            dumpRawContacts(resolver, contactId);
1023            Log.i("          ", ".");
1024        }
1025        c.close();
1026    }
1027
1028    private static void dumpRawContacts(ContentResolver resolver, long contactId) {
1029        String[] projection = new String[] {
1030                RawContacts._ID,
1031        };
1032        Cursor c = resolver.query(RawContacts.CONTENT_URI, projection, RawContacts.CONTACT_ID + "="
1033                + contactId, null, null);
1034        while(c.moveToNext()) {
1035            long rawContactId = c.getLong(0);
1036            Log.i("RawContact", String.format("      %-5d", rawContactId));
1037            dumpData(resolver, rawContactId);
1038        }
1039        c.close();
1040    }
1041
1042    private static void dumpData(ContentResolver resolver, long rawContactId) {
1043        String[] projection = new String[] {
1044                Data.MIMETYPE,
1045                Data.DATA1,
1046                Data.DATA2,
1047                Data.DATA3,
1048        };
1049        Cursor c = resolver.query(Data.CONTENT_URI, projection, Data.RAW_CONTACT_ID + "="
1050                + rawContactId, null, Data.MIMETYPE);
1051        while(c.moveToNext()) {
1052            String mimetype = c.getString(0);
1053            if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) {
1054                Log.i("Photo     ", "");
1055            } else {
1056                mimetype = mimetype.substring(mimetype.indexOf('/') + 1);
1057                Log.i("Data      ", String.format("            %-10s %s,%s,%s", mimetype,
1058                        c.getString(1), c.getString(2), c.getString(3)));
1059            }
1060        }
1061        c.close();
1062    }
1063
1064    protected void assertNetworkNotified(boolean expected) {
1065        assertEquals(expected, (getContactsProvider()).isNetworkNotified());
1066    }
1067
1068    protected void assertProjection(Uri uri, String[] expectedProjection) {
1069        Cursor cursor = mResolver.query(uri, null, "0", null, null);
1070        String[] actualProjection = cursor.getColumnNames();
1071        MoreAsserts.assertEquals("Incorrect projection for URI: " + uri,
1072                Sets.newHashSet(expectedProjection), Sets.newHashSet(actualProjection));
1073        cursor.close();
1074    }
1075
1076    /**
1077     * A contact in the database, and the attributes used to create it.  Construct using
1078     * {@link GoldenContactBuilder#build()}.
1079     */
1080    public final class GoldenContact {
1081
1082        private final long rawContactId;
1083
1084        private final long contactId;
1085
1086        private final String givenName;
1087
1088        private final String familyName;
1089
1090        private final String nickname;
1091
1092        private final byte[] photo;
1093
1094        private final String company;
1095
1096        private final String title;
1097
1098        private final String phone;
1099
1100        private final String email;
1101
1102        private GoldenContact(GoldenContactBuilder builder, long rawContactId, long contactId) {
1103
1104            this.rawContactId = rawContactId;
1105            this.contactId = contactId;
1106            givenName = builder.givenName;
1107            familyName = builder.familyName;
1108            nickname = builder.nickname;
1109            photo = builder.photo;
1110            company = builder.company;
1111            title = builder.title;
1112            phone = builder.phone;
1113            email = builder.email;
1114        }
1115
1116        public void delete() {
1117            Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
1118            mResolver.delete(rawContactUri, null, null);
1119        }
1120
1121        /**
1122         * Returns the index of the contact in table "raw_contacts"
1123         */
1124        public long getRawContactId() {
1125            return rawContactId;
1126        }
1127
1128        /**
1129         * Returns the index of the contact in table "contacts"
1130         */
1131        public long getContactId() {
1132            return contactId;
1133        }
1134
1135        /**
1136         * Returns the lookup key for the contact.
1137         */
1138        public String getLookupKey() {
1139            return queryLookupKey(contactId);
1140        }
1141
1142        /**
1143         * Returns the contact's given name.
1144         */
1145        public String getGivenName() {
1146            return givenName;
1147        }
1148
1149        /**
1150         * Returns the contact's family name.
1151         */
1152        public String getFamilyName() {
1153            return familyName;
1154        }
1155
1156        /**
1157         * Returns the contact's nickname.
1158         */
1159        public String getNickname() {
1160            return nickname;
1161        }
1162
1163        /**
1164         * Return's the contact's photo
1165         */
1166        public byte[] getPhoto() {
1167            return photo;
1168        }
1169
1170        /**
1171         * Return's the company at which the contact works.
1172         */
1173        public String getCompany() {
1174            return company;
1175        }
1176
1177        /**
1178         * Returns the contact's job title.
1179         */
1180        public String getTitle() {
1181            return title;
1182        }
1183
1184        /**
1185         * Returns the contact's phone number
1186         */
1187        public String getPhone() {
1188            return phone;
1189        }
1190
1191        /**
1192         * Returns the contact's email address
1193         */
1194        public String getEmail() {
1195            return email;
1196        }
1197     }
1198
1199    /**
1200     * Builds {@link GoldenContact} objects.  Unspecified boolean objects default to false.
1201     * Unspecified String objects default to null.
1202     */
1203    public final class GoldenContactBuilder {
1204
1205        private String givenName;
1206
1207        private String familyName;
1208
1209        private String nickname;
1210
1211        private byte[] photo;
1212
1213        private String company;
1214
1215        private String title;
1216
1217        private String phone;
1218
1219        private String email;
1220
1221        /**
1222         * The contact's given and family names.
1223         *
1224         * TODO(dplotnikov): inline, or should we require them to set both names if they set either?
1225         */
1226        public GoldenContactBuilder name(String givenName, String familyName) {
1227            return givenName(givenName).familyName(familyName);
1228        }
1229
1230        /**
1231         * The contact's given name.
1232         */
1233        public GoldenContactBuilder givenName(String value) {
1234            givenName = value;
1235            return this;
1236        }
1237
1238        /**
1239         * The contact's family name.
1240         */
1241        public GoldenContactBuilder familyName(String value) {
1242            familyName = value;
1243            return this;
1244        }
1245
1246        /**
1247         * The contact's nickname.
1248         */
1249        public GoldenContactBuilder nickname(String value) {
1250            nickname = value;
1251            return this;
1252        }
1253
1254        /**
1255         * The contact's photo.
1256         */
1257        public GoldenContactBuilder photo(byte[] value) {
1258            photo = value;
1259            return this;
1260        }
1261
1262        /**
1263         * The company at which the contact works.
1264         */
1265        public GoldenContactBuilder company(String value) {
1266            company = value;
1267            return this;
1268        }
1269
1270        /**
1271         * The contact's job title.
1272         */
1273        public GoldenContactBuilder title(String value) {
1274            title = value;
1275            return this;
1276        }
1277
1278        /**
1279         * The contact's phone number.
1280         */
1281        public GoldenContactBuilder phone(String value) {
1282            phone = value;
1283            return this;
1284        }
1285
1286        /**
1287         * The contact's email address; also sets their IM status to {@link StatusUpdates#OFFLINE}
1288         * with a presence of "Coding for Android".
1289         */
1290        public GoldenContactBuilder email(String value) {
1291            email = value;
1292            return this;
1293        }
1294
1295        /**
1296         * Builds the {@link GoldenContact} specified by this builder.
1297         */
1298        public GoldenContact build() {
1299
1300            final long groupId = createGroup(mAccount, "gsid1", "title1");
1301
1302            long rawContactId = createRawContact();
1303            insertGroupMembership(rawContactId, groupId);
1304
1305            if (givenName != null || familyName != null) {
1306                insertStructuredName(rawContactId, givenName, familyName);
1307            }
1308            if (nickname != null) {
1309                insertNickname(rawContactId, nickname);
1310            }
1311            if (photo != null) {
1312                insertPhoto(rawContactId);
1313            }
1314            if (company != null || title != null) {
1315                insertOrganization(rawContactId);
1316            }
1317            if (email != null) {
1318                insertEmail(rawContactId);
1319            }
1320            if (phone != null) {
1321                insertPhone(rawContactId);
1322            }
1323
1324            long contactId = queryContactId(rawContactId);
1325
1326            return new GoldenContact(this, rawContactId, contactId);
1327        }
1328
1329        private void insertPhoto(long rawContactId) {
1330            ContentValues values = new ContentValues();
1331            values.put(Data.RAW_CONTACT_ID, rawContactId);
1332            values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
1333            values.put(Photo.PHOTO, photo);
1334            mResolver.insert(Data.CONTENT_URI, values);
1335        }
1336
1337        private void insertOrganization(long rawContactId) {
1338
1339            ContentValues values = new ContentValues();
1340            values.put(Data.RAW_CONTACT_ID, rawContactId);
1341            values.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
1342            values.put(Organization.TYPE, Organization.TYPE_WORK);
1343            if (company != null) {
1344                values.put(Organization.COMPANY, company);
1345            }
1346            if (title != null) {
1347                values.put(Organization.TITLE, title);
1348            }
1349            mResolver.insert(Data.CONTENT_URI, values);
1350        }
1351
1352        private void insertEmail(long rawContactId) {
1353
1354            ContentValues values = new ContentValues();
1355            values.put(Data.RAW_CONTACT_ID, rawContactId);
1356            values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
1357            values.put(Email.TYPE, Email.TYPE_WORK);
1358            values.put(Email.DATA, "foo@acme.com");
1359            mResolver.insert(Data.CONTENT_URI, values);
1360
1361            int protocol = Im.PROTOCOL_GOOGLE_TALK;
1362
1363            values.clear();
1364            values.put(StatusUpdates.PROTOCOL, protocol);
1365            values.put(StatusUpdates.IM_HANDLE, email);
1366            values.put(StatusUpdates.IM_ACCOUNT, "foo");
1367            values.put(StatusUpdates.PRESENCE_STATUS, StatusUpdates.OFFLINE);
1368            values.put(StatusUpdates.CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA);
1369            values.put(StatusUpdates.PRESENCE_CUSTOM_STATUS, "Coding for Android");
1370            mResolver.insert(StatusUpdates.CONTENT_URI, values);
1371        }
1372
1373        private void insertPhone(long rawContactId) {
1374            ContentValues values = new ContentValues();
1375            values.put(Data.RAW_CONTACT_ID, rawContactId);
1376            values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
1377            values.put(Data.IS_PRIMARY, 1);
1378            values.put(Phone.TYPE, Phone.TYPE_HOME);
1379            values.put(Phone.NUMBER, phone);
1380            mResolver.insert(Data.CONTENT_URI, values);
1381        }
1382    }
1383}
1384