• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.providers.contacts;
18 
19 import static com.android.providers.contacts.ContactsActor.PACKAGE_GREY;
20 import static com.android.providers.contacts.TestUtils.cv;
21 import static com.android.providers.contacts.TestUtils.dumpCursor;
22 
23 import android.accounts.Account;
24 import android.content.ContentProvider;
25 import android.content.ContentResolver;
26 import android.content.ContentUris;
27 import android.content.ContentValues;
28 import android.content.Context;
29 import android.content.Entity;
30 import android.database.Cursor;
31 import android.database.sqlite.SQLiteDatabase;
32 import android.net.Uri;
33 import android.provider.BaseColumns;
34 import android.provider.CallLog;
35 import android.provider.CallLog.Calls;
36 import android.provider.ContactsContract;
37 import android.provider.ContactsContract.AggregationExceptions;
38 import android.provider.ContactsContract.CommonDataKinds.Email;
39 import android.provider.ContactsContract.CommonDataKinds.Event;
40 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
41 import android.provider.ContactsContract.CommonDataKinds.Identity;
42 import android.provider.ContactsContract.CommonDataKinds.Im;
43 import android.provider.ContactsContract.CommonDataKinds.Nickname;
44 import android.provider.ContactsContract.CommonDataKinds.Note;
45 import android.provider.ContactsContract.CommonDataKinds.Organization;
46 import android.provider.ContactsContract.CommonDataKinds.Phone;
47 import android.provider.ContactsContract.CommonDataKinds.Photo;
48 import android.provider.ContactsContract.CommonDataKinds.SipAddress;
49 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
50 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
51 import android.provider.ContactsContract.Contacts;
52 import android.provider.ContactsContract.Data;
53 import android.provider.ContactsContract.Groups;
54 import android.provider.ContactsContract.RawContacts;
55 import android.provider.ContactsContract.Settings;
56 import android.provider.ContactsContract.StatusUpdates;
57 import android.provider.ContactsContract.StreamItems;
58 import android.provider.VoicemailContract;
59 import android.telephony.SubscriptionManager;
60 import android.test.MoreAsserts;
61 import android.test.mock.MockContentResolver;
62 import android.util.Log;
63 import com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns;
64 import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
65 import com.android.providers.contacts.testutil.CommonDatabaseUtils;
66 import com.android.providers.contacts.testutil.DataUtil;
67 import com.android.providers.contacts.testutil.RawContactUtil;
68 import com.android.providers.contacts.testutil.TestUtil;
69 import com.android.providers.contacts.util.Hex;
70 import com.android.providers.contacts.util.MockClock;
71 import com.google.android.collect.Sets;
72 
73 import java.util.ArrayList;
74 import java.util.Arrays;
75 import java.util.BitSet;
76 import java.util.Comparator;
77 import java.util.HashSet;
78 import java.util.Iterator;
79 import java.util.Map;
80 import java.util.Map.Entry;
81 import java.util.Set;
82 
83 import org.mockito.Mock;
84 import org.mockito.MockitoAnnotations;
85 
86 /**
87  * A common superclass for {@link ContactsProvider2}-related tests.
88  */
89 public abstract class BaseContactsProvider2Test extends PhotoLoadingTestCase {
90 
91     static final String ADD_VOICEMAIL_PERMISSION =
92             "com.android.voicemail.permission.ADD_VOICEMAIL";
93     /*
94      * Permission to allow querying voicemails
95      */
96     static final String READ_VOICEMAIL_PERMISSION =
97             "com.android.voicemail.permission.READ_VOICEMAIL";
98     /*
99      * Permission to allow deleting and updating voicemails
100      */
101     static final String WRITE_VOICEMAIL_PERMISSION =
102             "com.android.voicemail.permission.WRITE_VOICEMAIL";
103 
104     protected static final String PACKAGE = "ContactsProvider2Test";
105     public static final String READ_ONLY_ACCOUNT_TYPE =
106             SynchronousContactsProvider2.READ_ONLY_ACCOUNT_TYPE;
107 
108     protected ContactsActor mActor;
109     protected MockContentResolver mResolver;
110     protected Account mAccount = new Account("account1", "account type1");
111     protected Account mAccountTwo = new Account("account2", "account type2");
112 
113     protected final static Long NO_LONG = new Long(0);
114     protected final static String NO_STRING = new String("");
115     protected final static Account NO_ACCOUNT = new Account("a", "b");
116 
117     ContextWithServiceOverrides mTestContext;
118     @Mock SubscriptionManager mSubscriptionManager;
119 
120     /**
121      * Use {@link MockClock#install()} to start using it.
122      * It'll be automatically uninstalled by {@link #tearDown()}.
123      */
124     protected static final MockClock sMockClock = new MockClock();
125 
getProviderClass()126     protected Class<? extends ContentProvider> getProviderClass() {
127         return SynchronousContactsProvider2.class;
128     }
129 
getAuthority()130     protected String getAuthority() {
131         return ContactsContract.AUTHORITY;
132     }
133 
134     @Override
setUp()135     protected void setUp() throws Exception {
136         super.setUp();
137         MockitoAnnotations.initMocks(this);
138 
139         mTestContext = new ContextWithServiceOverrides(getContext());
140         mTestContext.injectSystemService(SubscriptionManager.class, mSubscriptionManager);
141 
142         mActor = new ContactsActor(
143                 mTestContext, getContextPackageName(), getProviderClass(), getAuthority());
144         mResolver = mActor.resolver;
145         if (mActor.provider instanceof SynchronousContactsProvider2) {
146             getContactsProvider().wipeData();
147         }
148 
149         // Give the actor access to read/write contacts and profile data by default.
150         mActor.addPermissions(
151                 "android.permission.READ_CONTACTS",
152                 "android.permission.WRITE_CONTACTS",
153                 "android.permission.READ_WRITE_CONTACT_METADATA",
154                 "android.permission.READ_SOCIAL_STREAM",
155                 "android.permission.WRITE_SOCIAL_STREAM");
156     }
157 
getContextPackageName()158     protected String getContextPackageName() {
159         return PACKAGE_GREY;
160     }
161 
162     @Override
tearDown()163     protected void tearDown() throws Exception {
164         mActor.shutdown();
165         sMockClock.uninstall();
166         super.tearDown();
167     }
168 
getContactsProvider()169     public SynchronousContactsProvider2 getContactsProvider() {
170         return (SynchronousContactsProvider2) mActor.provider;
171     }
172 
getMockContext()173     public Context getMockContext() {
174         return mActor.context;
175     }
176 
addProvider(Class<T> providerClass, String authority)177     public <T extends ContentProvider> T addProvider(Class<T> providerClass,
178             String authority) throws Exception {
179         return mActor.addProvider(providerClass, authority);
180     }
181 
getProvider()182     public ContentProvider getProvider() {
183         return mActor.provider;
184     }
185 
setCallerIsSyncAdapter(Uri uri, Account account)186     protected Uri setCallerIsSyncAdapter(Uri uri, Account account) {
187         if (account == null) {
188             return uri;
189         }
190         final Uri.Builder builder = uri.buildUpon();
191         builder.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, account.name);
192         builder.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type);
193         builder.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true");
194         return builder.build();
195     }
196 
updateItem(Uri uri, long id, String... extras)197     protected int updateItem(Uri uri, long id, String... extras) {
198         Uri itemUri = ContentUris.withAppendedId(uri, id);
199         return updateItem(itemUri, extras);
200     }
201 
updateItem(Uri uri, String... extras)202     protected int updateItem(Uri uri, String... extras) {
203         ContentValues values = new ContentValues();
204         CommonDatabaseUtils.extrasVarArgsToValues(values, extras);
205         return mResolver.update(uri, values, null, null);
206     }
207 
createGroup(Account account, String sourceId, String title)208     protected long createGroup(Account account, String sourceId, String title) {
209         return createGroup(account, sourceId, title, 1, false, false);
210     }
211 
createGroup(Account account, String sourceId, String title, int visible)212     protected long createGroup(Account account, String sourceId, String title, int visible) {
213         return createGroup(account, sourceId, title, visible, false, false);
214     }
215 
createAutoAddGroup(Account account)216     protected long createAutoAddGroup(Account account) {
217         return createGroup(account, "auto", "auto",
218                 0 /* visible */,  true /* auto-add */, false /* fav */);
219     }
220 
createGroup(Account account, String sourceId, String title, int visible, boolean autoAdd, boolean favorite)221     protected long createGroup(Account account, String sourceId, String title,
222             int visible, boolean autoAdd, boolean favorite) {
223         ContentValues values = new ContentValues();
224         values.put(Groups.SOURCE_ID, sourceId);
225         values.put(Groups.TITLE, title);
226         values.put(Groups.GROUP_VISIBLE, visible);
227         values.put(Groups.AUTO_ADD, autoAdd ? 1 : 0);
228         values.put(Groups.FAVORITES, favorite ? 1 : 0);
229         final Uri uri = TestUtil.maybeAddAccountQueryParameters(Groups.CONTENT_URI, account);
230         return ContentUris.parseId(mResolver.insert(uri, values));
231     }
232 
createSettings(Account account, String shouldSync, String ungroupedVisible)233     protected Uri createSettings(Account account, String shouldSync, String ungroupedVisible) {
234         return createSettings(new AccountWithDataSet(account.name, account.type, null),
235                 shouldSync, ungroupedVisible);
236     }
237 
createSettings(AccountWithDataSet account, String shouldSync, String ungroupedVisible)238     protected Uri createSettings(AccountWithDataSet account, String shouldSync,
239             String ungroupedVisible) {
240         ContentValues values = new ContentValues();
241         values.put(Settings.ACCOUNT_NAME, account.getAccountName());
242         values.put(Settings.ACCOUNT_TYPE, account.getAccountType());
243         if (account.getDataSet() != null) {
244             values.put(Settings.DATA_SET, account.getDataSet());
245         }
246         values.put(Settings.SHOULD_SYNC, shouldSync);
247         values.put(Settings.UNGROUPED_VISIBLE, ungroupedVisible);
248         return mResolver.insert(Settings.CONTENT_URI, values);
249     }
250 
insertOrganization(long rawContactId, ContentValues values)251     protected Uri insertOrganization(long rawContactId, ContentValues values) {
252         return insertOrganization(rawContactId, values, false, false);
253     }
254 
insertOrganization(long rawContactId, ContentValues values, boolean primary)255     protected Uri insertOrganization(long rawContactId, ContentValues values, boolean primary) {
256         return insertOrganization(rawContactId, values, primary, false);
257     }
258 
insertOrganization(long rawContactId, ContentValues values, boolean primary, boolean superPrimary)259     protected Uri insertOrganization(long rawContactId, ContentValues values, boolean primary,
260             boolean superPrimary) {
261         values.put(Data.RAW_CONTACT_ID, rawContactId);
262         values.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
263         values.put(Organization.TYPE, Organization.TYPE_WORK);
264         if (primary) {
265             values.put(Data.IS_PRIMARY, 1);
266         }
267         if (superPrimary) {
268             values.put(Data.IS_SUPER_PRIMARY, 1);
269         }
270 
271         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
272         return resultUri;
273     }
274 
insertPhoneNumber(long rawContactId, String phoneNumber)275     protected Uri insertPhoneNumber(long rawContactId, String phoneNumber) {
276         return insertPhoneNumber(rawContactId, phoneNumber, false);
277     }
278 
insertPhoneNumber(long rawContactId, String phoneNumber, boolean primary)279     protected Uri insertPhoneNumber(long rawContactId, String phoneNumber, boolean primary) {
280         return insertPhoneNumber(rawContactId, phoneNumber, primary, false, Phone.TYPE_HOME);
281     }
282 
insertPhoneNumber(long rawContactId, String phoneNumber, boolean primary, boolean superPrimary)283     protected Uri insertPhoneNumber(long rawContactId, String phoneNumber, boolean primary,
284             boolean superPrimary) {
285         return insertPhoneNumber(rawContactId, phoneNumber, primary, superPrimary, Phone.TYPE_HOME);
286     }
287 
insertPhoneNumber(long rawContactId, String phoneNumber, boolean primary, int type)288     protected Uri insertPhoneNumber(long rawContactId, String phoneNumber, boolean primary,
289             int type) {
290         return insertPhoneNumber(rawContactId, phoneNumber, primary, false, type);
291     }
292 
insertPhoneNumber(long rawContactId, String phoneNumber, boolean primary, boolean superPrimary, int type)293     protected Uri insertPhoneNumber(long rawContactId, String phoneNumber, boolean primary,
294             boolean superPrimary, int type) {
295         ContentValues values = new ContentValues();
296         values.put(Data.RAW_CONTACT_ID, rawContactId);
297         values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
298         values.put(Phone.NUMBER, phoneNumber);
299         values.put(Phone.TYPE, type);
300         if (primary) {
301             values.put(Data.IS_PRIMARY, 1);
302         }
303         if (superPrimary) {
304             values.put(Data.IS_SUPER_PRIMARY, 1);
305         }
306 
307         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
308         return resultUri;
309     }
310 
insertEmail(long rawContactId, String email)311     protected Uri insertEmail(long rawContactId, String email) {
312         return insertEmail(rawContactId, email, false);
313     }
314 
insertEmail(long rawContactId, String email, boolean primary)315     protected Uri insertEmail(long rawContactId, String email, boolean primary) {
316         return insertEmail(rawContactId, email, primary, Email.TYPE_HOME, null);
317     }
318 
insertEmail(long rawContactId, String email, boolean primary, boolean superPrimary)319     protected Uri insertEmail(long rawContactId, String email, boolean primary,
320             boolean superPrimary) {
321         return insertEmail(rawContactId, email, primary, superPrimary, Email.TYPE_HOME, null);
322     }
323 
insertEmail(long rawContactId, String email, boolean primary, int type, String label)324     protected Uri insertEmail(long rawContactId, String email, boolean primary, int type,
325             String label) {
326         return insertEmail(rawContactId, email, primary, false, type, label);
327     }
328 
insertEmail(long rawContactId, String email, boolean primary, boolean superPrimary, int type, String label)329     protected Uri insertEmail(long rawContactId, String email, boolean primary,
330             boolean superPrimary, int type,  String label) {
331         ContentValues values = new ContentValues();
332         values.put(Data.RAW_CONTACT_ID, rawContactId);
333         values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
334         values.put(Email.DATA, email);
335         values.put(Email.TYPE, type);
336         values.put(Email.LABEL, label);
337         if (primary) {
338             values.put(Data.IS_PRIMARY, 1);
339         }
340         if (superPrimary) {
341             values.put(Data.IS_SUPER_PRIMARY, 1);
342         }
343 
344         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
345         return resultUri;
346     }
347 
insertSipAddress(long rawContactId, String sipAddress)348     protected Uri insertSipAddress(long rawContactId, String sipAddress) {
349         return insertSipAddress(rawContactId, sipAddress, false);
350     }
351 
insertSipAddress(long rawContactId, String sipAddress, boolean primary)352     protected Uri insertSipAddress(long rawContactId, String sipAddress, boolean primary) {
353         ContentValues values = new ContentValues();
354         values.put(Data.RAW_CONTACT_ID, rawContactId);
355         values.put(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE);
356         values.put(SipAddress.SIP_ADDRESS, sipAddress);
357         if (primary) {
358             values.put(Data.IS_PRIMARY, 1);
359         }
360 
361         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
362         return resultUri;
363     }
364 
insertNickname(long rawContactId, String nickname)365     protected Uri insertNickname(long rawContactId, String nickname) {
366         ContentValues values = new ContentValues();
367         values.put(Data.RAW_CONTACT_ID, rawContactId);
368         values.put(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE);
369         values.put(Nickname.NAME, nickname);
370         values.put(Nickname.TYPE, Nickname.TYPE_OTHER_NAME);
371 
372         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
373         return resultUri;
374     }
375 
insertPostalAddress(long rawContactId, String formattedAddress)376     protected Uri insertPostalAddress(long rawContactId, String formattedAddress) {
377         ContentValues values = new ContentValues();
378         values.put(Data.RAW_CONTACT_ID, rawContactId);
379         values.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
380         values.put(StructuredPostal.FORMATTED_ADDRESS, formattedAddress);
381 
382         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
383         return resultUri;
384     }
385 
insertPostalAddress(long rawContactId, ContentValues values)386     protected Uri insertPostalAddress(long rawContactId, ContentValues values) {
387         values.put(Data.RAW_CONTACT_ID, rawContactId);
388         values.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
389         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
390         return resultUri;
391     }
392 
insertPhoto(long rawContactId)393     protected Uri insertPhoto(long rawContactId) {
394         ContentValues values = new ContentValues();
395         values.put(Data.RAW_CONTACT_ID, rawContactId);
396         values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
397         values.put(Photo.PHOTO, loadTestPhoto());
398         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
399         return resultUri;
400     }
401 
insertPhoto(long rawContactId, int resourceId)402     protected Uri insertPhoto(long rawContactId, int resourceId) {
403         ContentValues values = new ContentValues();
404         values.put(Data.RAW_CONTACT_ID, rawContactId);
405         values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
406         values.put(Photo.PHOTO, loadPhotoFromResource(resourceId, PhotoSize.ORIGINAL));
407         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
408         return resultUri;
409     }
410 
insertGroupMembership(long rawContactId, String sourceId)411     protected Uri insertGroupMembership(long rawContactId, String sourceId) {
412         ContentValues values = new ContentValues();
413         values.put(Data.RAW_CONTACT_ID, rawContactId);
414         values.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
415         values.put(GroupMembership.GROUP_SOURCE_ID, sourceId);
416         return mResolver.insert(Data.CONTENT_URI, values);
417     }
418 
insertGroupMembership(long rawContactId, Long groupId)419     protected Uri insertGroupMembership(long rawContactId, Long groupId) {
420         ContentValues values = new ContentValues();
421         values.put(Data.RAW_CONTACT_ID, rawContactId);
422         values.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
423         values.put(GroupMembership.GROUP_ROW_ID, groupId);
424         return mResolver.insert(Data.CONTENT_URI, values);
425     }
426 
removeGroupMemberships(long rawContactId)427     public void removeGroupMemberships(long rawContactId) {
428         mResolver.delete(Data.CONTENT_URI,
429                 Data.MIMETYPE + "=? AND " + GroupMembership.RAW_CONTACT_ID + "=?",
430                 new String[] { GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(rawContactId) });
431     }
432 
insertStatusUpdate(int protocol, String customProtocol, String handle, int presence, String status, int chatMode)433     protected Uri insertStatusUpdate(int protocol, String customProtocol, String handle,
434             int presence, String status, int chatMode) {
435         return insertStatusUpdate(protocol, customProtocol, handle, presence, status, chatMode,
436                 false);
437     }
438 
insertStatusUpdate(int protocol, String customProtocol, String handle, int presence, String status, int chatMode, boolean isUserProfile)439     protected Uri insertStatusUpdate(int protocol, String customProtocol, String handle,
440             int presence, String status, int chatMode, boolean isUserProfile) {
441         return insertStatusUpdate(protocol, customProtocol, handle, presence, status, 0, chatMode,
442                 isUserProfile);
443     }
444 
insertStatusUpdate(int protocol, String customProtocol, String handle, int presence, String status, long timestamp, int chatMode, boolean isUserProfile)445     protected Uri insertStatusUpdate(int protocol, String customProtocol, String handle,
446             int presence, String status, long timestamp, int chatMode, boolean isUserProfile) {
447         ContentValues values = new ContentValues();
448         values.put(StatusUpdates.PROTOCOL, protocol);
449         values.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol);
450         values.put(StatusUpdates.IM_HANDLE, handle);
451         return insertStatusUpdate(values, presence, status, timestamp, chatMode, isUserProfile);
452     }
453 
insertStatusUpdate( long dataId, int presence, String status, long timestamp, int chatMode)454     protected Uri insertStatusUpdate(
455             long dataId, int presence, String status, long timestamp, int chatMode) {
456         return insertStatusUpdate(dataId, presence, status, timestamp, chatMode, false);
457     }
458 
insertStatusUpdate( long dataId, int presence, String status, long timestamp, int chatMode, boolean isUserProfile)459     protected Uri insertStatusUpdate(
460             long dataId, int presence, String status, long timestamp, int chatMode,
461             boolean isUserProfile) {
462         ContentValues values = new ContentValues();
463         values.put(StatusUpdates.DATA_ID, dataId);
464         return insertStatusUpdate(values, presence, status, timestamp, chatMode, isUserProfile);
465     }
466 
insertStatusUpdate( ContentValues values, int presence, String status, long timestamp, int chatMode, boolean isUserProfile)467     private Uri insertStatusUpdate(
468             ContentValues values, int presence, String status, long timestamp, int chatMode,
469             boolean isUserProfile) {
470         if (presence != 0) {
471             values.put(StatusUpdates.PRESENCE, presence);
472             values.put(StatusUpdates.CHAT_CAPABILITY, chatMode);
473         }
474         if (status != null) {
475             values.put(StatusUpdates.STATUS, status);
476         }
477         if (timestamp != 0) {
478             values.put(StatusUpdates.STATUS_TIMESTAMP, timestamp);
479         }
480 
481         Uri insertUri = isUserProfile
482                 ? StatusUpdates.PROFILE_CONTENT_URI
483                 : StatusUpdates.CONTENT_URI;
484         Uri resultUri = mResolver.insert(insertUri, values);
485         return resultUri;
486     }
487 
insertStreamItem(long rawContactId, ContentValues values, Account account)488     protected Uri insertStreamItem(long rawContactId, ContentValues values, Account account) {
489         return mResolver.insert(
490                 TestUtil.maybeAddAccountQueryParameters(Uri.withAppendedPath(
491                         ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
492                         RawContacts.StreamItems.CONTENT_DIRECTORY), account),
493                 values);
494     }
495 
insertStreamItemPhoto(long streamItemId, ContentValues values, Account account)496     protected Uri insertStreamItemPhoto(long streamItemId, ContentValues values, Account account) {
497         return mResolver.insert(
498                 TestUtil.maybeAddAccountQueryParameters(Uri.withAppendedPath(
499                         ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId),
500                         StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), account),
501                 values);
502     }
503 
insertImHandle(long rawContactId, int protocol, String customProtocol, String handle)504     protected Uri insertImHandle(long rawContactId, int protocol, String customProtocol,
505             String handle) {
506         ContentValues values = new ContentValues();
507         values.put(Data.RAW_CONTACT_ID, rawContactId);
508         values.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
509         values.put(Im.PROTOCOL, protocol);
510         values.put(Im.CUSTOM_PROTOCOL, customProtocol);
511         values.put(Im.DATA, handle);
512         values.put(Im.TYPE, Im.TYPE_HOME);
513 
514         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
515         return resultUri;
516     }
517 
insertEvent(long rawContactId, int type, String date)518     protected Uri insertEvent(long rawContactId, int type, String date) {
519         ContentValues values = new ContentValues();
520         values.put(Data.RAW_CONTACT_ID, rawContactId);
521         values.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
522         values.put(Event.TYPE, type);
523         values.put(Event.START_DATE, date);
524         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
525         return resultUri;
526     }
527 
insertNote(long rawContactId, String note)528     protected Uri insertNote(long rawContactId, String note) {
529         ContentValues values = new ContentValues();
530         values.put(Data.RAW_CONTACT_ID, rawContactId);
531         values.put(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
532         values.put(Note.NOTE, note);
533         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
534         return resultUri;
535     }
536 
insertIdentity(long rawContactId, String identity, String namespace)537     protected Uri insertIdentity(long rawContactId, String identity, String namespace) {
538         ContentValues values = new ContentValues();
539         values.put(Data.RAW_CONTACT_ID, rawContactId);
540         values.put(Data.MIMETYPE, Identity.CONTENT_ITEM_TYPE);
541         values.put(Identity.NAMESPACE, namespace);
542         values.put(Identity.IDENTITY, identity);
543 
544         Uri resultUri = mResolver.insert(Data.CONTENT_URI, values);
545         return resultUri;
546     }
547 
setContactAccount(long rawContactId, String accountType, String accountName)548     protected void setContactAccount(long rawContactId, String accountType, String accountName) {
549         ContentValues values = new ContentValues();
550         values.put(RawContacts.ACCOUNT_TYPE, accountType);
551         values.put(RawContacts.ACCOUNT_NAME, accountName);
552 
553         mResolver.update(ContentUris.withAppendedId(
554                 RawContacts.CONTENT_URI, rawContactId), values, null, null);
555     }
556 
setAggregationException(int type, long rawContactId1, long rawContactId2)557     protected void setAggregationException(int type, long rawContactId1, long rawContactId2) {
558         ContentValues values = new ContentValues();
559         values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
560         values.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
561         values.put(AggregationExceptions.TYPE, type);
562         assertEquals(1, mResolver.update(AggregationExceptions.CONTENT_URI, values, null, null));
563     }
564 
setRawContactCustomization(long rawContactId, int starred, int sendToVoiceMail)565     protected void setRawContactCustomization(long rawContactId, int starred, int sendToVoiceMail) {
566         ContentValues values = new ContentValues();
567 
568         values.put(RawContacts.STARRED, starred);
569         values.put(RawContacts.SEND_TO_VOICEMAIL, sendToVoiceMail);
570 
571         assertEquals(1, mResolver.update(ContentUris.withAppendedId(
572                 RawContacts.CONTENT_URI, rawContactId), values, null, null));
573     }
574 
markInvisible(long contactId)575     protected void markInvisible(long contactId) {
576         // There's no api for this, so we just tweak the DB directly.
577         SQLiteDatabase db = ((ContactsProvider2) getProvider()).getDatabaseHelper()
578                 .getWritableDatabase();
579         db.execSQL("DELETE FROM " + Tables.DEFAULT_DIRECTORY +
580                 " WHERE " + BaseColumns._ID + "=" + contactId);
581     }
582 
createAccount(String accountName, String accountType, String dataSet)583     protected long createAccount(String accountName, String accountType, String dataSet) {
584         // There's no api for this, so we just tweak the DB directly.
585         SQLiteDatabase db = ((ContactsProvider2) getProvider()).getDatabaseHelper()
586                 .getWritableDatabase();
587 
588         ContentValues values = new ContentValues();
589         values.put(AccountsColumns.ACCOUNT_NAME, accountName);
590         values.put(AccountsColumns.ACCOUNT_TYPE, accountType);
591         values.put(AccountsColumns.DATA_SET, dataSet);
592         return db.insert(Tables.ACCOUNTS, null, values);
593     }
594 
queryRawContact(long rawContactId)595     protected Cursor queryRawContact(long rawContactId) {
596         return mResolver.query(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
597                 null, null, null, null);
598     }
599 
queryContact(long contactId)600     protected Cursor queryContact(long contactId) {
601         return mResolver.query(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
602                 null, null, null, null);
603     }
604 
queryContact(long contactId, String[] projection)605     protected Cursor queryContact(long contactId, String[] projection) {
606         return mResolver.query(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
607                 projection, null, null, null);
608     }
609 
getContactUriForRawContact(long rawContactId)610     protected Uri getContactUriForRawContact(long rawContactId) {
611         return ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(rawContactId));
612     }
613 
queryContactId(long rawContactId)614     protected long queryContactId(long rawContactId) {
615         Cursor c = queryRawContact(rawContactId);
616         assertTrue(c.moveToFirst());
617         long contactId = c.getLong(c.getColumnIndex(RawContacts.CONTACT_ID));
618         c.close();
619         return contactId;
620     }
621 
queryPhotoId(long contactId)622     protected long queryPhotoId(long contactId) {
623         Cursor c = queryContact(contactId);
624         assertTrue(c.moveToFirst());
625         long photoId = c.getInt(c.getColumnIndex(Contacts.PHOTO_ID));
626         c.close();
627         return photoId;
628     }
629 
queryPhotoFileId(long contactId)630     protected long queryPhotoFileId(long contactId) {
631         return getStoredLongValue(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
632                 Contacts.PHOTO_FILE_ID);
633     }
634 
queryRawContactIsStarred(long rawContactId)635     protected boolean queryRawContactIsStarred(long rawContactId) {
636         Cursor c = queryRawContact(rawContactId);
637         try {
638             assertTrue(c.moveToFirst());
639             return c.getLong(c.getColumnIndex(RawContacts.STARRED)) != 0;
640         } finally {
641             c.close();
642         }
643     }
644 
queryDisplayName(long contactId)645     protected String queryDisplayName(long contactId) {
646         Cursor c = queryContact(contactId);
647         assertTrue(c.moveToFirst());
648         String displayName = c.getString(c.getColumnIndex(Contacts.DISPLAY_NAME));
649         c.close();
650         return displayName;
651     }
652 
queryLookupKey(long contactId)653     protected String queryLookupKey(long contactId) {
654         Cursor c = queryContact(contactId);
655         assertTrue(c.moveToFirst());
656         String lookupKey = c.getString(c.getColumnIndex(Contacts.LOOKUP_KEY));
657         c.close();
658         return lookupKey;
659     }
660 
assertAggregated(long rawContactId1, long rawContactId2)661     protected void assertAggregated(long rawContactId1, long rawContactId2) {
662         long contactId1 = queryContactId(rawContactId1);
663         long contactId2 = queryContactId(rawContactId2);
664         assertTrue(contactId1 == contactId2);
665     }
666 
assertAggregated(long rawContactId1, long rawContactId2, String expectedDisplayName)667     protected void assertAggregated(long rawContactId1, long rawContactId2,
668             String expectedDisplayName) {
669         long contactId1 = queryContactId(rawContactId1);
670         long contactId2 = queryContactId(rawContactId2);
671         assertTrue(contactId1 == contactId2);
672 
673         String displayName = queryDisplayName(contactId1);
674         assertEquals(expectedDisplayName, displayName);
675     }
676 
assertNotAggregated(long rawContactId1, long rawContactId2)677     protected void assertNotAggregated(long rawContactId1, long rawContactId2) {
678         long contactId1 = queryContactId(rawContactId1);
679         long contactId2 = queryContactId(rawContactId2);
680         assertTrue(contactId1 != contactId2);
681     }
682 
assertStructuredName(long rawContactId, String prefix, String givenName, String middleName, String familyName, String suffix)683     protected void assertStructuredName(long rawContactId, String prefix, String givenName,
684             String middleName, String familyName, String suffix) {
685         Uri uri = Uri.withAppendedPath(
686                 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
687                 RawContacts.Data.CONTENT_DIRECTORY);
688 
689         final String[] projection = new String[] {
690                 StructuredName.PREFIX, StructuredName.GIVEN_NAME, StructuredName.MIDDLE_NAME,
691                 StructuredName.FAMILY_NAME, StructuredName.SUFFIX
692         };
693 
694         Cursor c = mResolver.query(uri, projection, Data.MIMETYPE + "='"
695                 + StructuredName.CONTENT_ITEM_TYPE + "'", null, null);
696 
697         assertTrue(c.moveToFirst());
698         assertEquals(prefix, c.getString(0));
699         assertEquals(givenName, c.getString(1));
700         assertEquals(middleName, c.getString(2));
701         assertEquals(familyName, c.getString(3));
702         assertEquals(suffix, c.getString(4));
703         c.close();
704     }
705 
assertSingleGroup(Long rowId, Account account, String sourceId, String title)706     protected long assertSingleGroup(Long rowId, Account account, String sourceId, String title) {
707         Cursor c = mResolver.query(Groups.CONTENT_URI, null, null, null, null);
708         try {
709             assertTrue(c.moveToNext());
710             long actualRowId = assertGroup(c, rowId, account, sourceId, title);
711             assertFalse(c.moveToNext());
712             return actualRowId;
713         } finally {
714             c.close();
715         }
716     }
717 
assertSingleGroupMembership(Long rowId, Long rawContactId, Long groupRowId, String sourceId)718     protected long assertSingleGroupMembership(Long rowId, Long rawContactId, Long groupRowId,
719             String sourceId) {
720         Cursor c = mResolver.query(ContactsContract.Data.CONTENT_URI, null, null, null, null);
721         try {
722             assertTrue(c.moveToNext());
723             long actualRowId = assertGroupMembership(c, rowId, rawContactId, groupRowId, sourceId);
724             assertFalse(c.moveToNext());
725             return actualRowId;
726         } finally {
727             c.close();
728         }
729     }
730 
assertGroupMembership(Cursor c, Long rowId, Long rawContactId, Long groupRowId, String sourceId)731     protected long assertGroupMembership(Cursor c, Long rowId, Long rawContactId, Long groupRowId,
732             String sourceId) {
733         assertNullOrEquals(c, rowId, Data._ID);
734         assertNullOrEquals(c, rawContactId, GroupMembership.RAW_CONTACT_ID);
735         assertNullOrEquals(c, groupRowId, GroupMembership.GROUP_ROW_ID);
736         assertNullOrEquals(c, sourceId, GroupMembership.GROUP_SOURCE_ID);
737         return c.getLong(c.getColumnIndexOrThrow("_id"));
738     }
739 
assertGroup(Cursor c, Long rowId, Account account, String sourceId, String title)740     protected long assertGroup(Cursor c, Long rowId, Account account, String sourceId, String title) {
741         assertNullOrEquals(c, rowId, Groups._ID);
742         assertNullOrEquals(c, account);
743         assertNullOrEquals(c, sourceId, Groups.SOURCE_ID);
744         assertNullOrEquals(c, title, Groups.TITLE);
745         return c.getLong(c.getColumnIndexOrThrow("_id"));
746     }
747 
assertNullOrEquals(Cursor c, Account account)748     private void assertNullOrEquals(Cursor c, Account account) {
749         if (account == NO_ACCOUNT) {
750             return;
751         }
752         if (account == null) {
753             assertTrue(c.isNull(c.getColumnIndexOrThrow(Groups.ACCOUNT_NAME)));
754             assertTrue(c.isNull(c.getColumnIndexOrThrow(Groups.ACCOUNT_TYPE)));
755         } else {
756             assertEquals(account.name, c.getString(c.getColumnIndexOrThrow(Groups.ACCOUNT_NAME)));
757             assertEquals(account.type, c.getString(c.getColumnIndexOrThrow(Groups.ACCOUNT_TYPE)));
758         }
759     }
760 
assertNullOrEquals(Cursor c, Long value, String columnName)761     private void assertNullOrEquals(Cursor c, Long value, String columnName) {
762         if (value != NO_LONG) {
763             if (value == null) assertTrue(c.isNull(c.getColumnIndexOrThrow(columnName)));
764             else assertEquals((long) value, c.getLong(c.getColumnIndexOrThrow(columnName)));
765         }
766     }
767 
assertNullOrEquals(Cursor c, String value, String columnName)768     private void assertNullOrEquals(Cursor c, String value, String columnName) {
769         if (value != NO_STRING) {
770             if (value == null) assertTrue(c.isNull(c.getColumnIndexOrThrow(columnName)));
771             else assertEquals(value, c.getString(c.getColumnIndexOrThrow(columnName)));
772         }
773     }
774 
assertSuperPrimary(Long dataId, boolean isSuperPrimary)775     protected void assertSuperPrimary(Long dataId, boolean isSuperPrimary) {
776         final String[] projection = new String[]{Data.MIMETYPE, Data._ID, Data.IS_SUPER_PRIMARY};
777         Cursor c = mResolver.query(ContentUris.withAppendedId(Data.CONTENT_URI, dataId),
778                 projection, null, null, null);
779 
780         c.moveToFirst();
781         if (isSuperPrimary) {
782             assertEquals(1, c.getInt(c.getColumnIndexOrThrow(Data.IS_SUPER_PRIMARY)));
783         } else {
784             assertEquals(0, c.getInt(c.getColumnIndexOrThrow(Data.IS_SUPER_PRIMARY)));
785         }
786 
787     }
788 
assertDataRow(ContentValues actual, String expectedMimetype, Object... expectedArguments)789     protected void assertDataRow(ContentValues actual, String expectedMimetype,
790             Object... expectedArguments) {
791         assertEquals(actual.toString(), expectedMimetype, actual.getAsString(Data.MIMETYPE));
792         for (int i = 0; i < expectedArguments.length; i += 2) {
793             String columnName = (String) expectedArguments[i];
794             Object expectedValue = expectedArguments[i + 1];
795             if (expectedValue instanceof Uri) {
796                 expectedValue = ContentUris.parseId((Uri) expectedValue);
797             }
798             if (expectedValue == null) {
799                 assertNull(actual.toString(), actual.get(columnName));
800             }
801             if (expectedValue instanceof Long) {
802                 assertEquals("mismatch at " + columnName + " from " + actual.toString(),
803                         expectedValue, actual.getAsLong(columnName));
804             } else if (expectedValue instanceof Integer) {
805                 assertEquals("mismatch at " + columnName + " from " + actual.toString(),
806                         expectedValue, actual.getAsInteger(columnName));
807             } else if (expectedValue instanceof String) {
808                 assertEquals("mismatch at " + columnName + " from " + actual.toString(),
809                         expectedValue, actual.getAsString(columnName));
810             } else {
811                 assertEquals("mismatch at " + columnName + " from " + actual.toString(),
812                         expectedValue, actual.get(columnName));
813             }
814         }
815     }
816 
assertNoRowsAndClose(Cursor c)817     protected void assertNoRowsAndClose(Cursor c) {
818         try {
819             assertFalse(c.moveToNext());
820         } finally {
821             c.close();
822         }
823     }
824 
825     protected static class IdComparator implements Comparator<ContentValues> {
826         @Override
compare(ContentValues o1, ContentValues o2)827         public int compare(ContentValues o1, ContentValues o2) {
828             long id1 = o1.getAsLong(ContactsContract.Data._ID);
829             long id2 = o2.getAsLong(ContactsContract.Data._ID);
830             if (id1 == id2) return 0;
831             return (id1 < id2) ? -1 : 1;
832         }
833     }
834 
asSortedContentValuesArray( ArrayList<Entity.NamedContentValues> subValues)835     protected ContentValues[] asSortedContentValuesArray(
836             ArrayList<Entity.NamedContentValues> subValues) {
837         ContentValues[] result = new ContentValues[subValues.size()];
838         int i = 0;
839         for (Entity.NamedContentValues subValue : subValues) {
840             result[i] = subValue.values;
841             i++;
842         }
843         Arrays.sort(result, new IdComparator());
844         return result;
845     }
846 
assertDirty(Uri uri, boolean state)847     protected void assertDirty(Uri uri, boolean state) {
848         Cursor c = mResolver.query(uri, new String[]{"dirty"}, null, null, null);
849         assertTrue(c.moveToNext());
850         assertEquals(state, c.getLong(0) != 0);
851         assertFalse(c.moveToNext());
852         c.close();
853     }
854 
assertMetadataDirty(Uri uri, boolean state)855     protected void assertMetadataDirty(Uri uri, boolean state) {
856         Cursor c = mResolver.query(uri, new String[]{"metadata_dirty"}, null, null, null);
857         assertTrue(c.moveToNext());
858         assertEquals(state, c.getLong(0) != 0);
859         assertFalse(c.moveToNext());
860         c.close();
861     }
862 
getVersion(Uri uri)863     protected long getVersion(Uri uri) {
864         Cursor c = mResolver.query(uri, new String[]{"version"}, null, null, null);
865         assertTrue(c.moveToNext());
866         long version = c.getLong(0);
867         assertFalse(c.moveToNext());
868         c.close();
869         return version;
870     }
871 
clearDirty(Uri uri)872     protected void clearDirty(Uri uri) {
873         ContentValues values = new ContentValues();
874         values.put("dirty", 0);
875         mResolver.update(uri, values, null, null);
876     }
877 
clearMetadataDirty(Uri uri)878     protected void clearMetadataDirty(Uri uri) {
879         ContentValues values = new ContentValues();
880         values.put("metadata_dirty", 0);
881         mResolver.update(uri, values, null, null);
882     }
883 
storeValue(Uri contentUri, long id, String column, String value)884     protected void storeValue(Uri contentUri, long id, String column, String value) {
885         storeValue(ContentUris.withAppendedId(contentUri, id), column, value);
886     }
887 
storeValue(Uri contentUri, String column, String value)888     protected void storeValue(Uri contentUri, String column, String value) {
889         ContentValues values = new ContentValues();
890         values.put(column, value);
891 
892         mResolver.update(contentUri, values, null, null);
893     }
894 
storeValue(Uri contentUri, long id, String column, long value)895     protected void storeValue(Uri contentUri, long id, String column, long value) {
896         storeValue(ContentUris.withAppendedId(contentUri, id), column, value);
897     }
898 
storeValue(Uri contentUri, String column, long value)899     protected void storeValue(Uri contentUri, String column, long value) {
900         ContentValues values = new ContentValues();
901         values.put(column, value);
902 
903         mResolver.update(contentUri, values, null, null);
904     }
905 
assertStoredValue(Uri contentUri, long id, String column, Object expectedValue)906     protected void assertStoredValue(Uri contentUri, long id, String column, Object expectedValue) {
907         assertStoredValue(ContentUris.withAppendedId(contentUri, id), column, expectedValue);
908     }
909 
assertStoredValue(Uri rowUri, String column, Object expectedValue)910     protected void assertStoredValue(Uri rowUri, String column, Object expectedValue) {
911         String value = getStoredValue(rowUri, column);
912         if (expectedValue == null) {
913             assertNull("Column value " + column, value);
914         } else {
915             assertEquals("Column value " + column, String.valueOf(expectedValue), value);
916         }
917     }
918 
assertStoredValue(Uri rowUri, String selection, String[] selectionArgs, String column, Object expectedValue)919     protected void assertStoredValue(Uri rowUri, String selection, String[] selectionArgs,
920             String column, Object expectedValue) {
921         String value = getStoredValue(rowUri, selection, selectionArgs, column);
922         if (expectedValue == null) {
923             assertNull("Column value " + column, value);
924         } else {
925             assertEquals("Column value " + column, String.valueOf(expectedValue), value);
926         }
927     }
928 
getStoredValue(Uri rowUri, String column)929     protected String getStoredValue(Uri rowUri, String column) {
930         return getStoredValue(rowUri, null, null, column);
931     }
932 
getStoredValue(Uri uri, String selection, String[] selectionArgs, String column)933     protected String getStoredValue(Uri uri, String selection, String[] selectionArgs,
934             String column) {
935         String value = null;
936         Cursor c = mResolver.query(uri, new String[] { column }, selection, selectionArgs, null);
937         try {
938             assertEquals("Record count for " + uri, 1, c.getCount());
939 
940             if (c.moveToFirst()) {
941                 value = c.getString(c.getColumnIndex(column));
942             }
943         } finally {
944             c.close();
945         }
946         return value;
947     }
948 
getStoredLongValue(Uri uri, String selection, String[] selectionArgs, String column)949     protected Long getStoredLongValue(Uri uri, String selection, String[] selectionArgs,
950             String column) {
951         Long value = null;
952         Cursor c = mResolver.query(uri, new String[] { column }, selection, selectionArgs, null);
953         try {
954             assertEquals("Record count", 1, c.getCount());
955 
956             if (c.moveToFirst()) {
957                 value = c.getLong(c.getColumnIndex(column));
958             }
959         } finally {
960             c.close();
961         }
962         return value;
963     }
964 
getStoredLongValue(Uri uri, String column)965     protected Long getStoredLongValue(Uri uri, String column) {
966         return getStoredLongValue(uri, null, null, column);
967     }
968 
assertStoredValues(Uri rowUri, ContentValues expectedValues)969     protected void assertStoredValues(Uri rowUri, ContentValues expectedValues) {
970         assertStoredValues(rowUri, null, null, expectedValues);
971     }
972 
assertStoredValues(Uri rowUri, ContentValues... expectedValues)973     protected void assertStoredValues(Uri rowUri, ContentValues... expectedValues) {
974         assertStoredValues(rowUri, null, null, expectedValues);
975     }
976 
assertStoredValues(Uri rowUri, String selection, String[] selectionArgs, ContentValues expectedValues)977     protected void assertStoredValues(Uri rowUri, String selection, String[] selectionArgs,
978             ContentValues expectedValues) {
979         Cursor c = mResolver.query(rowUri, null, selection, selectionArgs, null);
980         try {
981             assertEquals("Record count", 1, c.getCount());
982             c.moveToFirst();
983             assertCursorValues(c, expectedValues);
984         } catch (Error e) {
985             TestUtils.dumpCursor(c);
986             throw e;
987         } finally {
988             c.close();
989         }
990     }
991 
assertContainsValues(Uri rowUri, ContentValues expectedValues)992     protected void assertContainsValues(Uri rowUri, ContentValues expectedValues) {
993         Cursor c = mResolver.query(rowUri, null, null, null, null);
994         try {
995             assertEquals("Record count", 1, c.getCount());
996             c.moveToFirst();
997             assertCursorValuesPartialMatch(c, expectedValues);
998         } catch (Error e) {
999             TestUtils.dumpCursor(c);
1000             throw e;
1001         } finally {
1002             c.close();
1003         }
1004     }
1005 
assertStoredValuesWithProjection(Uri rowUri, ContentValues expectedValues)1006     protected void assertStoredValuesWithProjection(Uri rowUri, ContentValues expectedValues) {
1007         assertStoredValuesWithProjection(rowUri, new ContentValues[] {expectedValues});
1008     }
1009 
assertStoredValuesWithProjection(Uri rowUri, ContentValues... expectedValues)1010     protected void assertStoredValuesWithProjection(Uri rowUri, ContentValues... expectedValues) {
1011         assertTrue("Need at least one ContentValues for this test", expectedValues.length > 0);
1012         Cursor c = mResolver.query(rowUri, buildProjection(expectedValues[0]), null, null, null);
1013         try {
1014             assertEquals("Record count", expectedValues.length, c.getCount());
1015             c.moveToFirst();
1016             assertCursorValues(c, expectedValues);
1017         } catch (Error e) {
1018             TestUtils.dumpCursor(c);
1019             throw e;
1020         } finally {
1021             c.close();
1022         }
1023     }
1024 
assertStoredValues( Uri rowUri, String selection, String[] selectionArgs, ContentValues... expectedValues)1025     protected void assertStoredValues(
1026             Uri rowUri, String selection, String[] selectionArgs, ContentValues... expectedValues) {
1027         assertStoredValues(mResolver.query(rowUri, null, selection, selectionArgs, null),
1028                 expectedValues);
1029     }
1030 
assertStoredValues(Cursor c, ContentValues... expectedValues)1031     private void assertStoredValues(Cursor c, ContentValues... expectedValues) {
1032         try {
1033             assertEquals("Record count", expectedValues.length, c.getCount());
1034             assertCursorValues(c, expectedValues);
1035         } catch (Error e) {
1036             TestUtils.dumpCursor(c);
1037             throw e;
1038         } finally {
1039             c.close();
1040         }
1041     }
1042 
1043     /**
1044      * A variation of {@link #assertStoredValues}, but it queries directly to the DB.
1045      */
assertStoredValuesDb( String sql, String[] selectionArgs, ContentValues... expectedValues)1046     protected void assertStoredValuesDb(
1047             String sql, String[] selectionArgs, ContentValues... expectedValues) {
1048         SQLiteDatabase db = ((ContactsProvider2) getProvider()).getDatabaseHelper()
1049                 .getReadableDatabase();
1050         assertStoredValues(db.rawQuery(sql, selectionArgs), expectedValues);
1051     }
1052 
assertStoredValuesOrderly(Uri rowUri, ContentValues... expectedValues)1053     protected void assertStoredValuesOrderly(Uri rowUri, ContentValues... expectedValues) {
1054         assertStoredValuesOrderly(rowUri, null, null, expectedValues);
1055     }
1056 
assertStoredValuesOrderly(Uri rowUri, String selection, String[] selectionArgs, ContentValues... expectedValues)1057     protected void assertStoredValuesOrderly(Uri rowUri, String selection,
1058             String[] selectionArgs, ContentValues... expectedValues) {
1059         Cursor c = mResolver.query(rowUri, null, selection, selectionArgs, null);
1060         try {
1061             assertEquals("Record count", expectedValues.length, c.getCount());
1062             assertCursorValuesOrderly(c, expectedValues);
1063         } catch (Error e) {
1064             TestUtils.dumpCursor(c);
1065             throw e;
1066         } finally {
1067             c.close();
1068         }
1069     }
1070 
1071     /**
1072      * Constructs a selection (where clause) out of all supplied values, uses it
1073      * to query the provider and verifies that a single row is returned and it
1074      * has the same values as requested.
1075      */
assertSelection(Uri uri, ContentValues values, String idColumn, long id)1076     protected void assertSelection(Uri uri, ContentValues values, String idColumn, long id) {
1077         assertSelection(uri, values, idColumn, id, null);
1078     }
1079 
assertSelectionWithProjection(Uri uri, ContentValues values, String idColumn, long id)1080     public void assertSelectionWithProjection(Uri uri, ContentValues values, String idColumn,
1081             long id) {
1082         assertSelection(uri, values, idColumn, id, buildProjection(values));
1083     }
1084 
assertSelection(Uri uri, ContentValues values, String idColumn, long id, String[] projection)1085     private void assertSelection(Uri uri, ContentValues values, String idColumn, long id,
1086             String[] projection) {
1087         StringBuilder sb = new StringBuilder();
1088         ArrayList<String> selectionArgs = new ArrayList<String>(values.size());
1089         if (idColumn != null) {
1090             sb.append(idColumn).append("=").append(id);
1091         }
1092         Set<Map.Entry<String, Object>> entries = values.valueSet();
1093         for (Map.Entry<String, Object> entry : entries) {
1094             String column = entry.getKey();
1095             Object value = entry.getValue();
1096             if (sb.length() != 0) {
1097                 sb.append(" AND ");
1098             }
1099             sb.append(column);
1100             if (value == null) {
1101                 sb.append(" IS NULL");
1102             } else {
1103                 sb.append("=?");
1104                 selectionArgs.add(String.valueOf(value));
1105             }
1106         }
1107 
1108         Cursor c = mResolver.query(uri, projection, sb.toString(), selectionArgs.toArray(new String[0]),
1109                 null);
1110         try {
1111             assertEquals("Record count", 1, c.getCount());
1112             c.moveToFirst();
1113             assertCursorValues(c, values);
1114         } catch (Error e) {
1115             TestUtils.dumpCursor(c);
1116 
1117             // Dump with no selection.
1118             TestUtils.dumpUri(mResolver, uri);
1119             throw e;
1120         } finally {
1121             c.close();
1122         }
1123     }
1124 
assertCursorValue(Cursor cursor, String column, Object expectedValue)1125     protected void assertCursorValue(Cursor cursor, String column, Object expectedValue) {
1126         String actualValue = cursor.getString(cursor.getColumnIndex(column));
1127         assertEquals("Column " + column, String.valueOf(expectedValue),
1128                 String.valueOf(actualValue));
1129     }
1130 
assertCursorValues(Cursor cursor, ContentValues expectedValues)1131     protected void assertCursorValues(Cursor cursor, ContentValues expectedValues) {
1132         StringBuilder message = new StringBuilder();
1133         boolean result = equalsWithExpectedValues(cursor, expectedValues, message);
1134         assertTrue(message.toString(), result);
1135     }
1136 
assertCursorValuesPartialMatch(Cursor cursor, ContentValues expectedValues)1137     protected void assertCursorValuesPartialMatch(Cursor cursor, ContentValues expectedValues) {
1138         StringBuilder message = new StringBuilder();
1139         boolean result = expectedValuePartiallyMatches(cursor, expectedValues, message);
1140         assertTrue(message.toString(), result);
1141     }
1142 
assertCursorHasAnyRecordMatch(Cursor cursor, ContentValues expectedValues)1143     protected void assertCursorHasAnyRecordMatch(Cursor cursor, ContentValues expectedValues) {
1144         final StringBuilder message = new StringBuilder();
1145         boolean found = false;
1146         cursor.moveToPosition(-1);
1147         while (cursor.moveToNext()) {
1148             message.setLength(0);
1149             final int pos = cursor.getPosition();
1150             found = equalsWithExpectedValues(cursor, expectedValues, message);
1151             if (found) {
1152                 break;
1153             }
1154         }
1155         assertTrue("Expected values can not be found " + expectedValues + "," + message.toString(),
1156                 found);
1157     }
1158 
assertCursorValues(Cursor cursor, ContentValues... expectedValues)1159     protected void assertCursorValues(Cursor cursor, ContentValues... expectedValues) {
1160         StringBuilder message = new StringBuilder();
1161 
1162         // In case if expectedValues contains multiple identical values, remember which cursor
1163         // rows are "consumed" to prevent multiple ContentValues from hitting the same row.
1164         final BitSet used = new BitSet(cursor.getCount());
1165 
1166         for (ContentValues v : expectedValues) {
1167             boolean found = false;
1168             cursor.moveToPosition(-1);
1169             while (cursor.moveToNext()) {
1170                 final int pos = cursor.getPosition();
1171                 if (used.get(pos)) continue;
1172                 found = equalsWithExpectedValues(cursor, v, message);
1173                 if (found) {
1174                     used.set(pos);
1175                     break;
1176                 }
1177             }
1178             assertTrue("Expected values can not be found " + v + "," + message.toString(), found);
1179         }
1180     }
1181 
assertCursorValuesOrderly(Cursor cursor, ContentValues... expectedValues)1182     public static void assertCursorValuesOrderly(Cursor cursor, ContentValues... expectedValues) {
1183         StringBuilder message = new StringBuilder();
1184         cursor.moveToPosition(-1);
1185         for (ContentValues v : expectedValues) {
1186             assertTrue(cursor.moveToNext());
1187             boolean ok = equalsWithExpectedValues(cursor, v, message);
1188             assertTrue("ContentValues didn't match.  Pos=" + cursor.getPosition() + ", values=" +
1189                     v + message.toString(), ok);
1190         }
1191     }
1192 
expectedValuePartiallyMatches(Cursor cursor, ContentValues expectedValues, StringBuilder msgBuffer)1193     private boolean expectedValuePartiallyMatches(Cursor cursor, ContentValues expectedValues,
1194             StringBuilder msgBuffer) {
1195         for (String column : expectedValues.keySet()) {
1196             int index = cursor.getColumnIndex(column);
1197             if (index == -1) {
1198                 msgBuffer.append(" No such column: ").append(column);
1199                 return false;
1200             }
1201             String expectedValue = expectedValues.getAsString(column);
1202             String value = cursor.getString(cursor.getColumnIndex(column));
1203             if (value != null && !value.contains(expectedValue)) {
1204                 msgBuffer.append(" Column value ").append(column).append(" expected to contain <")
1205                         .append(expectedValue).append(">, but was <").append(value).append('>');
1206                 return false;
1207             }
1208         }
1209         return true;
1210     }
1211 
equalsWithExpectedValues(Cursor cursor, ContentValues expectedValues, StringBuilder msgBuffer)1212     private static boolean equalsWithExpectedValues(Cursor cursor, ContentValues expectedValues,
1213             StringBuilder msgBuffer) {
1214         for (String column : expectedValues.keySet()) {
1215             int index = cursor.getColumnIndex(column);
1216             if (index == -1) {
1217                 msgBuffer.append(" No such column: ").append(column);
1218                 return false;
1219             }
1220             Object expectedValue = expectedValues.get(column);
1221             String value;
1222             if (expectedValue instanceof byte[]) {
1223                 expectedValue = Hex.encodeHex((byte[])expectedValue, false);
1224                 value = Hex.encodeHex(cursor.getBlob(index), false);
1225             } else {
1226                 expectedValue = expectedValues.getAsString(column);
1227                 value = cursor.getString(cursor.getColumnIndex(column));
1228             }
1229             if (expectedValue != null && !expectedValue.equals(value) || value != null
1230                     && !value.equals(expectedValue)) {
1231                 msgBuffer
1232                         .append(" Column value ")
1233                         .append(column)
1234                         .append(" expected <")
1235                         .append(expectedValue)
1236                         .append(">, but was <")
1237                         .append(value)
1238                         .append('>');
1239                 return false;
1240             }
1241         }
1242         return true;
1243     }
1244 
1245     private static final String[] DATA_USAGE_PROJECTION =
1246             new String[] {Data.DATA1, Data.TIMES_USED, Data.LAST_TIME_USED};
1247 
assertDataUsageZero(Uri uri, String data1)1248     protected void assertDataUsageZero(Uri uri, String data1) {
1249         final Cursor cursor = mResolver.query(uri, DATA_USAGE_PROJECTION, null, null,
1250                 null);
1251         try {
1252             dumpCursor(cursor);
1253             assertCursorHasAnyRecordMatch(cursor, cv(Data.DATA1, data1, Data.TIMES_USED, 0,
1254                     Data.LAST_TIME_USED, 0));
1255         } finally {
1256             cursor.close();
1257         }
1258     }
1259 
buildProjection(ContentValues values)1260     private String[] buildProjection(ContentValues values) {
1261         String[] projection = new String[values.size()];
1262         Iterator<Entry<String, Object>> iter = values.valueSet().iterator();
1263         for (int i = 0; i < projection.length; i++) {
1264             projection[i] = iter.next().getKey();
1265         }
1266         return projection;
1267     }
1268 
getCount(Uri uri)1269     protected int getCount(Uri uri) {
1270         return getCount(uri, null, null);
1271     }
1272 
getCount(Uri uri, String selection, String[] selectionArgs)1273     protected int getCount(Uri uri, String selection, String[] selectionArgs) {
1274         Cursor c = mResolver.query(uri, null, selection, selectionArgs, null);
1275         try {
1276             return c.getCount();
1277         } finally {
1278             c.close();
1279         }
1280     }
1281 
dump(ContentResolver resolver, boolean aggregatedOnly)1282     public static void dump(ContentResolver resolver, boolean aggregatedOnly) {
1283         String[] projection = new String[] {
1284                 Contacts._ID,
1285                 Contacts.DISPLAY_NAME
1286         };
1287         String selection = null;
1288         if (aggregatedOnly) {
1289             selection = Contacts._ID
1290                     + " IN (SELECT contact_id" +
1291                     		" FROM raw_contacts GROUP BY contact_id HAVING count(*) > 1)";
1292         }
1293 
1294         Cursor c = resolver.query(Contacts.CONTENT_URI, projection, selection, null,
1295                 Contacts.DISPLAY_NAME);
1296         while(c.moveToNext()) {
1297             long contactId = c.getLong(0);
1298             Log.i("Contact   ", String.format("%5d %s", contactId, c.getString(1)));
1299             dumpRawContacts(resolver, contactId);
1300             Log.i("          ", ".");
1301         }
1302         c.close();
1303     }
1304 
dumpRawContacts(ContentResolver resolver, long contactId)1305     private static void dumpRawContacts(ContentResolver resolver, long contactId) {
1306         String[] projection = new String[] {
1307                 RawContacts._ID,
1308         };
1309         Cursor c = resolver.query(RawContacts.CONTENT_URI, projection, RawContacts.CONTACT_ID + "="
1310                 + contactId, null, null);
1311         while(c.moveToNext()) {
1312             long rawContactId = c.getLong(0);
1313             Log.i("RawContact", String.format("      %-5d", rawContactId));
1314             dumpData(resolver, rawContactId);
1315         }
1316         c.close();
1317     }
1318 
dumpData(ContentResolver resolver, long rawContactId)1319     private static void dumpData(ContentResolver resolver, long rawContactId) {
1320         String[] projection = new String[] {
1321                 Data.MIMETYPE,
1322                 Data.DATA1,
1323                 Data.DATA2,
1324                 Data.DATA3,
1325         };
1326         Cursor c = resolver.query(Data.CONTENT_URI, projection, Data.RAW_CONTACT_ID + "="
1327                 + rawContactId, null, Data.MIMETYPE);
1328         while(c.moveToNext()) {
1329             String mimetype = c.getString(0);
1330             if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) {
1331                 Log.i("Photo     ", "");
1332             } else {
1333                 mimetype = mimetype.substring(mimetype.indexOf('/') + 1);
1334                 Log.i("Data      ", String.format("            %-10s %s,%s,%s", mimetype,
1335                         c.getString(1), c.getString(2), c.getString(3)));
1336             }
1337         }
1338         c.close();
1339     }
1340 
assertNetworkNotified(boolean expected)1341     protected void assertNetworkNotified(boolean expected) {
1342         assertEquals(expected, (getContactsProvider()).isNetworkNotified());
1343     }
1344 
assertProjection(Uri uri, String[] expectedProjection)1345     protected void assertProjection(Uri uri, String[] expectedProjection) {
1346         Cursor cursor = mResolver.query(uri, null, "0", null, null);
1347         String[] actualProjection = cursor.getColumnNames();
1348         MoreAsserts.assertEquals("Incorrect projection for URI: " + uri,
1349                 Sets.newHashSet(expectedProjection), Sets.newHashSet(actualProjection));
1350         cursor.close();
1351     }
1352 
assertContainProjection(Uri uri, String[] mustHaveProjection)1353     protected void assertContainProjection(Uri uri, String[] mustHaveProjection) {
1354         Cursor cursor = mResolver.query(uri, null, "0", null, null);
1355         String[] actualProjection = cursor.getColumnNames();
1356         Set<String> actualProjectionSet = Sets.newHashSet(actualProjection);
1357         Set<String> mustHaveProjectionSet = Sets.newHashSet(mustHaveProjection);
1358         actualProjectionSet.retainAll(mustHaveProjectionSet);
1359         MoreAsserts.assertEquals(mustHaveProjectionSet, actualProjectionSet);
1360         cursor.close();
1361     }
1362 
assertRowCount(int expectedCount, Uri uri, String selection, String[] args)1363     protected void assertRowCount(int expectedCount, Uri uri, String selection, String[] args) {
1364         Cursor cursor = mResolver.query(uri, null, selection, args, null);
1365 
1366         try {
1367             assertEquals(expectedCount, cursor.getCount());
1368         } catch (Error e) {
1369             TestUtils.dumpCursor(cursor);
1370             throw e;
1371         } finally {
1372             cursor.close();
1373         }
1374     }
1375 
assertLastModified(Uri uri, long time)1376     protected void assertLastModified(Uri uri, long time) {
1377         Cursor c = mResolver.query(uri, null, null, null, null);
1378         c.moveToFirst();
1379         int index = c.getColumnIndex(CallLog.Calls.LAST_MODIFIED);
1380         long timeStamp = c.getLong(index);
1381         assertEquals(timeStamp, time);
1382     }
1383 
setTimeForTest(Long time)1384     protected void setTimeForTest(Long time) {
1385         Uri uri = Calls.CONTENT_URI.buildUpon()
1386                 .appendQueryParameter(CallLogProvider.PARAM_KEY_QUERY_FOR_TESTING, "1")
1387                 .appendQueryParameter(CallLogProvider.PARAM_KEY_SET_TIME_FOR_TESTING,
1388                         time == null ? "null" : time.toString())
1389                 .build();
1390         mResolver.query(uri, null, null, null, null);
1391     }
1392 
insertRawContact(ContentValues values)1393     protected Uri insertRawContact(ContentValues values) {
1394         return TestUtils.insertRawContact(mResolver,
1395                 getContactsProvider().getDatabaseHelper(), values);
1396     }
1397 
insertProfileRawContact(ContentValues values)1398     protected Uri insertProfileRawContact(ContentValues values) {
1399         return TestUtils.insertProfileRawContact(mResolver,
1400                 getContactsProvider().getProfileProviderForTest().getDatabaseHelper(), values);
1401     }
1402 
1403     /**
1404      * A contact in the database, and the attributes used to create it.  Construct using
1405      * {@link GoldenContactBuilder#build()}.
1406      */
1407     public final class GoldenContact {
1408 
1409         private final long rawContactId;
1410 
1411         private final long contactId;
1412 
1413         private final String givenName;
1414 
1415         private final String familyName;
1416 
1417         private final String nickname;
1418 
1419         private final byte[] photo;
1420 
1421         private final String company;
1422 
1423         private final String title;
1424 
1425         private final String phone;
1426 
1427         private final String email;
1428 
GoldenContact(GoldenContactBuilder builder, long rawContactId, long contactId)1429         private GoldenContact(GoldenContactBuilder builder, long rawContactId, long contactId) {
1430 
1431             this.rawContactId = rawContactId;
1432             this.contactId = contactId;
1433             givenName = builder.givenName;
1434             familyName = builder.familyName;
1435             nickname = builder.nickname;
1436             photo = builder.photo;
1437             company = builder.company;
1438             title = builder.title;
1439             phone = builder.phone;
1440             email = builder.email;
1441         }
1442 
delete()1443         public void delete() {
1444             Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
1445             mResolver.delete(rawContactUri, null, null);
1446         }
1447 
1448         /**
1449          * Returns the index of the contact in table "raw_contacts"
1450          */
getRawContactId()1451         public long getRawContactId() {
1452             return rawContactId;
1453         }
1454 
1455         /**
1456          * Returns the index of the contact in table "contacts"
1457          */
getContactId()1458         public long getContactId() {
1459             return contactId;
1460         }
1461 
1462         /**
1463          * Returns the lookup key for the contact.
1464          */
getLookupKey()1465         public String getLookupKey() {
1466             return queryLookupKey(contactId);
1467         }
1468 
1469         /**
1470          * Returns the contact's given name.
1471          */
getGivenName()1472         public String getGivenName() {
1473             return givenName;
1474         }
1475 
1476         /**
1477          * Returns the contact's family name.
1478          */
getFamilyName()1479         public String getFamilyName() {
1480             return familyName;
1481         }
1482 
1483         /**
1484          * Returns the contact's nickname.
1485          */
getNickname()1486         public String getNickname() {
1487             return nickname;
1488         }
1489 
1490         /**
1491          * Return's the contact's photo
1492          */
getPhoto()1493         public byte[] getPhoto() {
1494             return photo;
1495         }
1496 
1497         /**
1498          * Return's the company at which the contact works.
1499          */
getCompany()1500         public String getCompany() {
1501             return company;
1502         }
1503 
1504         /**
1505          * Returns the contact's job title.
1506          */
getTitle()1507         public String getTitle() {
1508             return title;
1509         }
1510 
1511         /**
1512          * Returns the contact's phone number
1513          */
getPhone()1514         public String getPhone() {
1515             return phone;
1516         }
1517 
1518         /**
1519          * Returns the contact's email address
1520          */
getEmail()1521         public String getEmail() {
1522             return email;
1523         }
1524      }
1525 
1526     /**
1527      * Builds {@link GoldenContact} objects.  Unspecified boolean objects default to false.
1528      * Unspecified String objects default to null.
1529      */
1530     public final class GoldenContactBuilder {
1531 
1532         private String givenName;
1533 
1534         private String familyName;
1535 
1536         private String nickname;
1537 
1538         private byte[] photo;
1539 
1540         private String company;
1541 
1542         private String title;
1543 
1544         private String phone;
1545 
1546         private String email;
1547 
1548         /**
1549          * The contact's given and family names.
1550          *
1551          * TODO(dplotnikov): inline, or should we require them to set both names if they set either?
1552          */
name(String givenName, String familyName)1553         public GoldenContactBuilder name(String givenName, String familyName) {
1554             return givenName(givenName).familyName(familyName);
1555         }
1556 
1557         /**
1558          * The contact's given name.
1559          */
givenName(String value)1560         public GoldenContactBuilder givenName(String value) {
1561             givenName = value;
1562             return this;
1563         }
1564 
1565         /**
1566          * The contact's family name.
1567          */
familyName(String value)1568         public GoldenContactBuilder familyName(String value) {
1569             familyName = value;
1570             return this;
1571         }
1572 
1573         /**
1574          * The contact's nickname.
1575          */
nickname(String value)1576         public GoldenContactBuilder nickname(String value) {
1577             nickname = value;
1578             return this;
1579         }
1580 
1581         /**
1582          * The contact's photo.
1583          */
photo(byte[] value)1584         public GoldenContactBuilder photo(byte[] value) {
1585             photo = value;
1586             return this;
1587         }
1588 
1589         /**
1590          * The company at which the contact works.
1591          */
company(String value)1592         public GoldenContactBuilder company(String value) {
1593             company = value;
1594             return this;
1595         }
1596 
1597         /**
1598          * The contact's job title.
1599          */
title(String value)1600         public GoldenContactBuilder title(String value) {
1601             title = value;
1602             return this;
1603         }
1604 
1605         /**
1606          * The contact's phone number.
1607          */
phone(String value)1608         public GoldenContactBuilder phone(String value) {
1609             phone = value;
1610             return this;
1611         }
1612 
1613         /**
1614          * The contact's email address; also sets their IM status to {@link StatusUpdates#OFFLINE}
1615          * with a presence of "Coding for Android".
1616          */
email(String value)1617         public GoldenContactBuilder email(String value) {
1618             email = value;
1619             return this;
1620         }
1621 
1622         /**
1623          * Builds the {@link GoldenContact} specified by this builder.
1624          */
build()1625         public GoldenContact build() {
1626 
1627             final long groupId = createGroup(mAccount, "gsid1", "title1");
1628 
1629             long rawContactId = RawContactUtil.createRawContact(mResolver);
1630             insertGroupMembership(rawContactId, groupId);
1631 
1632             if (givenName != null || familyName != null) {
1633                 DataUtil.insertStructuredName(mResolver, rawContactId, givenName, familyName);
1634             }
1635             if (nickname != null) {
1636                 insertNickname(rawContactId, nickname);
1637             }
1638             if (photo != null) {
1639                 insertPhoto(rawContactId);
1640             }
1641             if (company != null || title != null) {
1642                 insertOrganization(rawContactId);
1643             }
1644             if (email != null) {
1645                 insertEmail(rawContactId);
1646             }
1647             if (phone != null) {
1648                 insertPhone(rawContactId);
1649             }
1650 
1651             long contactId = queryContactId(rawContactId);
1652 
1653             return new GoldenContact(this, rawContactId, contactId);
1654         }
1655 
insertPhoto(long rawContactId)1656         private void insertPhoto(long rawContactId) {
1657             ContentValues values = new ContentValues();
1658             values.put(Data.RAW_CONTACT_ID, rawContactId);
1659             values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
1660             values.put(Photo.PHOTO, photo);
1661             mResolver.insert(Data.CONTENT_URI, values);
1662         }
1663 
insertOrganization(long rawContactId)1664         private void insertOrganization(long rawContactId) {
1665 
1666             ContentValues values = new ContentValues();
1667             values.put(Data.RAW_CONTACT_ID, rawContactId);
1668             values.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
1669             values.put(Organization.TYPE, Organization.TYPE_WORK);
1670             if (company != null) {
1671                 values.put(Organization.COMPANY, company);
1672             }
1673             if (title != null) {
1674                 values.put(Organization.TITLE, title);
1675             }
1676             mResolver.insert(Data.CONTENT_URI, values);
1677         }
1678 
insertEmail(long rawContactId)1679         private void insertEmail(long rawContactId) {
1680 
1681             ContentValues values = new ContentValues();
1682             values.put(Data.RAW_CONTACT_ID, rawContactId);
1683             values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
1684             values.put(Email.TYPE, Email.TYPE_WORK);
1685             values.put(Email.DATA, "foo@acme.com");
1686             mResolver.insert(Data.CONTENT_URI, values);
1687 
1688             int protocol = Im.PROTOCOL_GOOGLE_TALK;
1689 
1690             values.clear();
1691             values.put(StatusUpdates.PROTOCOL, protocol);
1692             values.put(StatusUpdates.IM_HANDLE, email);
1693             values.put(StatusUpdates.IM_ACCOUNT, "foo");
1694             values.put(StatusUpdates.PRESENCE_STATUS, StatusUpdates.OFFLINE);
1695             values.put(StatusUpdates.CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA);
1696             values.put(StatusUpdates.PRESENCE_CUSTOM_STATUS, "Coding for Android");
1697             mResolver.insert(StatusUpdates.CONTENT_URI, values);
1698         }
1699 
insertPhone(long rawContactId)1700         private void insertPhone(long rawContactId) {
1701             ContentValues values = new ContentValues();
1702             values.put(Data.RAW_CONTACT_ID, rawContactId);
1703             values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
1704             values.put(Data.IS_PRIMARY, 1);
1705             values.put(Phone.TYPE, Phone.TYPE_HOME);
1706             values.put(Phone.NUMBER, phone);
1707             mResolver.insert(Data.CONTENT_URI, values);
1708         }
1709     }
1710 }
1711