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