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 assertDataUsageCursorContains(Uri uri, String data1, int timesUsed, int lastTimeUsed)1237 protected void assertDataUsageCursorContains(Uri uri, String data1, int timesUsed, 1238 int lastTimeUsed) { 1239 final Cursor cursor = mResolver.query(uri, DATA_USAGE_PROJECTION, null, null, 1240 null); 1241 try { 1242 dumpCursor(cursor); 1243 assertCursorHasAnyRecordMatch(cursor, cv(Data.DATA1, data1, Data.TIMES_USED, timesUsed, 1244 Data.LAST_TIME_USED, lastTimeUsed)); 1245 } finally { 1246 cursor.close(); 1247 } 1248 } 1249 buildProjection(ContentValues values)1250 private String[] buildProjection(ContentValues values) { 1251 String[] projection = new String[values.size()]; 1252 Iterator<Entry<String, Object>> iter = values.valueSet().iterator(); 1253 for (int i = 0; i < projection.length; i++) { 1254 projection[i] = iter.next().getKey(); 1255 } 1256 return projection; 1257 } 1258 getCount(Uri uri)1259 protected int getCount(Uri uri) { 1260 return getCount(uri, null, null); 1261 } 1262 getCount(Uri uri, String selection, String[] selectionArgs)1263 protected int getCount(Uri uri, String selection, String[] selectionArgs) { 1264 Cursor c = mResolver.query(uri, null, selection, selectionArgs, null); 1265 try { 1266 return c.getCount(); 1267 } finally { 1268 c.close(); 1269 } 1270 } 1271 dump(ContentResolver resolver, boolean aggregatedOnly)1272 public static void dump(ContentResolver resolver, boolean aggregatedOnly) { 1273 String[] projection = new String[] { 1274 Contacts._ID, 1275 Contacts.DISPLAY_NAME 1276 }; 1277 String selection = null; 1278 if (aggregatedOnly) { 1279 selection = Contacts._ID 1280 + " IN (SELECT contact_id" + 1281 " FROM raw_contacts GROUP BY contact_id HAVING count(*) > 1)"; 1282 } 1283 1284 Cursor c = resolver.query(Contacts.CONTENT_URI, projection, selection, null, 1285 Contacts.DISPLAY_NAME); 1286 while(c.moveToNext()) { 1287 long contactId = c.getLong(0); 1288 Log.i("Contact ", String.format("%5d %s", contactId, c.getString(1))); 1289 dumpRawContacts(resolver, contactId); 1290 Log.i(" ", "."); 1291 } 1292 c.close(); 1293 } 1294 dumpRawContacts(ContentResolver resolver, long contactId)1295 private static void dumpRawContacts(ContentResolver resolver, long contactId) { 1296 String[] projection = new String[] { 1297 RawContacts._ID, 1298 }; 1299 Cursor c = resolver.query(RawContacts.CONTENT_URI, projection, RawContacts.CONTACT_ID + "=" 1300 + contactId, null, null); 1301 while(c.moveToNext()) { 1302 long rawContactId = c.getLong(0); 1303 Log.i("RawContact", String.format(" %-5d", rawContactId)); 1304 dumpData(resolver, rawContactId); 1305 } 1306 c.close(); 1307 } 1308 dumpData(ContentResolver resolver, long rawContactId)1309 private static void dumpData(ContentResolver resolver, long rawContactId) { 1310 String[] projection = new String[] { 1311 Data.MIMETYPE, 1312 Data.DATA1, 1313 Data.DATA2, 1314 Data.DATA3, 1315 }; 1316 Cursor c = resolver.query(Data.CONTENT_URI, projection, Data.RAW_CONTACT_ID + "=" 1317 + rawContactId, null, Data.MIMETYPE); 1318 while(c.moveToNext()) { 1319 String mimetype = c.getString(0); 1320 if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) { 1321 Log.i("Photo ", ""); 1322 } else { 1323 mimetype = mimetype.substring(mimetype.indexOf('/') + 1); 1324 Log.i("Data ", String.format(" %-10s %s,%s,%s", mimetype, 1325 c.getString(1), c.getString(2), c.getString(3))); 1326 } 1327 } 1328 c.close(); 1329 } 1330 assertNetworkNotified(boolean expected)1331 protected void assertNetworkNotified(boolean expected) { 1332 assertEquals(expected, (getContactsProvider()).isNetworkNotified()); 1333 } 1334 assertMetadataNetworkNotified(boolean expected)1335 protected void assertMetadataNetworkNotified(boolean expected) { 1336 assertEquals(expected, (getContactsProvider()).isMetadataNetworkNotified()); 1337 } 1338 assertProjection(Uri uri, String[] expectedProjection)1339 protected void assertProjection(Uri uri, String[] expectedProjection) { 1340 Cursor cursor = mResolver.query(uri, null, "0", null, null); 1341 String[] actualProjection = cursor.getColumnNames(); 1342 MoreAsserts.assertEquals("Incorrect projection for URI: " + uri, 1343 Sets.newHashSet(expectedProjection), Sets.newHashSet(actualProjection)); 1344 cursor.close(); 1345 } 1346 assertContainProjection(Uri uri, String[] mustHaveProjection)1347 protected void assertContainProjection(Uri uri, String[] mustHaveProjection) { 1348 Cursor cursor = mResolver.query(uri, null, "0", null, null); 1349 String[] actualProjection = cursor.getColumnNames(); 1350 Set<String> actualProjectionSet = Sets.newHashSet(actualProjection); 1351 Set<String> mustHaveProjectionSet = Sets.newHashSet(mustHaveProjection); 1352 actualProjectionSet.retainAll(mustHaveProjectionSet); 1353 MoreAsserts.assertEquals(mustHaveProjectionSet, actualProjectionSet); 1354 cursor.close(); 1355 } 1356 assertRowCount(int expectedCount, Uri uri, String selection, String[] args)1357 protected void assertRowCount(int expectedCount, Uri uri, String selection, String[] args) { 1358 Cursor cursor = mResolver.query(uri, null, selection, args, null); 1359 1360 try { 1361 assertEquals(expectedCount, cursor.getCount()); 1362 } catch (Error e) { 1363 TestUtils.dumpCursor(cursor); 1364 throw e; 1365 } finally { 1366 cursor.close(); 1367 } 1368 } 1369 assertLastModified(Uri uri, long time)1370 protected void assertLastModified(Uri uri, long time) { 1371 Cursor c = mResolver.query(uri, null, null, null, null); 1372 c.moveToFirst(); 1373 int index = c.getColumnIndex(CallLog.Calls.LAST_MODIFIED); 1374 long timeStamp = c.getLong(index); 1375 assertEquals(timeStamp, time); 1376 } 1377 setTimeForTest(Long time)1378 protected void setTimeForTest(Long time) { 1379 Uri uri = Calls.CONTENT_URI.buildUpon() 1380 .appendQueryParameter(CallLogProvider.PARAM_KEY_QUERY_FOR_TESTING, "1") 1381 .appendQueryParameter(CallLogProvider.PARAM_KEY_SET_TIME_FOR_TESTING, 1382 time == null ? "null" : time.toString()) 1383 .build(); 1384 mResolver.query(uri, null, null, null, null); 1385 } 1386 insertRawContact(ContentValues values)1387 protected Uri insertRawContact(ContentValues values) { 1388 return TestUtils.insertRawContact(mResolver, 1389 getContactsProvider().getDatabaseHelper(), values); 1390 } 1391 insertProfileRawContact(ContentValues values)1392 protected Uri insertProfileRawContact(ContentValues values) { 1393 return TestUtils.insertProfileRawContact(mResolver, 1394 getContactsProvider().getProfileProviderForTest().getDatabaseHelper(), values); 1395 } 1396 1397 /** 1398 * A contact in the database, and the attributes used to create it. Construct using 1399 * {@link GoldenContactBuilder#build()}. 1400 */ 1401 public final class GoldenContact { 1402 1403 private final long rawContactId; 1404 1405 private final long contactId; 1406 1407 private final String givenName; 1408 1409 private final String familyName; 1410 1411 private final String nickname; 1412 1413 private final byte[] photo; 1414 1415 private final String company; 1416 1417 private final String title; 1418 1419 private final String phone; 1420 1421 private final String email; 1422 GoldenContact(GoldenContactBuilder builder, long rawContactId, long contactId)1423 private GoldenContact(GoldenContactBuilder builder, long rawContactId, long contactId) { 1424 1425 this.rawContactId = rawContactId; 1426 this.contactId = contactId; 1427 givenName = builder.givenName; 1428 familyName = builder.familyName; 1429 nickname = builder.nickname; 1430 photo = builder.photo; 1431 company = builder.company; 1432 title = builder.title; 1433 phone = builder.phone; 1434 email = builder.email; 1435 } 1436 delete()1437 public void delete() { 1438 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 1439 mResolver.delete(rawContactUri, null, null); 1440 } 1441 1442 /** 1443 * Returns the index of the contact in table "raw_contacts" 1444 */ getRawContactId()1445 public long getRawContactId() { 1446 return rawContactId; 1447 } 1448 1449 /** 1450 * Returns the index of the contact in table "contacts" 1451 */ getContactId()1452 public long getContactId() { 1453 return contactId; 1454 } 1455 1456 /** 1457 * Returns the lookup key for the contact. 1458 */ getLookupKey()1459 public String getLookupKey() { 1460 return queryLookupKey(contactId); 1461 } 1462 1463 /** 1464 * Returns the contact's given name. 1465 */ getGivenName()1466 public String getGivenName() { 1467 return givenName; 1468 } 1469 1470 /** 1471 * Returns the contact's family name. 1472 */ getFamilyName()1473 public String getFamilyName() { 1474 return familyName; 1475 } 1476 1477 /** 1478 * Returns the contact's nickname. 1479 */ getNickname()1480 public String getNickname() { 1481 return nickname; 1482 } 1483 1484 /** 1485 * Return's the contact's photo 1486 */ getPhoto()1487 public byte[] getPhoto() { 1488 return photo; 1489 } 1490 1491 /** 1492 * Return's the company at which the contact works. 1493 */ getCompany()1494 public String getCompany() { 1495 return company; 1496 } 1497 1498 /** 1499 * Returns the contact's job title. 1500 */ getTitle()1501 public String getTitle() { 1502 return title; 1503 } 1504 1505 /** 1506 * Returns the contact's phone number 1507 */ getPhone()1508 public String getPhone() { 1509 return phone; 1510 } 1511 1512 /** 1513 * Returns the contact's email address 1514 */ getEmail()1515 public String getEmail() { 1516 return email; 1517 } 1518 } 1519 1520 /** 1521 * Builds {@link GoldenContact} objects. Unspecified boolean objects default to false. 1522 * Unspecified String objects default to null. 1523 */ 1524 public final class GoldenContactBuilder { 1525 1526 private String givenName; 1527 1528 private String familyName; 1529 1530 private String nickname; 1531 1532 private byte[] photo; 1533 1534 private String company; 1535 1536 private String title; 1537 1538 private String phone; 1539 1540 private String email; 1541 1542 /** 1543 * The contact's given and family names. 1544 * 1545 * TODO(dplotnikov): inline, or should we require them to set both names if they set either? 1546 */ name(String givenName, String familyName)1547 public GoldenContactBuilder name(String givenName, String familyName) { 1548 return givenName(givenName).familyName(familyName); 1549 } 1550 1551 /** 1552 * The contact's given name. 1553 */ givenName(String value)1554 public GoldenContactBuilder givenName(String value) { 1555 givenName = value; 1556 return this; 1557 } 1558 1559 /** 1560 * The contact's family name. 1561 */ familyName(String value)1562 public GoldenContactBuilder familyName(String value) { 1563 familyName = value; 1564 return this; 1565 } 1566 1567 /** 1568 * The contact's nickname. 1569 */ nickname(String value)1570 public GoldenContactBuilder nickname(String value) { 1571 nickname = value; 1572 return this; 1573 } 1574 1575 /** 1576 * The contact's photo. 1577 */ photo(byte[] value)1578 public GoldenContactBuilder photo(byte[] value) { 1579 photo = value; 1580 return this; 1581 } 1582 1583 /** 1584 * The company at which the contact works. 1585 */ company(String value)1586 public GoldenContactBuilder company(String value) { 1587 company = value; 1588 return this; 1589 } 1590 1591 /** 1592 * The contact's job title. 1593 */ title(String value)1594 public GoldenContactBuilder title(String value) { 1595 title = value; 1596 return this; 1597 } 1598 1599 /** 1600 * The contact's phone number. 1601 */ phone(String value)1602 public GoldenContactBuilder phone(String value) { 1603 phone = value; 1604 return this; 1605 } 1606 1607 /** 1608 * The contact's email address; also sets their IM status to {@link StatusUpdates#OFFLINE} 1609 * with a presence of "Coding for Android". 1610 */ email(String value)1611 public GoldenContactBuilder email(String value) { 1612 email = value; 1613 return this; 1614 } 1615 1616 /** 1617 * Builds the {@link GoldenContact} specified by this builder. 1618 */ build()1619 public GoldenContact build() { 1620 1621 final long groupId = createGroup(mAccount, "gsid1", "title1"); 1622 1623 long rawContactId = RawContactUtil.createRawContact(mResolver); 1624 insertGroupMembership(rawContactId, groupId); 1625 1626 if (givenName != null || familyName != null) { 1627 DataUtil.insertStructuredName(mResolver, rawContactId, givenName, familyName); 1628 } 1629 if (nickname != null) { 1630 insertNickname(rawContactId, nickname); 1631 } 1632 if (photo != null) { 1633 insertPhoto(rawContactId); 1634 } 1635 if (company != null || title != null) { 1636 insertOrganization(rawContactId); 1637 } 1638 if (email != null) { 1639 insertEmail(rawContactId); 1640 } 1641 if (phone != null) { 1642 insertPhone(rawContactId); 1643 } 1644 1645 long contactId = queryContactId(rawContactId); 1646 1647 return new GoldenContact(this, rawContactId, contactId); 1648 } 1649 insertPhoto(long rawContactId)1650 private void insertPhoto(long rawContactId) { 1651 ContentValues values = new ContentValues(); 1652 values.put(Data.RAW_CONTACT_ID, rawContactId); 1653 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 1654 values.put(Photo.PHOTO, photo); 1655 mResolver.insert(Data.CONTENT_URI, values); 1656 } 1657 insertOrganization(long rawContactId)1658 private void insertOrganization(long rawContactId) { 1659 1660 ContentValues values = new ContentValues(); 1661 values.put(Data.RAW_CONTACT_ID, rawContactId); 1662 values.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE); 1663 values.put(Organization.TYPE, Organization.TYPE_WORK); 1664 if (company != null) { 1665 values.put(Organization.COMPANY, company); 1666 } 1667 if (title != null) { 1668 values.put(Organization.TITLE, title); 1669 } 1670 mResolver.insert(Data.CONTENT_URI, values); 1671 } 1672 insertEmail(long rawContactId)1673 private void insertEmail(long rawContactId) { 1674 1675 ContentValues values = new ContentValues(); 1676 values.put(Data.RAW_CONTACT_ID, rawContactId); 1677 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 1678 values.put(Email.TYPE, Email.TYPE_WORK); 1679 values.put(Email.DATA, "foo@acme.com"); 1680 mResolver.insert(Data.CONTENT_URI, values); 1681 1682 int protocol = Im.PROTOCOL_GOOGLE_TALK; 1683 1684 values.clear(); 1685 values.put(StatusUpdates.PROTOCOL, protocol); 1686 values.put(StatusUpdates.IM_HANDLE, email); 1687 values.put(StatusUpdates.IM_ACCOUNT, "foo"); 1688 values.put(StatusUpdates.PRESENCE_STATUS, StatusUpdates.OFFLINE); 1689 values.put(StatusUpdates.CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 1690 values.put(StatusUpdates.PRESENCE_CUSTOM_STATUS, "Coding for Android"); 1691 mResolver.insert(StatusUpdates.CONTENT_URI, values); 1692 } 1693 insertPhone(long rawContactId)1694 private void insertPhone(long rawContactId) { 1695 ContentValues values = new ContentValues(); 1696 values.put(Data.RAW_CONTACT_ID, rawContactId); 1697 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1698 values.put(Data.IS_PRIMARY, 1); 1699 values.put(Phone.TYPE, Phone.TYPE_HOME); 1700 values.put(Phone.NUMBER, phone); 1701 mResolver.insert(Data.CONTENT_URI, values); 1702 } 1703 } 1704 } 1705