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 assertProjection(Uri uri, String[] expectedProjection)1334 protected void assertProjection(Uri uri, String[] expectedProjection) { 1335 Cursor cursor = mResolver.query(uri, null, "0", null, null); 1336 String[] actualProjection = cursor.getColumnNames(); 1337 MoreAsserts.assertEquals("Incorrect projection for URI: " + uri, 1338 Sets.newHashSet(expectedProjection), Sets.newHashSet(actualProjection)); 1339 cursor.close(); 1340 } 1341 assertContainProjection(Uri uri, String[] mustHaveProjection)1342 protected void assertContainProjection(Uri uri, String[] mustHaveProjection) { 1343 Cursor cursor = mResolver.query(uri, null, "0", null, null); 1344 String[] actualProjection = cursor.getColumnNames(); 1345 Set<String> actualProjectionSet = Sets.newHashSet(actualProjection); 1346 Set<String> mustHaveProjectionSet = Sets.newHashSet(mustHaveProjection); 1347 actualProjectionSet.retainAll(mustHaveProjectionSet); 1348 MoreAsserts.assertEquals(mustHaveProjectionSet, actualProjectionSet); 1349 cursor.close(); 1350 } 1351 assertRowCount(int expectedCount, Uri uri, String selection, String[] args)1352 protected void assertRowCount(int expectedCount, Uri uri, String selection, String[] args) { 1353 Cursor cursor = mResolver.query(uri, null, selection, args, null); 1354 1355 try { 1356 assertEquals(expectedCount, cursor.getCount()); 1357 } catch (Error e) { 1358 TestUtils.dumpCursor(cursor); 1359 throw e; 1360 } finally { 1361 cursor.close(); 1362 } 1363 } 1364 assertLastModified(Uri uri, long time)1365 protected void assertLastModified(Uri uri, long time) { 1366 Cursor c = mResolver.query(uri, null, null, null, null); 1367 c.moveToFirst(); 1368 int index = c.getColumnIndex(CallLog.Calls.LAST_MODIFIED); 1369 long timeStamp = c.getLong(index); 1370 assertEquals(timeStamp, time); 1371 } 1372 setTimeForTest(Long time)1373 protected void setTimeForTest(Long time) { 1374 Uri uri = Calls.CONTENT_URI.buildUpon() 1375 .appendQueryParameter(CallLogProvider.PARAM_KEY_QUERY_FOR_TESTING, "1") 1376 .appendQueryParameter(CallLogProvider.PARAM_KEY_SET_TIME_FOR_TESTING, 1377 time == null ? "null" : time.toString()) 1378 .build(); 1379 mResolver.query(uri, null, null, null, null); 1380 } 1381 insertRawContact(ContentValues values)1382 protected Uri insertRawContact(ContentValues values) { 1383 return TestUtils.insertRawContact(mResolver, 1384 getContactsProvider().getDatabaseHelper(), values); 1385 } 1386 insertProfileRawContact(ContentValues values)1387 protected Uri insertProfileRawContact(ContentValues values) { 1388 return TestUtils.insertProfileRawContact(mResolver, 1389 getContactsProvider().getProfileProviderForTest().getDatabaseHelper(), values); 1390 } 1391 1392 /** 1393 * A contact in the database, and the attributes used to create it. Construct using 1394 * {@link GoldenContactBuilder#build()}. 1395 */ 1396 public final class GoldenContact { 1397 1398 private final long rawContactId; 1399 1400 private final long contactId; 1401 1402 private final String givenName; 1403 1404 private final String familyName; 1405 1406 private final String nickname; 1407 1408 private final byte[] photo; 1409 1410 private final String company; 1411 1412 private final String title; 1413 1414 private final String phone; 1415 1416 private final String email; 1417 GoldenContact(GoldenContactBuilder builder, long rawContactId, long contactId)1418 private GoldenContact(GoldenContactBuilder builder, long rawContactId, long contactId) { 1419 1420 this.rawContactId = rawContactId; 1421 this.contactId = contactId; 1422 givenName = builder.givenName; 1423 familyName = builder.familyName; 1424 nickname = builder.nickname; 1425 photo = builder.photo; 1426 company = builder.company; 1427 title = builder.title; 1428 phone = builder.phone; 1429 email = builder.email; 1430 } 1431 delete()1432 public void delete() { 1433 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 1434 mResolver.delete(rawContactUri, null, null); 1435 } 1436 1437 /** 1438 * Returns the index of the contact in table "raw_contacts" 1439 */ getRawContactId()1440 public long getRawContactId() { 1441 return rawContactId; 1442 } 1443 1444 /** 1445 * Returns the index of the contact in table "contacts" 1446 */ getContactId()1447 public long getContactId() { 1448 return contactId; 1449 } 1450 1451 /** 1452 * Returns the lookup key for the contact. 1453 */ getLookupKey()1454 public String getLookupKey() { 1455 return queryLookupKey(contactId); 1456 } 1457 1458 /** 1459 * Returns the contact's given name. 1460 */ getGivenName()1461 public String getGivenName() { 1462 return givenName; 1463 } 1464 1465 /** 1466 * Returns the contact's family name. 1467 */ getFamilyName()1468 public String getFamilyName() { 1469 return familyName; 1470 } 1471 1472 /** 1473 * Returns the contact's nickname. 1474 */ getNickname()1475 public String getNickname() { 1476 return nickname; 1477 } 1478 1479 /** 1480 * Return's the contact's photo 1481 */ getPhoto()1482 public byte[] getPhoto() { 1483 return photo; 1484 } 1485 1486 /** 1487 * Return's the company at which the contact works. 1488 */ getCompany()1489 public String getCompany() { 1490 return company; 1491 } 1492 1493 /** 1494 * Returns the contact's job title. 1495 */ getTitle()1496 public String getTitle() { 1497 return title; 1498 } 1499 1500 /** 1501 * Returns the contact's phone number 1502 */ getPhone()1503 public String getPhone() { 1504 return phone; 1505 } 1506 1507 /** 1508 * Returns the contact's email address 1509 */ getEmail()1510 public String getEmail() { 1511 return email; 1512 } 1513 } 1514 1515 /** 1516 * Builds {@link GoldenContact} objects. Unspecified boolean objects default to false. 1517 * Unspecified String objects default to null. 1518 */ 1519 public final class GoldenContactBuilder { 1520 1521 private String givenName; 1522 1523 private String familyName; 1524 1525 private String nickname; 1526 1527 private byte[] photo; 1528 1529 private String company; 1530 1531 private String title; 1532 1533 private String phone; 1534 1535 private String email; 1536 1537 /** 1538 * The contact's given and family names. 1539 * 1540 * TODO(dplotnikov): inline, or should we require them to set both names if they set either? 1541 */ name(String givenName, String familyName)1542 public GoldenContactBuilder name(String givenName, String familyName) { 1543 return givenName(givenName).familyName(familyName); 1544 } 1545 1546 /** 1547 * The contact's given name. 1548 */ givenName(String value)1549 public GoldenContactBuilder givenName(String value) { 1550 givenName = value; 1551 return this; 1552 } 1553 1554 /** 1555 * The contact's family name. 1556 */ familyName(String value)1557 public GoldenContactBuilder familyName(String value) { 1558 familyName = value; 1559 return this; 1560 } 1561 1562 /** 1563 * The contact's nickname. 1564 */ nickname(String value)1565 public GoldenContactBuilder nickname(String value) { 1566 nickname = value; 1567 return this; 1568 } 1569 1570 /** 1571 * The contact's photo. 1572 */ photo(byte[] value)1573 public GoldenContactBuilder photo(byte[] value) { 1574 photo = value; 1575 return this; 1576 } 1577 1578 /** 1579 * The company at which the contact works. 1580 */ company(String value)1581 public GoldenContactBuilder company(String value) { 1582 company = value; 1583 return this; 1584 } 1585 1586 /** 1587 * The contact's job title. 1588 */ title(String value)1589 public GoldenContactBuilder title(String value) { 1590 title = value; 1591 return this; 1592 } 1593 1594 /** 1595 * The contact's phone number. 1596 */ phone(String value)1597 public GoldenContactBuilder phone(String value) { 1598 phone = value; 1599 return this; 1600 } 1601 1602 /** 1603 * The contact's email address; also sets their IM status to {@link StatusUpdates#OFFLINE} 1604 * with a presence of "Coding for Android". 1605 */ email(String value)1606 public GoldenContactBuilder email(String value) { 1607 email = value; 1608 return this; 1609 } 1610 1611 /** 1612 * Builds the {@link GoldenContact} specified by this builder. 1613 */ build()1614 public GoldenContact build() { 1615 1616 final long groupId = createGroup(mAccount, "gsid1", "title1"); 1617 1618 long rawContactId = RawContactUtil.createRawContact(mResolver); 1619 insertGroupMembership(rawContactId, groupId); 1620 1621 if (givenName != null || familyName != null) { 1622 DataUtil.insertStructuredName(mResolver, rawContactId, givenName, familyName); 1623 } 1624 if (nickname != null) { 1625 insertNickname(rawContactId, nickname); 1626 } 1627 if (photo != null) { 1628 insertPhoto(rawContactId); 1629 } 1630 if (company != null || title != null) { 1631 insertOrganization(rawContactId); 1632 } 1633 if (email != null) { 1634 insertEmail(rawContactId); 1635 } 1636 if (phone != null) { 1637 insertPhone(rawContactId); 1638 } 1639 1640 long contactId = queryContactId(rawContactId); 1641 1642 return new GoldenContact(this, rawContactId, contactId); 1643 } 1644 insertPhoto(long rawContactId)1645 private void insertPhoto(long rawContactId) { 1646 ContentValues values = new ContentValues(); 1647 values.put(Data.RAW_CONTACT_ID, rawContactId); 1648 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 1649 values.put(Photo.PHOTO, photo); 1650 mResolver.insert(Data.CONTENT_URI, values); 1651 } 1652 insertOrganization(long rawContactId)1653 private void insertOrganization(long rawContactId) { 1654 1655 ContentValues values = new ContentValues(); 1656 values.put(Data.RAW_CONTACT_ID, rawContactId); 1657 values.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE); 1658 values.put(Organization.TYPE, Organization.TYPE_WORK); 1659 if (company != null) { 1660 values.put(Organization.COMPANY, company); 1661 } 1662 if (title != null) { 1663 values.put(Organization.TITLE, title); 1664 } 1665 mResolver.insert(Data.CONTENT_URI, values); 1666 } 1667 insertEmail(long rawContactId)1668 private void insertEmail(long rawContactId) { 1669 1670 ContentValues values = new ContentValues(); 1671 values.put(Data.RAW_CONTACT_ID, rawContactId); 1672 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 1673 values.put(Email.TYPE, Email.TYPE_WORK); 1674 values.put(Email.DATA, "foo@acme.com"); 1675 mResolver.insert(Data.CONTENT_URI, values); 1676 1677 int protocol = Im.PROTOCOL_GOOGLE_TALK; 1678 1679 values.clear(); 1680 values.put(StatusUpdates.PROTOCOL, protocol); 1681 values.put(StatusUpdates.IM_HANDLE, email); 1682 values.put(StatusUpdates.IM_ACCOUNT, "foo"); 1683 values.put(StatusUpdates.PRESENCE_STATUS, StatusUpdates.OFFLINE); 1684 values.put(StatusUpdates.CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 1685 values.put(StatusUpdates.PRESENCE_CUSTOM_STATUS, "Coding for Android"); 1686 mResolver.insert(StatusUpdates.CONTENT_URI, values); 1687 } 1688 insertPhone(long rawContactId)1689 private void insertPhone(long rawContactId) { 1690 ContentValues values = new ContentValues(); 1691 values.put(Data.RAW_CONTACT_ID, rawContactId); 1692 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1693 values.put(Data.IS_PRIMARY, 1); 1694 values.put(Phone.TYPE, Phone.TYPE_HOME); 1695 values.put(Phone.NUMBER, phone); 1696 mResolver.insert(Data.CONTENT_URI, values); 1697 } 1698 } 1699 } 1700