ContactsProvider2Test.java revision e3e79030101447da07547647bad225686eb9b8df
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.providers.contacts; 18 19import com.android.internal.util.ArrayUtils; 20import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 21import com.google.android.collect.Lists; 22 23import android.accounts.Account; 24import android.content.ContentProviderOperation; 25import android.content.ContentProviderResult; 26import android.content.ContentUris; 27import android.content.ContentValues; 28import android.content.Entity; 29import android.content.EntityIterator; 30import android.content.res.AssetFileDescriptor; 31import android.database.Cursor; 32import android.net.Uri; 33import android.os.RemoteException; 34import android.provider.ContactsContract; 35import android.provider.LiveFolders; 36import android.provider.OpenableColumns; 37import android.provider.ContactsContract.AggregationExceptions; 38import android.provider.ContactsContract.ContactCounts; 39import android.provider.ContactsContract.Contacts; 40import android.provider.ContactsContract.Data; 41import android.provider.ContactsContract.DisplayNameSources; 42import android.provider.ContactsContract.Groups; 43import android.provider.ContactsContract.PhoneLookup; 44import android.provider.ContactsContract.PhoneticNameStyle; 45import android.provider.ContactsContract.ProviderStatus; 46import android.provider.ContactsContract.RawContacts; 47import android.provider.ContactsContract.RawContactsEntity; 48import android.provider.ContactsContract.SearchSnippetColumns; 49import android.provider.ContactsContract.Settings; 50import android.provider.ContactsContract.StatusUpdates; 51import android.provider.ContactsContract.CommonDataKinds.Email; 52import android.provider.ContactsContract.CommonDataKinds.GroupMembership; 53import android.provider.ContactsContract.CommonDataKinds.Im; 54import android.provider.ContactsContract.CommonDataKinds.Nickname; 55import android.provider.ContactsContract.CommonDataKinds.Organization; 56import android.provider.ContactsContract.CommonDataKinds.Phone; 57import android.provider.ContactsContract.CommonDataKinds.Photo; 58import android.provider.ContactsContract.CommonDataKinds.StructuredName; 59import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 60import android.test.MoreAsserts; 61import android.test.suitebuilder.annotation.LargeTest; 62 63import java.io.FileInputStream; 64import java.io.IOException; 65import java.text.Collator; 66import java.util.Arrays; 67import java.util.Locale; 68 69 70/** 71 * Unit tests for {@link ContactsProvider2}. 72 * 73 * Run the test like this: 74 * <code> 75 * adb shell am instrument -e class com.android.providers.contacts.ContactsProvider2Test -w \ 76 * com.android.providers.contacts.tests/android.test.InstrumentationTestRunner 77 * </code> 78 */ 79@LargeTest 80public class ContactsProvider2Test extends BaseContactsProvider2Test { 81 82 public void testRawContactsInsert() { 83 ContentValues values = new ContentValues(); 84 85 values.put(RawContacts.ACCOUNT_NAME, "a"); 86 values.put(RawContacts.ACCOUNT_TYPE, "b"); 87 values.put(RawContacts.SOURCE_ID, "c"); 88 values.put(RawContacts.VERSION, 42); 89 values.put(RawContacts.DIRTY, 1); 90 values.put(RawContacts.DELETED, 1); 91 values.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 92 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 93 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 94 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 95 values.put(RawContacts.STARRED, 1); 96 values.put(RawContacts.SYNC1, "e"); 97 values.put(RawContacts.SYNC2, "f"); 98 values.put(RawContacts.SYNC3, "g"); 99 values.put(RawContacts.SYNC4, "h"); 100 101 Uri rowUri = mResolver.insert(RawContacts.CONTENT_URI, values); 102 long rawContactId = ContentUris.parseId(rowUri); 103 104 assertStoredValues(rowUri, values); 105 assertSelection(RawContacts.CONTENT_URI, values, RawContacts._ID, rawContactId); 106 assertNetworkNotified(true); 107 } 108 109 public void testDataDirectoryWithLookupUri() { 110 ContentValues values = new ContentValues(); 111 112 long rawContactId = createRawContactWithName(); 113 insertPhoneNumber(rawContactId, "555-GOOG-411"); 114 insertEmail(rawContactId, "google@android.com"); 115 116 long contactId = queryContactId(rawContactId); 117 String lookupKey = queryLookupKey(contactId); 118 119 // Complete and valid lookup URI 120 Uri lookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey); 121 Uri dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY); 122 123 assertDataRows(dataUri, values); 124 125 // Complete but stale lookup URI 126 lookupUri = ContactsContract.Contacts.getLookupUri(contactId + 1, lookupKey); 127 dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY); 128 assertDataRows(dataUri, values); 129 130 // Incomplete lookup URI (lookup key only, no contact ID) 131 dataUri = Uri.withAppendedPath(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, 132 lookupKey), Contacts.Data.CONTENT_DIRECTORY); 133 assertDataRows(dataUri, values); 134 } 135 136 private void assertDataRows(Uri dataUri, ContentValues values) { 137 Cursor cursor = mResolver.query(dataUri, new String[]{ Data.DATA1 }, null, null, Data._ID); 138 assertEquals(3, cursor.getCount()); 139 cursor.moveToFirst(); 140 values.put(Data.DATA1, "John Doe"); 141 assertCursorValues(cursor, values); 142 143 cursor.moveToNext(); 144 values.put(Data.DATA1, "555-GOOG-411"); 145 assertCursorValues(cursor, values); 146 147 cursor.moveToNext(); 148 values.put(Data.DATA1, "google@android.com"); 149 assertCursorValues(cursor, values); 150 151 cursor.close(); 152 } 153 154 public void testDataInsert() { 155 long rawContactId = createRawContactWithName("John", "Doe"); 156 157 ContentValues values = new ContentValues(); 158 putDataValues(values, rawContactId); 159 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 160 long dataId = ContentUris.parseId(dataUri); 161 162 long contactId = queryContactId(rawContactId); 163 values.put(RawContacts.CONTACT_ID, contactId); 164 assertStoredValues(dataUri, values); 165 166 assertSelection(Data.CONTENT_URI, values, Data._ID, dataId); 167 168 // Access the same data through the directory under RawContacts 169 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 170 Uri rawContactDataUri = 171 Uri.withAppendedPath(rawContactUri, RawContacts.Data.CONTENT_DIRECTORY); 172 assertSelection(rawContactDataUri, values, Data._ID, dataId); 173 174 // Access the same data through the directory under Contacts 175 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 176 Uri contactDataUri = Uri.withAppendedPath(contactUri, Contacts.Data.CONTENT_DIRECTORY); 177 assertSelection(contactDataUri, values, Data._ID, dataId); 178 assertNetworkNotified(true); 179 } 180 181 public void testRawContactDataQuery() { 182 Account account1 = new Account("a", "b"); 183 Account account2 = new Account("c", "d"); 184 long rawContactId1 = createRawContact(account1); 185 Uri dataUri1 = insertStructuredName(rawContactId1, "John", "Doe"); 186 long rawContactId2 = createRawContact(account2); 187 Uri dataUri2 = insertStructuredName(rawContactId2, "Jane", "Doe"); 188 189 Uri uri1 = maybeAddAccountQueryParameters(dataUri1, account1); 190 Uri uri2 = maybeAddAccountQueryParameters(dataUri2, account2); 191 assertStoredValue(uri1, Data._ID, ContentUris.parseId(dataUri1)) ; 192 assertStoredValue(uri2, Data._ID, ContentUris.parseId(dataUri2)) ; 193 } 194 195 public void testPhonesQuery() { 196 197 ContentValues values = new ContentValues(); 198 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 199 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 200 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 201 values.put(RawContacts.TIMES_CONTACTED, 54321); 202 values.put(RawContacts.STARRED, 1); 203 204 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 205 long rawContactId = ContentUris.parseId(rawContactUri); 206 207 insertStructuredName(rawContactId, "Meghan", "Knox"); 208 Uri uri = insertPhoneNumber(rawContactId, "18004664411"); 209 long phoneId = ContentUris.parseId(uri); 210 211 212 long contactId = queryContactId(rawContactId); 213 values.clear(); 214 values.put(Data._ID, phoneId); 215 values.put(Data.RAW_CONTACT_ID, rawContactId); 216 values.put(RawContacts.CONTACT_ID, contactId); 217 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 218 values.put(Phone.NUMBER, "18004664411"); 219 values.put(Phone.TYPE, Phone.TYPE_HOME); 220 values.putNull(Phone.LABEL); 221 values.put(Contacts.DISPLAY_NAME, "Meghan Knox"); 222 values.put(Contacts.CUSTOM_RINGTONE, "d"); 223 values.put(Contacts.SEND_TO_VOICEMAIL, 1); 224 values.put(Contacts.LAST_TIME_CONTACTED, 12345); 225 values.put(Contacts.TIMES_CONTACTED, 54321); 226 values.put(Contacts.STARRED, 1); 227 228 assertStoredValues(ContentUris.withAppendedId(Phone.CONTENT_URI, phoneId), values); 229 assertSelection(Phone.CONTENT_URI, values, Data._ID, phoneId); 230 } 231 232 public void testPhonesFilterQuery() { 233 long rawContactId1 = createRawContactWithName("Hot", "Tamale"); 234 insertPhoneNumber(rawContactId1, "18004664411"); 235 insertPhoneNumber(rawContactId1, "1-800-466-4411"); 236 237 long rawContactId2 = createRawContactWithName("Hot", "Tamale"); 238 insertPhoneNumber(rawContactId2, "1-800-466-4411"); 239 240 Uri filterUri1 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "tamale"); 241 ContentValues values = new ContentValues(); 242 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 243 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 244 values.put(Phone.NUMBER, "1-800-466-4411"); 245 values.put(Phone.TYPE, Phone.TYPE_HOME); 246 values.putNull(Phone.LABEL); 247 assertStoredValuesWithProjection(filterUri1, values); 248 249 Uri filterUri2 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "1-800-GOOG-411"); 250 assertStoredValues(filterUri2, values); 251 252 Uri filterUri3 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "18004664"); 253 assertStoredValues(filterUri3, values); 254 255 Uri filterUri4 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "encilada"); 256 assertEquals(0, getCount(filterUri4, null, null)); 257 258 Uri filterUri5 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "*"); 259 assertEquals(0, getCount(filterUri5, null, null)); 260 } 261 262 public void testPhoneLookup() { 263 ContentValues values = new ContentValues(); 264 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 265 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 266 267 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 268 long rawContactId = ContentUris.parseId(rawContactUri); 269 270 insertStructuredName(rawContactId, "Hot", "Tamale"); 271 insertPhoneNumber(rawContactId, "18004664411"); 272 273 Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411"); 274 275 values.clear(); 276 values.put(PhoneLookup._ID, queryContactId(rawContactId)); 277 values.put(PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 278 values.put(PhoneLookup.NUMBER, "18004664411"); 279 values.put(PhoneLookup.TYPE, Phone.TYPE_HOME); 280 values.putNull(PhoneLookup.LABEL); 281 values.put(PhoneLookup.CUSTOM_RINGTONE, "d"); 282 values.put(PhoneLookup.SEND_TO_VOICEMAIL, 1); 283 assertStoredValues(lookupUri1, values); 284 285 // The strict comparation, adopted in Donut, does not allow the behavior like 286 // "8004664411 == 4664411", while the loose comparation, which had been used in Cupcake 287 // and reverted back into the default in Eclair, allows it. Hmm... 288 final boolean useStrictComparation = 289 mContext.getResources().getBoolean( 290 com.android.internal.R.bool.config_use_strict_phone_number_comparation); 291 final int expectedResult = (useStrictComparation ? 0 : 1); 292 293 Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "4664411"); 294 assertEquals(expectedResult, getCount(lookupUri2, null, null)); 295 } 296 297 public void testPhoneUpdate() { 298 ContentValues values = new ContentValues(); 299 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 300 long rawContactId = ContentUris.parseId(rawContactUri); 301 302 insertStructuredName(rawContactId, "Hot", "Tamale"); 303 Uri phoneUri = insertPhoneNumber(rawContactId, "18004664411"); 304 305 Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411"); 306 assertStoredValue(lookupUri1, PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 307 308 values.clear(); 309 values.put(Phone.NUMBER, "18004664422"); 310 mResolver.update(phoneUri, values, null, null); 311 312 Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664422"); 313 assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 314 315 // Setting number to null will remove the phone lookup record 316 values.clear(); 317 values.putNull(Phone.NUMBER); 318 mResolver.update(phoneUri, values, null, null); 319 320 assertEquals(0, getCount(lookupUri2, null, null)); 321 322 // Let's restore that phone lookup record 323 values.clear(); 324 values.put(Phone.NUMBER, "18004664422"); 325 mResolver.update(phoneUri, values, null, null); 326 assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 327 assertNetworkNotified(true); 328 } 329 330 public void testEmailsQuery() { 331 ContentValues values = new ContentValues(); 332 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 333 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 334 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 335 values.put(RawContacts.TIMES_CONTACTED, 54321); 336 values.put(RawContacts.STARRED, 1); 337 338 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 339 long rawContactId = ContentUris.parseId(rawContactUri); 340 341 insertStructuredName(rawContactId, "Meghan", "Knox"); 342 Uri uri = insertEmail(rawContactId, "meghan@acme.com"); 343 long emailId = ContentUris.parseId(uri); 344 345 long contactId = queryContactId(rawContactId); 346 values.clear(); 347 values.put(Data._ID, emailId); 348 values.put(Data.RAW_CONTACT_ID, rawContactId); 349 values.put(RawContacts.CONTACT_ID, contactId); 350 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 351 values.put(Email.DATA, "meghan@acme.com"); 352 values.put(Email.TYPE, Email.TYPE_HOME); 353 values.putNull(Email.LABEL); 354 values.put(Contacts.DISPLAY_NAME, "Meghan Knox"); 355 values.put(Contacts.CUSTOM_RINGTONE, "d"); 356 values.put(Contacts.SEND_TO_VOICEMAIL, 1); 357 values.put(Contacts.LAST_TIME_CONTACTED, 12345); 358 values.put(Contacts.TIMES_CONTACTED, 54321); 359 values.put(Contacts.STARRED, 1); 360 361 assertStoredValues(ContentUris.withAppendedId(Email.CONTENT_URI, emailId), values); 362 assertSelection(Email.CONTENT_URI, values, Data._ID, emailId); 363 } 364 365 public void testEmailsLookupQuery() { 366 long rawContactId = createRawContactWithName("Hot", "Tamale"); 367 insertEmail(rawContactId, "tamale@acme.com"); 368 369 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "tamale@acme.com"); 370 ContentValues values = new ContentValues(); 371 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 372 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 373 values.put(Email.DATA, "tamale@acme.com"); 374 values.put(Email.TYPE, Email.TYPE_HOME); 375 values.putNull(Email.LABEL); 376 assertStoredValues(filterUri1, values); 377 378 Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "Ta<TaMale@acme.com>"); 379 assertStoredValues(filterUri2, values); 380 381 Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "encilada@acme.com"); 382 assertEquals(0, getCount(filterUri3, null, null)); 383 } 384 385 public void testEmailsFilterQuery() { 386 long rawContactId1 = createRawContactWithName("Hot", "Tamale"); 387 insertEmail(rawContactId1, "tamale@acme.com"); 388 insertEmail(rawContactId1, "tamale@acme.com"); 389 390 long rawContactId2 = createRawContactWithName("Hot", "Tamale"); 391 insertEmail(rawContactId2, "tamale@acme.com"); 392 393 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tam"); 394 ContentValues values = new ContentValues(); 395 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 396 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 397 values.put(Email.DATA, "tamale@acme.com"); 398 values.put(Email.TYPE, Email.TYPE_HOME); 399 values.putNull(Email.LABEL); 400 assertStoredValuesWithProjection(filterUri1, values); 401 402 Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hot"); 403 assertStoredValuesWithProjection(filterUri2, values); 404 405 Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hottamale"); 406 assertStoredValuesWithProjection(filterUri3, values); 407 408 Uri filterUri4 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tamale@acme"); 409 assertStoredValuesWithProjection(filterUri4, values); 410 411 Uri filterUri5 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "encilada"); 412 assertEquals(0, getCount(filterUri5, null, null)); 413 } 414 415 public void testPostalsQuery() { 416 long rawContactId = createRawContactWithName("Alice", "Nextore"); 417 Uri dataUri = insertPostalAddress(rawContactId, "1600 Amphiteatre Ave, Mountain View"); 418 long dataId = ContentUris.parseId(dataUri); 419 420 long contactId = queryContactId(rawContactId); 421 ContentValues values = new ContentValues(); 422 values.put(Data._ID, dataId); 423 values.put(Data.RAW_CONTACT_ID, rawContactId); 424 values.put(RawContacts.CONTACT_ID, contactId); 425 values.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE); 426 values.put(StructuredPostal.FORMATTED_ADDRESS, "1600 Amphiteatre Ave, Mountain View"); 427 values.put(Contacts.DISPLAY_NAME, "Alice Nextore"); 428 429 assertStoredValues(ContentUris.withAppendedId(StructuredPostal.CONTENT_URI, dataId), 430 values); 431 assertSelection(StructuredPostal.CONTENT_URI, values, Data._ID, dataId); 432 } 433 434 public void testQueryContactData() { 435 ContentValues values = new ContentValues(); 436 long contactId = createContact(values, "John", "Doe", 437 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0); 438 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 439 440 assertStoredValues(contactUri, values); 441 assertSelection(Contacts.CONTENT_URI, values, Contacts._ID, contactId); 442 } 443 444 public void testQueryContactWithStatusUpdate() { 445 ContentValues values = new ContentValues(); 446 long contactId = createContact(values, "John", "Doe", 447 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0); 448 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 449 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 450 assertStoredValuesWithProjection(contactUri, values); 451 assertSelectionWithProjection(Contacts.CONTENT_URI, values, Contacts._ID, contactId); 452 } 453 454 public void testQueryContactFilter() { 455 ContentValues values = new ContentValues(); 456 long rawContactId = createRawContact(values, "18004664411", 457 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0); 458 459 ContentValues nameValues = new ContentValues(); 460 nameValues.put(StructuredName.GIVEN_NAME, "Stu"); 461 nameValues.put(StructuredName.FAMILY_NAME, "Goulash"); 462 nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "goo"); 463 nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "LASH"); 464 Uri nameUri = insertStructuredName(rawContactId, nameValues); 465 466 long contactId = queryContactId(rawContactId); 467 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 468 469 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goulash"); 470 assertStoredValuesWithProjection(filterUri1, values); 471 472 assertContactFilter(contactId, "goolash"); 473 assertContactFilter(contactId, "lash"); 474 475 Uri filterUri2 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goolish"); 476 assertEquals(0, getCount(filterUri2, null, null)); 477 478 // Phonetic name with given/family reversed should not match 479 Uri filterUri3 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "lashgoo"); 480 assertEquals(0, getCount(filterUri3, null, null)); 481 482 nameValues.clear(); 483 nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "ga"); 484 nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "losh"); 485 486 mResolver.update(nameUri, nameValues, null, null); 487 488 assertContactFilter(contactId, "galosh"); 489 490 Uri filterUri4 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goolish"); 491 assertEquals(0, getCount(filterUri4, null, null)); 492 } 493 494 public void testQueryContactStrequent() { 495 ContentValues values1 = new ContentValues(); 496 createContact(values1, "Noah", "Tever", "18004664411", 497 "a@acme.com", StatusUpdates.OFFLINE, 0, 0, 0); 498 ContentValues values2 = new ContentValues(); 499 createContact(values2, "Sam", "Times", "18004664412", 500 "b@acme.com", StatusUpdates.INVISIBLE, 3, 0, 0); 501 ContentValues values3 = new ContentValues(); 502 createContact(values3, "Lotta", "Calling", "18004664413", 503 "c@acme.com", StatusUpdates.AWAY, 5, 0, 0); 504 ContentValues values4 = new ContentValues(); 505 createContact(values4, "Fay", "Veritt", "18004664414", 506 "d@acme.com", StatusUpdates.AVAILABLE, 0, 1, 0); 507 508 Cursor c = mResolver.query(Contacts.CONTENT_STREQUENT_URI, null, null, null, 509 Contacts._ID); 510 assertEquals(3, c.getCount()); 511 c.moveToFirst(); 512 assertCursorValues(c, values4); 513 c.moveToNext(); 514 assertCursorValues(c, values3); 515 c.moveToNext(); 516 assertCursorValues(c, values2); 517 c.close(); 518 519 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_STREQUENT_FILTER_URI, "fay"); 520 c = mResolver.query(filterUri, null, null, null, Contacts._ID); 521 assertEquals(1, c.getCount()); 522 c.moveToFirst(); 523 assertCursorValues(c, values4); 524 c.close(); 525 } 526 527 public void testQueryContactGroup() { 528 long groupId = createGroup(null, "testGroup", "Test Group"); 529 530 ContentValues values1 = new ContentValues(); 531 createContact(values1, "Best", "West", "18004664411", 532 "west@acme.com", StatusUpdates.OFFLINE, 0, 0, groupId); 533 534 ContentValues values2 = new ContentValues(); 535 createContact(values2, "Rest", "East", "18004664422", 536 "east@acme.com", StatusUpdates.AVAILABLE, 0, 0, 0); 537 538 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group"); 539 Cursor c = mResolver.query(filterUri1, null, null, null, Contacts._ID); 540 assertEquals(1, c.getCount()); 541 c.moveToFirst(); 542 assertCursorValues(c, values1); 543 c.close(); 544 545 Uri filterUri2 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group"); 546 c = mResolver.query(filterUri2, null, Contacts.DISPLAY_NAME + "=?", 547 new String[] { "Best West" }, Contacts._ID); 548 assertEquals(1, c.getCount()); 549 c.close(); 550 551 Uri filterUri3 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Next Group"); 552 c = mResolver.query(filterUri3, null, null, null, Contacts._ID); 553 assertEquals(0, c.getCount()); 554 c.close(); 555 } 556 557 public void testPhonesWithStatusUpdate() { 558 559 ContentValues values = new ContentValues(); 560 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 561 long rawContactId = ContentUris.parseId(rawContactUri); 562 insertStructuredName(rawContactId, "John", "Doe"); 563 Uri photoUri = insertPhoto(rawContactId); 564 long photoId = ContentUris.parseId(photoUri); 565 values.put(Contacts.PHOTO_ID, photoId); 566 insertPhoneNumber(rawContactId, "18004664411"); 567 insertPhoneNumber(rawContactId, "18004664412"); 568 insertEmail(rawContactId, "goog411@acme.com"); 569 insertEmail(rawContactId, "goog412@acme.com"); 570 571 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog411@acme.com", 572 StatusUpdates.INVISIBLE, "Bad"); 573 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog412@acme.com", 574 StatusUpdates.AVAILABLE, "Good"); 575 long contactId = queryContactId(rawContactId); 576 577 Uri uri = Data.CONTENT_URI; 578 579 Cursor c = mResolver.query(uri, null, RawContacts.CONTACT_ID + "=" + contactId + " AND " 580 + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'", null, Phone.NUMBER); 581 assertEquals(2, c.getCount()); 582 583 c.moveToFirst(); 584 585 values.clear(); 586 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 587 values.put(Contacts.CONTACT_STATUS, "Bad"); 588 values.put(Contacts.DISPLAY_NAME, "John Doe"); 589 values.put(Phone.NUMBER, "18004664411"); 590 values.putNull(Phone.LABEL); 591 values.put(RawContacts.CONTACT_ID, contactId); 592 assertCursorValues(c, values); 593 594 c.moveToNext(); 595 596 values.clear(); 597 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 598 values.put(Contacts.CONTACT_STATUS, "Bad"); 599 values.put(Contacts.DISPLAY_NAME, "John Doe"); 600 values.put(Phone.NUMBER, "18004664412"); 601 values.putNull(Phone.LABEL); 602 values.put(RawContacts.CONTACT_ID, contactId); 603 assertCursorValues(c, values); 604 605 c.close(); 606 } 607 608 public void testGroupQuery() { 609 Account account1 = new Account("a", "b"); 610 Account account2 = new Account("c", "d"); 611 long groupId1 = createGroup(account1, "e", "f"); 612 long groupId2 = createGroup(account2, "g", "h"); 613 Uri uri1 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account1); 614 Uri uri2 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account2); 615 assertEquals(1, getCount(uri1, null, null)); 616 assertEquals(1, getCount(uri2, null, null)); 617 assertStoredValue(uri1, Groups._ID + "=" + groupId1, null, Groups._ID, groupId1) ; 618 assertStoredValue(uri2, Groups._ID + "=" + groupId2, null, Groups._ID, groupId2) ; 619 } 620 621 public void testGroupInsert() { 622 ContentValues values = new ContentValues(); 623 624 values.put(Groups.ACCOUNT_NAME, "a"); 625 values.put(Groups.ACCOUNT_TYPE, "b"); 626 values.put(Groups.SOURCE_ID, "c"); 627 values.put(Groups.VERSION, 42); 628 values.put(Groups.GROUP_VISIBLE, 1); 629 values.put(Groups.TITLE, "d"); 630 values.put(Groups.TITLE_RES, 1234); 631 values.put(Groups.NOTES, "e"); 632 values.put(Groups.RES_PACKAGE, "f"); 633 values.put(Groups.SYSTEM_ID, "g"); 634 values.put(Groups.DELETED, 1); 635 values.put(Groups.SYNC1, "h"); 636 values.put(Groups.SYNC2, "i"); 637 values.put(Groups.SYNC3, "j"); 638 values.put(Groups.SYNC4, "k"); 639 640 Uri rowUri = mResolver.insert(Groups.CONTENT_URI, values); 641 642 values.put(Groups.DIRTY, 1); 643 assertStoredValues(rowUri, values); 644 } 645 646 public void testSettingsQuery() { 647 Account account1 = new Account("a", "b"); 648 Account account2 = new Account("c", "d"); 649 createSettings(account1, "0", "0"); 650 createSettings(account2, "1", "1"); 651 Uri uri1 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account1); 652 Uri uri2 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account2); 653 assertEquals(1, getCount(uri1, null, null)); 654 assertEquals(1, getCount(uri2, null, null)); 655 assertStoredValue(uri1, Settings.SHOULD_SYNC, "0") ; 656 assertStoredValue(uri1, Settings.UNGROUPED_VISIBLE, "0") ; 657 assertStoredValue(uri2, Settings.SHOULD_SYNC, "1") ; 658 assertStoredValue(uri2, Settings.UNGROUPED_VISIBLE, "1") ; 659 } 660 661 public void testDisplayNameParsingWhenPartsUnspecified() { 662 long rawContactId = createRawContact(); 663 ContentValues values = new ContentValues(); 664 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 665 insertStructuredName(rawContactId, values); 666 667 assertStructuredName(rawContactId, "Mr", "John", "Kevin", "von Smith", "Jr."); 668 } 669 670 public void testDisplayNameParsingWhenPartsAreNull() { 671 long rawContactId = createRawContact(); 672 ContentValues values = new ContentValues(); 673 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 674 values.putNull(StructuredName.GIVEN_NAME); 675 values.putNull(StructuredName.FAMILY_NAME); 676 insertStructuredName(rawContactId, values); 677 assertStructuredName(rawContactId, "Mr", "John", "Kevin", "von Smith", "Jr."); 678 } 679 680 public void testDisplayNameParsingWhenPartsSpecified() { 681 long rawContactId = createRawContact(); 682 ContentValues values = new ContentValues(); 683 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 684 values.put(StructuredName.FAMILY_NAME, "Johnson"); 685 insertStructuredName(rawContactId, values); 686 687 assertStructuredName(rawContactId, null, null, null, "Johnson", null); 688 } 689 690 public void testContactWithoutPhoneticName() { 691 final long rawContactId = createRawContact(null); 692 693 ContentValues values = new ContentValues(); 694 values.put(StructuredName.PREFIX, "Mr"); 695 values.put(StructuredName.GIVEN_NAME, "John"); 696 values.put(StructuredName.MIDDLE_NAME, "K."); 697 values.put(StructuredName.FAMILY_NAME, "Doe"); 698 values.put(StructuredName.SUFFIX, "Jr."); 699 Uri dataUri = insertStructuredName(rawContactId, values); 700 701 values.clear(); 702 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 703 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "John K. Doe, Jr."); 704 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "Doe, John K., Jr."); 705 values.putNull(RawContacts.PHONETIC_NAME); 706 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 707 values.put(RawContacts.SORT_KEY_PRIMARY, "John K. Doe, Jr."); 708 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "Doe, John K., Jr."); 709 710 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 711 assertStoredValues(rawContactUri, values); 712 713 values.clear(); 714 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 715 values.put(Contacts.DISPLAY_NAME_PRIMARY, "John K. Doe, Jr."); 716 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "Doe, John K., Jr."); 717 values.putNull(Contacts.PHONETIC_NAME); 718 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 719 values.put(Contacts.SORT_KEY_PRIMARY, "John K. Doe, Jr."); 720 values.put(Contacts.SORT_KEY_ALTERNATIVE, "Doe, John K., Jr."); 721 722 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 723 queryContactId(rawContactId)); 724 assertStoredValues(contactUri, values); 725 726 // The same values should be available through a join with Data 727 assertStoredValues(dataUri, values); 728 } 729 730 public void testContactWithChineseName() { 731 732 // Only run this test when Chinese collation is supported 733 if (!Arrays.asList(Collator.getAvailableLocales()).contains(Locale.CHINA)) { 734 return; 735 } 736 737 long rawContactId = createRawContact(null); 738 739 ContentValues values = new ContentValues(); 740 values.put(StructuredName.DISPLAY_NAME, "\u6BB5\u5C0F\u6D9B"); 741 Uri dataUri = insertStructuredName(rawContactId, values); 742 743 values.clear(); 744 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 745 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "\u6BB5\u5C0F\u6D9B"); 746 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B"); 747 values.putNull(RawContacts.PHONETIC_NAME); 748 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 749 values.put(RawContacts.SORT_KEY_PRIMARY, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 750 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 751 752 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 753 assertStoredValues(rawContactUri, values); 754 755 values.clear(); 756 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 757 values.put(Contacts.DISPLAY_NAME_PRIMARY, "\u6BB5\u5C0F\u6D9B"); 758 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B"); 759 values.putNull(Contacts.PHONETIC_NAME); 760 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 761 values.put(Contacts.SORT_KEY_PRIMARY, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 762 values.put(Contacts.SORT_KEY_ALTERNATIVE, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 763 764 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 765 queryContactId(rawContactId)); 766 assertStoredValues(contactUri, values); 767 768 // The same values should be available through a join with Data 769 assertStoredValues(dataUri, values); 770 } 771 772 public void testContactWithJapaneseName() { 773 long rawContactId = createRawContact(null); 774 775 ContentValues values = new ContentValues(); 776 values.put(StructuredName.GIVEN_NAME, "\u7A7A\u6D77"); 777 values.put(StructuredName.PHONETIC_GIVEN_NAME, "\u304B\u3044\u304F\u3046"); 778 Uri dataUri = insertStructuredName(rawContactId, values); 779 780 values.clear(); 781 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 782 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "\u7A7A\u6D77"); 783 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "\u7A7A\u6D77"); 784 values.put(RawContacts.PHONETIC_NAME, "\u304B\u3044\u304F\u3046"); 785 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 786 values.put(RawContacts.SORT_KEY_PRIMARY, "\u304B\u3044\u304F\u3046"); 787 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "\u304B\u3044\u304F\u3046"); 788 789 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 790 assertStoredValues(rawContactUri, values); 791 792 values.clear(); 793 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 794 values.put(Contacts.DISPLAY_NAME_PRIMARY, "\u7A7A\u6D77"); 795 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "\u7A7A\u6D77"); 796 values.put(Contacts.PHONETIC_NAME, "\u304B\u3044\u304F\u3046"); 797 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 798 values.put(Contacts.SORT_KEY_PRIMARY, "\u304B\u3044\u304F\u3046"); 799 values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u304B\u3044\u304F\u3046"); 800 801 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 802 queryContactId(rawContactId)); 803 assertStoredValues(contactUri, values); 804 805 // The same values should be available through a join with Data 806 assertStoredValues(dataUri, values); 807 } 808 809 public void testDisplayNameUpdate() { 810 long rawContactId1 = createRawContact(); 811 insertEmail(rawContactId1, "potato@acme.com", true); 812 813 long rawContactId2 = createRawContact(); 814 insertPhoneNumber(rawContactId2, "123456789", true); 815 816 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 817 rawContactId1, rawContactId2); 818 819 assertAggregated(rawContactId1, rawContactId2, "123456789"); 820 821 insertStructuredName(rawContactId2, "Potato", "Head"); 822 823 assertAggregated(rawContactId1, rawContactId2, "Potato Head"); 824 assertNetworkNotified(true); 825 } 826 827 public void testDisplayNameFromData() { 828 long rawContactId = createRawContact(); 829 long contactId = queryContactId(rawContactId); 830 ContentValues values = new ContentValues(); 831 832 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 833 834 assertStoredValue(uri, Contacts.DISPLAY_NAME, null); 835 insertEmail(rawContactId, "mike@monstersinc.com"); 836 assertStoredValue(uri, Contacts.DISPLAY_NAME, "mike@monstersinc.com"); 837 838 insertEmail(rawContactId, "james@monstersinc.com", true); 839 assertStoredValue(uri, Contacts.DISPLAY_NAME, "james@monstersinc.com"); 840 841 insertPhoneNumber(rawContactId, "1-800-466-4411"); 842 assertStoredValue(uri, Contacts.DISPLAY_NAME, "1-800-466-4411"); 843 844 // If there are title and company, the company is display name. 845 values.clear(); 846 values.put(Organization.COMPANY, "Monsters Inc"); 847 Uri organizationUri = insertOrganization(rawContactId, values); 848 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Monsters Inc"); 849 850 // If there is nickname, that is display name. 851 insertNickname(rawContactId, "Sully"); 852 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Sully"); 853 854 // If there is structured name, that is display name. 855 values.clear(); 856 values.put(StructuredName.GIVEN_NAME, "James"); 857 values.put(StructuredName.MIDDLE_NAME, "P."); 858 values.put(StructuredName.FAMILY_NAME, "Sullivan"); 859 insertStructuredName(rawContactId, values); 860 assertStoredValue(uri, Contacts.DISPLAY_NAME, "James P. Sullivan"); 861 } 862 863 public void testDisplayNameFromOrganizationWithoutPhoneticName() { 864 long rawContactId = createRawContact(); 865 long contactId = queryContactId(rawContactId); 866 ContentValues values = new ContentValues(); 867 868 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 869 870 // If there is title without company, the title is display name. 871 values.clear(); 872 values.put(Organization.TITLE, "Protagonist"); 873 Uri organizationUri = insertOrganization(rawContactId, values); 874 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Protagonist"); 875 876 // If there are title and company, the company is display name. 877 values.clear(); 878 values.put(Organization.COMPANY, "Monsters Inc"); 879 mResolver.update(organizationUri, values, null, null); 880 881 values.clear(); 882 values.put(Contacts.DISPLAY_NAME, "Monsters Inc"); 883 values.putNull(Contacts.PHONETIC_NAME); 884 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 885 values.put(Contacts.SORT_KEY_PRIMARY, "Monsters Inc"); 886 values.put(Contacts.SORT_KEY_ALTERNATIVE, "Monsters Inc"); 887 assertStoredValues(uri, values); 888 } 889 890 public void testDisplayNameFromOrganizationWithJapanesePhoneticName() { 891 long rawContactId = createRawContact(); 892 long contactId = queryContactId(rawContactId); 893 ContentValues values = new ContentValues(); 894 895 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 896 897 // If there is title without company, the title is display name. 898 values.clear(); 899 values.put(Organization.COMPANY, "DoCoMo"); 900 values.put(Organization.PHONETIC_NAME, "\u30C9\u30B3\u30E2"); 901 Uri organizationUri = insertOrganization(rawContactId, values); 902 903 values.clear(); 904 values.put(Contacts.DISPLAY_NAME, "DoCoMo"); 905 values.put(Contacts.PHONETIC_NAME, "\u30C9\u30B3\u30E2"); 906 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 907 values.put(Contacts.SORT_KEY_PRIMARY, "\u30C9\u30B3\u30E2"); 908 values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u30C9\u30B3\u30E2"); 909 assertStoredValues(uri, values); 910 } 911 912 public void testDisplayNameFromOrganizationWithChineseName() { 913 boolean hasChineseCollator = false; 914 final Locale locale[] = Collator.getAvailableLocales(); 915 for (int i = 0; i < locale.length; i++) { 916 if (locale[i].equals(Locale.CHINA)) { 917 hasChineseCollator = true; 918 break; 919 } 920 } 921 922 if (!hasChineseCollator) { 923 return; 924 } 925 926 long rawContactId = createRawContact(); 927 long contactId = queryContactId(rawContactId); 928 ContentValues values = new ContentValues(); 929 930 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 931 932 // If there is title without company, the title is display name. 933 values.clear(); 934 values.put(Organization.COMPANY, "\u4E2D\u56FD\u7535\u4FE1"); 935 Uri organizationUri = insertOrganization(rawContactId, values); 936 937 values.clear(); 938 values.put(Contacts.DISPLAY_NAME, "\u4E2D\u56FD\u7535\u4FE1"); 939 values.putNull(Contacts.PHONETIC_NAME); 940 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 941 values.put(Contacts.SORT_KEY_PRIMARY, "ZHONG \u4E2D GUO \u56FD DIAN \u7535 XIN \u4FE1"); 942 values.put(Contacts.SORT_KEY_ALTERNATIVE, "ZHONG \u4E2D GUO \u56FD DIAN \u7535 XIN \u4FE1"); 943 assertStoredValues(uri, values); 944 } 945 946 public void testLookupByOrganization() { 947 long rawContactId = createRawContact(); 948 long contactId = queryContactId(rawContactId); 949 ContentValues values = new ContentValues(); 950 951 values.clear(); 952 values.put(Organization.COMPANY, "acmecorp"); 953 values.put(Organization.TITLE, "president"); 954 Uri organizationUri = insertOrganization(rawContactId, values); 955 956 assertContactFilter(contactId, "acmecorp"); 957 assertContactFilter(contactId, "president"); 958 959 values.clear(); 960 values.put(Organization.DEPARTMENT, "software"); 961 mResolver.update(organizationUri, values, null, null); 962 963 assertContactFilter(contactId, "acmecorp"); 964 assertContactFilter(contactId, "president"); 965 966 values.clear(); 967 values.put(Organization.COMPANY, "incredibles"); 968 mResolver.update(organizationUri, values, null, null); 969 970 assertContactFilter(contactId, "incredibles"); 971 assertContactFilter(contactId, "president"); 972 973 values.clear(); 974 values.put(Organization.TITLE, "director"); 975 mResolver.update(organizationUri, values, null, null); 976 977 assertContactFilter(contactId, "incredibles"); 978 assertContactFilter(contactId, "director"); 979 980 values.clear(); 981 values.put(Organization.COMPANY, "monsters"); 982 values.put(Organization.TITLE, "scarer"); 983 mResolver.update(organizationUri, values, null, null); 984 985 assertContactFilter(contactId, "monsters"); 986 assertContactFilter(contactId, "scarer"); 987 } 988 989 private void assertContactFilter(long contactId, String filter) { 990 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(filter)); 991 assertStoredValue(filterUri, Contacts._ID, contactId); 992 } 993 994 public void testSearchSnippetOrganization() throws Exception { 995 long rawContactId = createRawContactWithName(); 996 long contactId = queryContactId(rawContactId); 997 998 // Some random data element 999 insertEmail(rawContactId, "inc@corp.com"); 1000 1001 ContentValues values = new ContentValues(); 1002 values.clear(); 1003 values.put(Organization.COMPANY, "acmecorp"); 1004 values.put(Organization.TITLE, "engineer"); 1005 Uri organizationUri = insertOrganization(rawContactId, values); 1006 1007 // Add another matching organization 1008 values.put(Organization.COMPANY, "acmeinc"); 1009 insertOrganization(rawContactId, values); 1010 1011 // Add another non-matching organization 1012 values.put(Organization.COMPANY, "corpacme"); 1013 insertOrganization(rawContactId, values); 1014 1015 // And another data element 1016 insertEmail(rawContactId, "emca@corp.com", true, Email.TYPE_CUSTOM, "Custom"); 1017 1018 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode("acme")); 1019 1020 values.clear(); 1021 values.put(Contacts._ID, contactId); 1022 values.put(SearchSnippetColumns.SNIPPET_DATA_ID, ContentUris.parseId(organizationUri)); 1023 values.put(SearchSnippetColumns.SNIPPET_DATA1, "acmecorp"); 1024 values.put(SearchSnippetColumns.SNIPPET_DATA4, "engineer"); 1025 values.put(SearchSnippetColumns.SNIPPET_MIMETYPE, Organization.CONTENT_ITEM_TYPE); 1026 assertStoredValues(filterUri, values); 1027 } 1028 1029 public void testSearchSnippetEmail() throws Exception { 1030 long rawContactId = createRawContact(); 1031 long contactId = queryContactId(rawContactId); 1032 ContentValues values = new ContentValues(); 1033 1034 Uri dataUri = insertEmail(rawContactId, "acme@corp.com", true, Email.TYPE_CUSTOM, "Custom"); 1035 1036 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode("acme")); 1037 1038 values.clear(); 1039 values.put(Contacts._ID, contactId); 1040 values.put(SearchSnippetColumns.SNIPPET_DATA1, "acme@corp.com"); 1041 values.put(SearchSnippetColumns.SNIPPET_DATA_ID, ContentUris.parseId(dataUri)); 1042 values.put(SearchSnippetColumns.SNIPPET_MIMETYPE, Email.CONTENT_ITEM_TYPE); 1043 values.put(SearchSnippetColumns.SNIPPET_DATA2, Email.TYPE_CUSTOM); 1044 values.put(SearchSnippetColumns.SNIPPET_DATA3, "Custom"); 1045 assertStoredValues(filterUri, values); 1046 } 1047 1048 public void testSearchSnippetNickname() throws Exception { 1049 long rawContactId = createRawContactWithName(); 1050 long contactId = queryContactId(rawContactId); 1051 ContentValues values = new ContentValues(); 1052 1053 Uri dataUri = insertNickname(rawContactId, "Incredible"); 1054 1055 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode("inc")); 1056 1057 values.clear(); 1058 values.put(Contacts._ID, contactId); 1059 values.put(SearchSnippetColumns.SNIPPET_DATA1, "Incredible"); 1060 values.put(SearchSnippetColumns.SNIPPET_DATA_ID, ContentUris.parseId(dataUri)); 1061 values.put(SearchSnippetColumns.SNIPPET_MIMETYPE, Nickname.CONTENT_ITEM_TYPE); 1062 assertStoredValues(filterUri, values); 1063 } 1064 1065 public void testDisplayNameUpdateFromStructuredNameUpdate() { 1066 long rawContactId = createRawContact(); 1067 Uri nameUri = insertStructuredName(rawContactId, "Slinky", "Dog"); 1068 1069 long contactId = queryContactId(rawContactId); 1070 1071 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1072 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky Dog"); 1073 1074 ContentValues values = new ContentValues(); 1075 values.putNull(StructuredName.FAMILY_NAME); 1076 1077 mResolver.update(nameUri, values, null, null); 1078 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky"); 1079 1080 values.putNull(StructuredName.GIVEN_NAME); 1081 1082 mResolver.update(nameUri, values, null, null); 1083 assertStoredValue(uri, Contacts.DISPLAY_NAME, null); 1084 1085 values.put(StructuredName.FAMILY_NAME, "Dog"); 1086 mResolver.update(nameUri, values, null, null); 1087 1088 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Dog"); 1089 } 1090 1091 public void testInsertDataWithContentProviderOperations() throws Exception { 1092 ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1093 .withValues(new ContentValues()) 1094 .build(); 1095 ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1096 .withValueBackReference(Data.RAW_CONTACT_ID, 0) 1097 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1098 .withValue(StructuredName.GIVEN_NAME, "John") 1099 .withValue(StructuredName.FAMILY_NAME, "Doe") 1100 .build(); 1101 ContentProviderResult[] results = 1102 mResolver.applyBatch(ContactsContract.AUTHORITY, Lists.newArrayList(cpo1, cpo2)); 1103 long contactId = queryContactId(ContentUris.parseId(results[0].uri)); 1104 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1105 assertStoredValue(uri, Contacts.DISPLAY_NAME, "John Doe"); 1106 } 1107 1108 public void testSendToVoicemailDefault() { 1109 long rawContactId = createRawContactWithName(); 1110 long contactId = queryContactId(rawContactId); 1111 1112 Cursor c = queryContact(contactId); 1113 assertTrue(c.moveToNext()); 1114 int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL)); 1115 assertEquals(0, sendToVoicemail); 1116 c.close(); 1117 } 1118 1119 public void testSetSendToVoicemailAndRingtone() { 1120 long rawContactId = createRawContactWithName(); 1121 long contactId = queryContactId(rawContactId); 1122 1123 updateSendToVoicemailAndRingtone(contactId, true, "foo"); 1124 assertSendToVoicemailAndRingtone(contactId, true, "foo"); 1125 assertNetworkNotified(false); 1126 1127 updateSendToVoicemailAndRingtoneWithSelection(contactId, false, "bar"); 1128 assertSendToVoicemailAndRingtone(contactId, false, "bar"); 1129 assertNetworkNotified(false); 1130 } 1131 1132 public void testSendToVoicemailAndRingtoneAfterAggregation() { 1133 long rawContactId1 = createRawContactWithName("a", "b"); 1134 long contactId1 = queryContactId(rawContactId1); 1135 updateSendToVoicemailAndRingtone(contactId1, true, "foo"); 1136 1137 long rawContactId2 = createRawContactWithName("c", "d"); 1138 long contactId2 = queryContactId(rawContactId2); 1139 updateSendToVoicemailAndRingtone(contactId2, true, "bar"); 1140 1141 // Aggregate them 1142 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1143 rawContactId1, rawContactId2); 1144 1145 // Both contacts had "send to VM", the contact now has the same value 1146 assertSendToVoicemailAndRingtone(contactId1, true, "foo,bar"); // Either foo or bar 1147 } 1148 1149 public void testDoNotSendToVoicemailAfterAggregation() { 1150 long rawContactId1 = createRawContactWithName("e", "f"); 1151 long contactId1 = queryContactId(rawContactId1); 1152 updateSendToVoicemailAndRingtone(contactId1, true, null); 1153 1154 long rawContactId2 = createRawContactWithName("g", "h"); 1155 long contactId2 = queryContactId(rawContactId2); 1156 updateSendToVoicemailAndRingtone(contactId2, false, null); 1157 1158 // Aggregate them 1159 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1160 rawContactId1, rawContactId2); 1161 1162 // Since one of the contacts had "don't send to VM" that setting wins for the aggregate 1163 assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), false, null); 1164 } 1165 1166 public void testSetSendToVoicemailAndRingtonePreservedAfterJoinAndSplit() { 1167 long rawContactId1 = createRawContactWithName("i", "j"); 1168 long contactId1 = queryContactId(rawContactId1); 1169 updateSendToVoicemailAndRingtone(contactId1, true, "foo"); 1170 1171 long rawContactId2 = createRawContactWithName("k", "l"); 1172 long contactId2 = queryContactId(rawContactId2); 1173 updateSendToVoicemailAndRingtone(contactId2, false, "bar"); 1174 1175 // Aggregate them 1176 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1177 rawContactId1, rawContactId2); 1178 1179 // Split them 1180 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 1181 rawContactId1, rawContactId2); 1182 1183 assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), true, "foo"); 1184 assertSendToVoicemailAndRingtone(queryContactId(rawContactId2), false, "bar"); 1185 } 1186 1187 public void testStatusUpdateInsert() { 1188 long rawContactId = createRawContact(); 1189 Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 1190 long dataId = ContentUris.parseId(imUri); 1191 1192 ContentValues values = new ContentValues(); 1193 values.put(StatusUpdates.DATA_ID, dataId); 1194 values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM); 1195 values.putNull(StatusUpdates.CUSTOM_PROTOCOL); 1196 values.put(StatusUpdates.IM_HANDLE, "aim"); 1197 values.put(StatusUpdates.PRESENCE, StatusUpdates.INVISIBLE); 1198 values.put(StatusUpdates.STATUS, "Hiding"); 1199 values.put(StatusUpdates.STATUS_TIMESTAMP, 100); 1200 values.put(StatusUpdates.STATUS_RES_PACKAGE, "a.b.c"); 1201 values.put(StatusUpdates.STATUS_ICON, 1234); 1202 values.put(StatusUpdates.STATUS_LABEL, 2345); 1203 1204 Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values); 1205 1206 assertStoredValues(resultUri, values); 1207 1208 long contactId = queryContactId(rawContactId); 1209 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1210 1211 values.clear(); 1212 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 1213 values.put(Contacts.CONTACT_STATUS, "Hiding"); 1214 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100); 1215 values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "a.b.c"); 1216 values.put(Contacts.CONTACT_STATUS_ICON, 1234); 1217 values.put(Contacts.CONTACT_STATUS_LABEL, 2345); 1218 1219 assertStoredValues(contactUri, values); 1220 1221 values.clear(); 1222 values.put(StatusUpdates.DATA_ID, dataId); 1223 values.put(StatusUpdates.STATUS, "Cloaked"); 1224 values.put(StatusUpdates.STATUS_TIMESTAMP, 200); 1225 values.put(StatusUpdates.STATUS_RES_PACKAGE, "d.e.f"); 1226 values.put(StatusUpdates.STATUS_ICON, 4321); 1227 values.put(StatusUpdates.STATUS_LABEL, 5432); 1228 mResolver.insert(StatusUpdates.CONTENT_URI, values); 1229 1230 values.clear(); 1231 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 1232 values.put(Contacts.CONTACT_STATUS, "Cloaked"); 1233 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 200); 1234 values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "d.e.f"); 1235 values.put(Contacts.CONTACT_STATUS_ICON, 4321); 1236 values.put(Contacts.CONTACT_STATUS_LABEL, 5432); 1237 assertStoredValues(contactUri, values); 1238 } 1239 1240 public void testStatusUpdateInferAttribution() { 1241 long rawContactId = createRawContact(); 1242 Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 1243 long dataId = ContentUris.parseId(imUri); 1244 1245 ContentValues values = new ContentValues(); 1246 values.put(StatusUpdates.DATA_ID, dataId); 1247 values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM); 1248 values.put(StatusUpdates.IM_HANDLE, "aim"); 1249 values.put(StatusUpdates.STATUS, "Hiding"); 1250 1251 Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values); 1252 1253 values.clear(); 1254 values.put(StatusUpdates.DATA_ID, dataId); 1255 values.put(StatusUpdates.STATUS_LABEL, com.android.internal.R.string.imProtocolAim); 1256 values.put(StatusUpdates.STATUS, "Hiding"); 1257 1258 assertStoredValues(resultUri, values); 1259 } 1260 1261 public void testStatusUpdateMatchingImOrEmail() { 1262 long rawContactId = createRawContact(); 1263 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 1264 insertImHandle(rawContactId, Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im"); 1265 insertEmail(rawContactId, "m@acme.com"); 1266 1267 // Match on IM (standard) 1268 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available"); 1269 1270 // Match on IM (custom) 1271 insertStatusUpdate(Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im", StatusUpdates.IDLE, "Idle"); 1272 1273 // Match on Email 1274 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "m@acme.com", StatusUpdates.AWAY, "Away"); 1275 1276 // No match 1277 insertStatusUpdate(Im.PROTOCOL_ICQ, null, "12345", StatusUpdates.DO_NOT_DISTURB, "Go away"); 1278 1279 Cursor c = mResolver.query(StatusUpdates.CONTENT_URI, new String[] { 1280 StatusUpdates.DATA_ID, StatusUpdates.PROTOCOL, StatusUpdates.CUSTOM_PROTOCOL, 1281 StatusUpdates.PRESENCE, StatusUpdates.STATUS}, 1282 PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null, StatusUpdates.DATA_ID); 1283 assertTrue(c.moveToNext()); 1284 assertStatusUpdate(c, Im.PROTOCOL_AIM, null, StatusUpdates.AVAILABLE, "Available"); 1285 assertTrue(c.moveToNext()); 1286 assertStatusUpdate(c, Im.PROTOCOL_CUSTOM, "my_im_proto", StatusUpdates.IDLE, "Idle"); 1287 assertTrue(c.moveToNext()); 1288 assertStatusUpdate(c, Im.PROTOCOL_GOOGLE_TALK, null, StatusUpdates.AWAY, "Away"); 1289 assertFalse(c.moveToNext()); 1290 c.close(); 1291 1292 long contactId = queryContactId(rawContactId); 1293 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1294 1295 ContentValues values = new ContentValues(); 1296 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 1297 values.put(Contacts.CONTACT_STATUS, "Available"); 1298 assertStoredValuesWithProjection(contactUri, values); 1299 } 1300 1301 public void testStatusUpdateUpdateAndDelete() { 1302 long rawContactId = createRawContact(); 1303 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 1304 1305 long contactId = queryContactId(rawContactId); 1306 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1307 1308 ContentValues values = new ContentValues(); 1309 values.putNull(Contacts.CONTACT_PRESENCE); 1310 values.putNull(Contacts.CONTACT_STATUS); 1311 assertStoredValuesWithProjection(contactUri, values); 1312 1313 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AWAY, "BUSY"); 1314 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.DO_NOT_DISTURB, "GO AWAY"); 1315 Uri statusUri = 1316 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available"); 1317 long statusId = ContentUris.parseId(statusUri); 1318 1319 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 1320 values.put(Contacts.CONTACT_STATUS, "Available"); 1321 assertStoredValuesWithProjection(contactUri, values); 1322 1323 // update status_updates table to set new values for 1324 // status_updates.status 1325 // status_updates.status_ts 1326 // presence 1327 long updatedTs = 200; 1328 String testUpdate = "test_update"; 1329 String selection = StatusUpdates.DATA_ID + "=" + statusId; 1330 values.clear(); 1331 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 1332 values.put(StatusUpdates.STATUS, testUpdate); 1333 values.put(StatusUpdates.PRESENCE, "presence_test"); 1334 mResolver.update(StatusUpdates.CONTENT_URI, values, 1335 StatusUpdates.DATA_ID + "=" + statusId, null); 1336 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 1337 1338 // update status_updates table to set new values for columns in status_updates table ONLY 1339 // i.e., no rows in presence table are to be updated. 1340 updatedTs = 300; 1341 testUpdate = "test_update_new"; 1342 selection = StatusUpdates.DATA_ID + "=" + statusId; 1343 values.clear(); 1344 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 1345 values.put(StatusUpdates.STATUS, testUpdate); 1346 mResolver.update(StatusUpdates.CONTENT_URI, values, 1347 StatusUpdates.DATA_ID + "=" + statusId, null); 1348 // make sure the presence column value is still the old value 1349 values.put(StatusUpdates.PRESENCE, "presence_test"); 1350 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 1351 1352 // update status_updates table to set new values for columns in presence table ONLY 1353 // i.e., no rows in status_updates table are to be updated. 1354 selection = StatusUpdates.DATA_ID + "=" + statusId; 1355 values.clear(); 1356 values.put(StatusUpdates.PRESENCE, "presence_test_new"); 1357 mResolver.update(StatusUpdates.CONTENT_URI, values, 1358 StatusUpdates.DATA_ID + "=" + statusId, null); 1359 // make sure the status_updates table is not updated 1360 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 1361 values.put(StatusUpdates.STATUS, testUpdate); 1362 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 1363 1364 // effect "delete status_updates" operation and expect the following 1365 // data deleted from status_updates table 1366 // presence set to null 1367 mResolver.delete(StatusUpdates.CONTENT_URI, StatusUpdates.DATA_ID + "=" + statusId, null); 1368 values.clear(); 1369 values.putNull(Contacts.CONTACT_PRESENCE); 1370 assertStoredValuesWithProjection(contactUri, values); 1371 } 1372 1373 public void testStatusUpdateWithTimestamp() { 1374 long rawContactId = createRawContact(); 1375 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 1376 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk"); 1377 1378 long contactId = queryContactId(rawContactId); 1379 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1380 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Offline", 80); 1381 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Available", 100); 1382 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", 0, "Busy", 90); 1383 1384 // Should return the latest status 1385 ContentValues values = new ContentValues(); 1386 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100); 1387 values.put(Contacts.CONTACT_STATUS, "Available"); 1388 assertStoredValuesWithProjection(contactUri, values); 1389 } 1390 1391 private void assertStatusUpdate(Cursor c, int protocol, String customProtocol, int presence, 1392 String status) { 1393 ContentValues values = new ContentValues(); 1394 values.put(StatusUpdates.PROTOCOL, protocol); 1395 values.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 1396 values.put(StatusUpdates.PRESENCE_STATUS, presence); 1397 values.put(StatusUpdates.STATUS, status); 1398 assertCursorValues(c, values); 1399 } 1400 1401 public void testSingleStatusUpdateRowPerContact() { 1402 int protocol1 = Im.PROTOCOL_GOOGLE_TALK; 1403 String handle1 = "test@gmail.com"; 1404 1405 long rawContactId1 = createRawContact(); 1406 insertImHandle(rawContactId1, protocol1, null, handle1); 1407 1408 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AVAILABLE, "Green"); 1409 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AWAY, "Yellow"); 1410 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.INVISIBLE, "Red"); 1411 1412 Cursor c = queryContact(queryContactId(rawContactId1), 1413 new String[] {Contacts.CONTACT_PRESENCE, Contacts.CONTACT_STATUS}); 1414 assertEquals(1, c.getCount()); 1415 1416 c.moveToFirst(); 1417 assertEquals(StatusUpdates.INVISIBLE, c.getInt(0)); 1418 assertEquals("Red", c.getString(1)); 1419 c.close(); 1420 } 1421 1422 private void updateSendToVoicemailAndRingtone(long contactId, boolean sendToVoicemail, 1423 String ringtone) { 1424 ContentValues values = new ContentValues(); 1425 values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail); 1426 if (ringtone != null) { 1427 values.put(Contacts.CUSTOM_RINGTONE, ringtone); 1428 } 1429 1430 final Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1431 int count = mResolver.update(uri, values, null, null); 1432 assertEquals(1, count); 1433 } 1434 1435 private void updateSendToVoicemailAndRingtoneWithSelection(long contactId, 1436 boolean sendToVoicemail, String ringtone) { 1437 ContentValues values = new ContentValues(); 1438 values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail); 1439 if (ringtone != null) { 1440 values.put(Contacts.CUSTOM_RINGTONE, ringtone); 1441 } 1442 1443 int count = mResolver.update(Contacts.CONTENT_URI, values, Contacts._ID + "=" + contactId, 1444 null); 1445 assertEquals(1, count); 1446 } 1447 1448 private void assertSendToVoicemailAndRingtone(long contactId, boolean expectedSendToVoicemail, 1449 String expectedRingtone) { 1450 Cursor c = queryContact(contactId); 1451 assertTrue(c.moveToNext()); 1452 int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL)); 1453 assertEquals(expectedSendToVoicemail ? 1 : 0, sendToVoicemail); 1454 String ringtone = c.getString(c.getColumnIndex(Contacts.CUSTOM_RINGTONE)); 1455 if (expectedRingtone == null) { 1456 assertNull(ringtone); 1457 } else { 1458 assertTrue(ArrayUtils.contains(expectedRingtone.split(","), ringtone)); 1459 } 1460 c.close(); 1461 } 1462 1463 public void testGroupCreationAfterMembershipInsert() { 1464 long rawContactId1 = createRawContact(mAccount); 1465 Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1"); 1466 1467 long groupId = assertSingleGroup(NO_LONG, mAccount, "gsid1", null); 1468 assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri), 1469 rawContactId1, groupId, "gsid1"); 1470 } 1471 1472 public void testGroupReuseAfterMembershipInsert() { 1473 long rawContactId1 = createRawContact(mAccount); 1474 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 1475 Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1"); 1476 1477 assertSingleGroup(groupId1, mAccount, "gsid1", "title1"); 1478 assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri), 1479 rawContactId1, groupId1, "gsid1"); 1480 } 1481 1482 public void testGroupInsertFailureOnGroupIdConflict() { 1483 long rawContactId1 = createRawContact(mAccount); 1484 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 1485 1486 ContentValues values = new ContentValues(); 1487 values.put(GroupMembership.RAW_CONTACT_ID, rawContactId1); 1488 values.put(GroupMembership.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE); 1489 values.put(GroupMembership.GROUP_SOURCE_ID, "gsid1"); 1490 values.put(GroupMembership.GROUP_ROW_ID, groupId1); 1491 try { 1492 mResolver.insert(Data.CONTENT_URI, values); 1493 fail("the insert was expected to fail, but it succeeded"); 1494 } catch (IllegalArgumentException e) { 1495 // this was expected 1496 } 1497 } 1498 1499 public void testContactVisibilityUpdateOnMembershipChange() { 1500 long rawContactId = createRawContact(mAccount); 1501 assertVisibility(rawContactId, "0"); 1502 1503 long visibleGroupId = createGroup(mAccount, "123", "Visible", 1); 1504 long invisibleGroupId = createGroup(mAccount, "567", "Invisible", 0); 1505 1506 Uri membership1 = insertGroupMembership(rawContactId, visibleGroupId); 1507 assertVisibility(rawContactId, "1"); 1508 1509 Uri membership2 = insertGroupMembership(rawContactId, invisibleGroupId); 1510 assertVisibility(rawContactId, "1"); 1511 1512 mResolver.delete(membership1, null, null); 1513 assertVisibility(rawContactId, "0"); 1514 1515 ContentValues values = new ContentValues(); 1516 values.put(GroupMembership.GROUP_ROW_ID, visibleGroupId); 1517 1518 mResolver.update(membership2, values, null, null); 1519 assertVisibility(rawContactId, "1"); 1520 } 1521 1522 private void assertVisibility(long rawContactId, String expectedValue) { 1523 assertStoredValue(Contacts.CONTENT_URI, Contacts._ID + "=" + queryContactId(rawContactId), 1524 null, Contacts.IN_VISIBLE_GROUP, expectedValue); 1525 } 1526 1527 public void testContentEntityIterator() throws RemoteException { 1528 // create multiple contacts and check that the selected ones are returned 1529 long id; 1530 1531 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 1532 long groupId2 = createGroup(mAccount, "gsid2", "title2"); 1533 1534 id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c0"); 1535 insertGroupMembership(id, "gsid1"); 1536 insertEmail(id, "c0@email.com"); 1537 insertPhoneNumber(id, "5551212c0"); 1538 1539 long c1 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c1"); 1540 Uri id_1_0 = insertGroupMembership(id, "gsid1"); 1541 Uri id_1_1 = insertGroupMembership(id, "gsid2"); 1542 Uri id_1_2 = insertEmail(id, "c1@email.com"); 1543 Uri id_1_3 = insertPhoneNumber(id, "5551212c1"); 1544 1545 long c2 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c2"); 1546 Uri id_2_0 = insertGroupMembership(id, "gsid1"); 1547 Uri id_2_1 = insertEmail(id, "c2@email.com"); 1548 Uri id_2_2 = insertPhoneNumber(id, "5551212c2"); 1549 1550 long c3 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c3"); 1551 Uri id_3_0 = insertGroupMembership(id, groupId2); 1552 Uri id_3_1 = insertEmail(id, "c3@email.com"); 1553 Uri id_3_2 = insertPhoneNumber(id, "5551212c3"); 1554 1555 EntityIterator iterator = RawContacts.newEntityIterator(mResolver.query( 1556 maybeAddAccountQueryParameters(RawContactsEntity.CONTENT_URI, mAccount), null, 1557 RawContacts.SOURCE_ID + " in ('c1', 'c2', 'c3')", null, null)); 1558 Entity entity; 1559 ContentValues[] subValues; 1560 entity = iterator.next(); 1561 assertEquals(c1, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 1562 subValues = asSortedContentValuesArray(entity.getSubValues()); 1563 assertEquals(4, subValues.length); 1564 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 1565 Data._ID, id_1_0, 1566 GroupMembership.GROUP_ROW_ID, groupId1, 1567 GroupMembership.GROUP_SOURCE_ID, "gsid1"); 1568 assertDataRow(subValues[1], GroupMembership.CONTENT_ITEM_TYPE, 1569 Data._ID, id_1_1, 1570 GroupMembership.GROUP_ROW_ID, groupId2, 1571 GroupMembership.GROUP_SOURCE_ID, "gsid2"); 1572 assertDataRow(subValues[2], Email.CONTENT_ITEM_TYPE, 1573 Data._ID, id_1_2, 1574 Email.DATA, "c1@email.com"); 1575 assertDataRow(subValues[3], Phone.CONTENT_ITEM_TYPE, 1576 Data._ID, id_1_3, 1577 Email.DATA, "5551212c1"); 1578 1579 entity = iterator.next(); 1580 assertEquals(c2, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 1581 subValues = asSortedContentValuesArray(entity.getSubValues()); 1582 assertEquals(3, subValues.length); 1583 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 1584 Data._ID, id_2_0, 1585 GroupMembership.GROUP_ROW_ID, groupId1, 1586 GroupMembership.GROUP_SOURCE_ID, "gsid1"); 1587 assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE, 1588 Data._ID, id_2_1, 1589 Email.DATA, "c2@email.com"); 1590 assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE, 1591 Data._ID, id_2_2, 1592 Email.DATA, "5551212c2"); 1593 1594 entity = iterator.next(); 1595 assertEquals(c3, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 1596 subValues = asSortedContentValuesArray(entity.getSubValues()); 1597 assertEquals(3, subValues.length); 1598 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 1599 Data._ID, id_3_0, 1600 GroupMembership.GROUP_ROW_ID, groupId2, 1601 GroupMembership.GROUP_SOURCE_ID, "gsid2"); 1602 assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE, 1603 Data._ID, id_3_1, 1604 Email.DATA, "c3@email.com"); 1605 assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE, 1606 Data._ID, id_3_2, 1607 Email.DATA, "5551212c3"); 1608 1609 assertFalse(iterator.hasNext()); 1610 iterator.close(); 1611 } 1612 1613 public void testDataCreateUpdateDeleteByMimeType() throws Exception { 1614 long rawContactId = createRawContact(); 1615 1616 ContentValues values = new ContentValues(); 1617 values.put(Data.RAW_CONTACT_ID, rawContactId); 1618 values.put(Data.MIMETYPE, "testmimetype"); 1619 values.put(Data.RES_PACKAGE, "oldpackage"); 1620 values.put(Data.IS_PRIMARY, 1); 1621 values.put(Data.IS_SUPER_PRIMARY, 1); 1622 values.put(Data.DATA1, "old1"); 1623 values.put(Data.DATA2, "old2"); 1624 values.put(Data.DATA3, "old3"); 1625 values.put(Data.DATA4, "old4"); 1626 values.put(Data.DATA5, "old5"); 1627 values.put(Data.DATA6, "old6"); 1628 values.put(Data.DATA7, "old7"); 1629 values.put(Data.DATA8, "old8"); 1630 values.put(Data.DATA9, "old9"); 1631 values.put(Data.DATA10, "old10"); 1632 values.put(Data.DATA11, "old11"); 1633 values.put(Data.DATA12, "old12"); 1634 values.put(Data.DATA13, "old13"); 1635 values.put(Data.DATA14, "old14"); 1636 values.put(Data.DATA15, "old15"); 1637 Uri uri = mResolver.insert(Data.CONTENT_URI, values); 1638 assertStoredValues(uri, values); 1639 assertNetworkNotified(true); 1640 1641 values.clear(); 1642 values.put(Data.RES_PACKAGE, "newpackage"); 1643 values.put(Data.IS_PRIMARY, 0); 1644 values.put(Data.IS_SUPER_PRIMARY, 0); 1645 values.put(Data.DATA1, "new1"); 1646 values.put(Data.DATA2, "new2"); 1647 values.put(Data.DATA3, "new3"); 1648 values.put(Data.DATA4, "new4"); 1649 values.put(Data.DATA5, "new5"); 1650 values.put(Data.DATA6, "new6"); 1651 values.put(Data.DATA7, "new7"); 1652 values.put(Data.DATA8, "new8"); 1653 values.put(Data.DATA9, "new9"); 1654 values.put(Data.DATA10, "new10"); 1655 values.put(Data.DATA11, "new11"); 1656 values.put(Data.DATA12, "new12"); 1657 values.put(Data.DATA13, "new13"); 1658 values.put(Data.DATA14, "new14"); 1659 values.put(Data.DATA15, "new15"); 1660 mResolver.update(Data.CONTENT_URI, values, Data.RAW_CONTACT_ID + "=" + rawContactId + 1661 " AND " + Data.MIMETYPE + "='testmimetype'", null); 1662 assertNetworkNotified(true); 1663 1664 // Should not be able to change IS_PRIMARY and IS_SUPER_PRIMARY by the above update 1665 values.put(Data.IS_PRIMARY, 1); 1666 values.put(Data.IS_SUPER_PRIMARY, 1); 1667 assertStoredValues(uri, values); 1668 1669 int count = mResolver.delete(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId 1670 + " AND " + Data.MIMETYPE + "='testmimetype'", null); 1671 assertEquals(1, count); 1672 assertEquals(0, getCount(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId 1673 + " AND " + Data.MIMETYPE + "='testmimetype'", null)); 1674 assertNetworkNotified(true); 1675 } 1676 1677 public void testRawContactQuery() { 1678 Account account1 = new Account("a", "b"); 1679 Account account2 = new Account("c", "d"); 1680 long rawContactId1 = createRawContact(account1); 1681 long rawContactId2 = createRawContact(account2); 1682 1683 Uri uri1 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account1); 1684 Uri uri2 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account2); 1685 assertEquals(1, getCount(uri1, null, null)); 1686 assertEquals(1, getCount(uri2, null, null)); 1687 assertStoredValue(uri1, RawContacts._ID, rawContactId1) ; 1688 assertStoredValue(uri2, RawContacts._ID, rawContactId2) ; 1689 1690 Uri rowUri1 = ContentUris.withAppendedId(uri1, rawContactId1); 1691 Uri rowUri2 = ContentUris.withAppendedId(uri2, rawContactId2); 1692 assertStoredValue(rowUri1, RawContacts._ID, rawContactId1) ; 1693 assertStoredValue(rowUri2, RawContacts._ID, rawContactId2) ; 1694 } 1695 1696 public void testRawContactDeletion() { 1697 long rawContactId = createRawContact(mAccount); 1698 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 1699 1700 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 1701 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 1702 StatusUpdates.AVAILABLE, null); 1703 long contactId = queryContactId(rawContactId); 1704 1705 assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 1706 null, null)); 1707 assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 1708 + rawContactId, null)); 1709 1710 mResolver.delete(uri, null, null); 1711 1712 assertStoredValue(uri, RawContacts.DELETED, "1"); 1713 assertNetworkNotified(true); 1714 1715 Uri permanentDeletionUri = setCallerIsSyncAdapter(uri, mAccount); 1716 mResolver.delete(permanentDeletionUri, null, null); 1717 assertEquals(0, getCount(uri, null, null)); 1718 assertEquals(0, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 1719 null, null)); 1720 assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 1721 + rawContactId, null)); 1722 assertEquals(0, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null)); 1723 assertNetworkNotified(false); 1724 } 1725 1726 public void testRawContactDeletionKeepingAggregateContact() { 1727 long rawContactId1 = createRawContactWithName(mAccount); 1728 long rawContactId2 = createRawContactWithName(mAccount); 1729 1730 // Same name - should be aggregated 1731 assertAggregated(rawContactId1, rawContactId2); 1732 1733 long contactId = queryContactId(rawContactId1); 1734 1735 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 1736 Uri permanentDeletionUri = setCallerIsSyncAdapter(uri, mAccount); 1737 mResolver.delete(permanentDeletionUri, null, null); 1738 assertEquals(0, getCount(uri, null, null)); 1739 assertEquals(1, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null)); 1740 } 1741 1742 public void testRawContactDeletionWithAccounts() { 1743 long rawContactId = createRawContact(mAccount); 1744 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 1745 1746 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 1747 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 1748 StatusUpdates.AVAILABLE, null); 1749 assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 1750 null, null)); 1751 assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 1752 + rawContactId, null)); 1753 1754 // Do not delete if we are deleting with wrong account. 1755 Uri deleteWithWrongAccountUri = 1756 RawContacts.CONTENT_URI.buildUpon() 1757 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccountTwo.name) 1758 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccountTwo.type) 1759 .build(); 1760 mResolver.delete(deleteWithWrongAccountUri, null, null); 1761 1762 assertStoredValue(uri, RawContacts.DELETED, "0"); 1763 1764 // Delete if we are deleting with correct account. 1765 Uri deleteWithCorrectAccountUri = 1766 RawContacts.CONTENT_URI.buildUpon() 1767 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccount.name) 1768 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccount.type) 1769 .build(); 1770 mResolver.delete(deleteWithCorrectAccountUri, null, null); 1771 1772 assertStoredValue(uri, RawContacts.DELETED, "1"); 1773 } 1774 1775 public void testAccountsUpdated() { 1776 // This is to ensure we do not delete contacts with null, null (account name, type) 1777 // accidentally. 1778 long rawContactId3 = createRawContactWithName("James", "Sullivan"); 1779 insertPhoneNumber(rawContactId3, "5234567890"); 1780 Uri rawContact3 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId3); 1781 assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null)); 1782 1783 ContactsProvider2 cp = (ContactsProvider2) getProvider(); 1784 cp.onAccountsUpdated(new Account[]{mAccount, mAccountTwo}); 1785 assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null)); 1786 assertStoredValue(rawContact3, RawContacts.ACCOUNT_NAME, null); 1787 assertStoredValue(rawContact3, RawContacts.ACCOUNT_TYPE, null); 1788 1789 long rawContactId1 = createRawContact(mAccount); 1790 insertEmail(rawContactId1, "account1@email.com"); 1791 long rawContactId2 = createRawContact(mAccountTwo); 1792 insertEmail(rawContactId2, "account2@email.com"); 1793 insertImHandle(rawContactId2, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 1794 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 1795 StatusUpdates.AVAILABLE, null); 1796 1797 cp.onAccountsUpdated(new Account[]{mAccount}); 1798 assertEquals(2, getCount(RawContacts.CONTENT_URI, null, null)); 1799 assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 1800 + rawContactId2, null)); 1801 } 1802 1803 public void testAccountDeletion() { 1804 Account readOnlyAccount = new Account("act", READ_ONLY_ACCOUNT_TYPE); 1805 ContactsProvider2 cp = (ContactsProvider2) getProvider(); 1806 cp.onAccountsUpdated(new Account[]{readOnlyAccount, mAccount}); 1807 1808 long rawContactId1 = createRawContactWithName("John", "Doe", readOnlyAccount); 1809 Uri photoUri1 = insertPhoto(rawContactId1); 1810 long rawContactId2 = createRawContactWithName("john", "doe", mAccount); 1811 Uri photoUri2 = insertPhoto(rawContactId2); 1812 storeValue(photoUri2, Photo.IS_SUPER_PRIMARY, "1"); 1813 1814 assertAggregated(rawContactId1, rawContactId2); 1815 1816 long contactId = queryContactId(rawContactId1); 1817 1818 // The display name should come from the writable account 1819 assertStoredValue(Uri.withAppendedPath( 1820 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 1821 Contacts.Data.CONTENT_DIRECTORY), 1822 Contacts.DISPLAY_NAME, "john doe"); 1823 1824 // The photo should be the one we marked as super-primary 1825 assertStoredValue(Contacts.CONTENT_URI, contactId, 1826 Contacts.PHOTO_ID, ContentUris.parseId(photoUri2)); 1827 1828 // Remove the writable account 1829 cp.onAccountsUpdated(new Account[]{readOnlyAccount}); 1830 1831 // The display name should come from the remaining account 1832 assertStoredValue(Uri.withAppendedPath( 1833 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 1834 Contacts.Data.CONTENT_DIRECTORY), 1835 Contacts.DISPLAY_NAME, "John Doe"); 1836 1837 // The photo should be the remaining one 1838 assertStoredValue(Contacts.CONTENT_URI, contactId, 1839 Contacts.PHOTO_ID, ContentUris.parseId(photoUri1)); 1840 1841 } 1842 1843 public void testContactDeletion() { 1844 long rawContactId1 = createRawContactWithName("John", "Doe"); 1845 long rawContactId2 = createRawContactWithName("John", "Doe"); 1846 1847 long contactId = queryContactId(rawContactId1); 1848 1849 mResolver.delete(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), null, null); 1850 1851 assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1), 1852 RawContacts.DELETED, "1"); 1853 assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2), 1854 RawContacts.DELETED, "1"); 1855 } 1856 1857 public void testMarkAsDirtyParameter() { 1858 long rawContactId = createRawContact(mAccount); 1859 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 1860 1861 Uri uri = insertStructuredName(rawContactId, "John", "Doe"); 1862 clearDirty(rawContactUri); 1863 Uri updateUri = setCallerIsSyncAdapter(uri, mAccount); 1864 1865 ContentValues values = new ContentValues(); 1866 values.put(StructuredName.FAMILY_NAME, "Dough"); 1867 mResolver.update(updateUri, values, null, null); 1868 assertStoredValue(uri, StructuredName.FAMILY_NAME, "Dough"); 1869 assertDirty(rawContactUri, false); 1870 assertNetworkNotified(false); 1871 } 1872 1873 public void testRawContactDirtyAndVersion() { 1874 final long rawContactId = createRawContact(mAccount); 1875 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId); 1876 assertDirty(uri, false); 1877 long version = getVersion(uri); 1878 1879 ContentValues values = new ContentValues(); 1880 values.put(ContactsContract.RawContacts.DIRTY, 0); 1881 values.put(ContactsContract.RawContacts.SEND_TO_VOICEMAIL, 1); 1882 values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 1883 RawContacts.AGGREGATION_MODE_IMMEDIATE); 1884 values.put(ContactsContract.RawContacts.STARRED, 1); 1885 assertEquals(1, mResolver.update(uri, values, null, null)); 1886 assertEquals(version, getVersion(uri)); 1887 1888 assertDirty(uri, false); 1889 assertNetworkNotified(false); 1890 1891 Uri emailUri = insertEmail(rawContactId, "goo@woo.com"); 1892 assertDirty(uri, true); 1893 assertNetworkNotified(true); 1894 ++version; 1895 assertEquals(version, getVersion(uri)); 1896 clearDirty(uri); 1897 1898 values = new ContentValues(); 1899 values.put(Email.DATA, "goo@hoo.com"); 1900 mResolver.update(emailUri, values, null, null); 1901 assertDirty(uri, true); 1902 assertNetworkNotified(true); 1903 ++version; 1904 assertEquals(version, getVersion(uri)); 1905 clearDirty(uri); 1906 1907 mResolver.delete(emailUri, null, null); 1908 assertDirty(uri, true); 1909 assertNetworkNotified(true); 1910 ++version; 1911 assertEquals(version, getVersion(uri)); 1912 } 1913 1914 public void testRawContactClearDirty() { 1915 final long rawContactId = createRawContact(mAccount); 1916 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, 1917 rawContactId); 1918 long version = getVersion(uri); 1919 insertEmail(rawContactId, "goo@woo.com"); 1920 assertDirty(uri, true); 1921 version++; 1922 assertEquals(version, getVersion(uri)); 1923 1924 clearDirty(uri); 1925 assertDirty(uri, false); 1926 assertEquals(version, getVersion(uri)); 1927 } 1928 1929 public void testRawContactDeletionSetsDirty() { 1930 final long rawContactId = createRawContact(mAccount); 1931 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, 1932 rawContactId); 1933 long version = getVersion(uri); 1934 clearDirty(uri); 1935 assertDirty(uri, false); 1936 1937 mResolver.delete(uri, null, null); 1938 assertStoredValue(uri, RawContacts.DELETED, "1"); 1939 assertDirty(uri, true); 1940 assertNetworkNotified(true); 1941 version++; 1942 assertEquals(version, getVersion(uri)); 1943 } 1944 1945 public void testDeleteContactWithoutName() { 1946 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues()); 1947 long rawContactId = ContentUris.parseId(rawContactUri); 1948 1949 Uri phoneUri = insertPhoneNumber(rawContactId, "555-123-45678", true); 1950 1951 long contactId = queryContactId(rawContactId); 1952 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1953 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 1954 1955 int numDeleted = mResolver.delete(lookupUri, null, null); 1956 assertEquals(1, numDeleted); 1957 } 1958 1959 public void testDeleteContactWithoutAnyData() { 1960 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues()); 1961 long rawContactId = ContentUris.parseId(rawContactUri); 1962 1963 long contactId = queryContactId(rawContactId); 1964 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1965 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 1966 1967 int numDeleted = mResolver.delete(lookupUri, null, null); 1968 assertEquals(1, numDeleted); 1969 } 1970 1971 public void testDeleteContactWithEscapedUri() { 1972 ContentValues values = new ContentValues(); 1973 values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~"); 1974 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1975 long rawContactId = ContentUris.parseId(rawContactUri); 1976 1977 long contactId = queryContactId(rawContactId); 1978 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1979 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 1980 assertEquals(1, mResolver.delete(lookupUri, null, null)); 1981 } 1982 1983 public void testQueryContactWithEscapedUri() { 1984 ContentValues values = new ContentValues(); 1985 values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~"); 1986 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1987 long rawContactId = ContentUris.parseId(rawContactUri); 1988 1989 long contactId = queryContactId(rawContactId); 1990 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1991 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 1992 Cursor c = mResolver.query(lookupUri, null, null, null, ""); 1993 assertEquals(1, c.getCount()); 1994 c.close(); 1995 } 1996 1997 public void testGetPhotoUri() { 1998 ContentValues values = new ContentValues(); 1999 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2000 long rawContactId = ContentUris.parseId(rawContactUri); 2001 insertStructuredName(rawContactId, "John", "Doe"); 2002 Uri photoUri = insertPhoto(rawContactId); 2003 2004 Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, 2005 queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY); 2006 2007 long twigId = Long.parseLong(getStoredValue(twigUri, Data._ID)); 2008 assertEquals(ContentUris.parseId(photoUri), twigId); 2009 } 2010 2011 public void testOpenAssertFileDescriptorForPhoto() throws Exception { 2012 long rawContactId = createRawContact(); 2013 Uri photoUri = insertPhoto(rawContactId); 2014 AssetFileDescriptor fd = mResolver.openAssetFileDescriptor(photoUri, "r"); 2015 assertEquals(loadTestPhoto().length, fd.getLength()); 2016 2017 Uri contactPhotoUri = Uri.withAppendedPath( 2018 ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(rawContactId)), 2019 Contacts.Photo.CONTENT_DIRECTORY); 2020 fd = mResolver.openAssetFileDescriptor(contactPhotoUri, "r"); 2021 assertEquals(loadTestPhoto().length, fd.getLength()); 2022 } 2023 2024 public void testSuperPrimaryPhoto() { 2025 long rawContactId1 = createRawContact(new Account("a", "a")); 2026 Uri photoUri1 = insertPhoto(rawContactId1); 2027 long photoId1 = ContentUris.parseId(photoUri1); 2028 2029 long rawContactId2 = createRawContact(new Account("b", "b")); 2030 Uri photoUri2 = insertPhoto(rawContactId2); 2031 long photoId2 = ContentUris.parseId(photoUri2); 2032 2033 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 2034 rawContactId1, rawContactId2); 2035 2036 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 2037 queryContactId(rawContactId1)); 2038 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1); 2039 2040 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 2041 rawContactId1, rawContactId2); 2042 2043 ContentValues values = new ContentValues(); 2044 values.put(Data.IS_SUPER_PRIMARY, 1); 2045 mResolver.update(photoUri2, values, null, null); 2046 2047 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 2048 rawContactId1, rawContactId2); 2049 contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 2050 queryContactId(rawContactId1)); 2051 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId2); 2052 2053 mResolver.update(photoUri1, values, null, null); 2054 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1); 2055 } 2056 2057 public void testUpdatePhoto() { 2058 ContentValues values = new ContentValues(); 2059 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2060 long rawContactId = ContentUris.parseId(rawContactUri); 2061 insertStructuredName(rawContactId, "John", "Doe"); 2062 2063 Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, 2064 queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY); 2065 2066 values.clear(); 2067 values.put(Data.RAW_CONTACT_ID, rawContactId); 2068 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 2069 values.putNull(Photo.PHOTO); 2070 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 2071 long photoId = ContentUris.parseId(dataUri); 2072 2073 assertNull(getStoredValue(twigUri, Data._ID)); 2074 2075 values.clear(); 2076 values.put(Photo.PHOTO, loadTestPhoto()); 2077 mResolver.update(dataUri, values, null, null); 2078 assertNetworkNotified(true); 2079 2080 long twigId = Long.parseLong(getStoredValue(twigUri, Data._ID)); 2081 assertEquals(photoId, twigId); 2082 } 2083 2084 public void testUpdateRawContactDataPhoto() { 2085 // setup a contact with a null photo 2086 ContentValues values = new ContentValues(); 2087 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2088 long rawContactId = ContentUris.parseId(rawContactUri); 2089 2090 // setup a photo 2091 values.put(Data.RAW_CONTACT_ID, rawContactId); 2092 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 2093 values.putNull(Photo.PHOTO); 2094 2095 // try to do an update before insert should return count == 0 2096 Uri dataUri = Uri.withAppendedPath( 2097 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 2098 RawContacts.Data.CONTENT_DIRECTORY); 2099 assertEquals(0, mResolver.update(dataUri, values, Data.MIMETYPE + "=?", 2100 new String[] {Photo.CONTENT_ITEM_TYPE})); 2101 2102 mResolver.insert(Data.CONTENT_URI, values); 2103 2104 // save a photo to the db 2105 values.clear(); 2106 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 2107 values.put(Photo.PHOTO, loadTestPhoto()); 2108 assertEquals(1, mResolver.update(dataUri, values, Data.MIMETYPE + "=?", 2109 new String[] {Photo.CONTENT_ITEM_TYPE})); 2110 2111 // verify the photo 2112 Cursor storedPhoto = mResolver.query(dataUri, new String[] {Photo.PHOTO}, 2113 Data.MIMETYPE + "=?", new String[] {Photo.CONTENT_ITEM_TYPE}, null); 2114 storedPhoto.moveToFirst(); 2115 MoreAsserts.assertEquals(loadTestPhoto(), storedPhoto.getBlob(0)); 2116 storedPhoto.close(); 2117 } 2118 2119 public void testUpdateRawContactSetStarred() { 2120 long rawContactId1 = createRawContactWithName(); 2121 Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 2122 long rawContactId2 = createRawContactWithName(); 2123 Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2); 2124 2125 assertAggregated(rawContactId1, rawContactId2); 2126 2127 long contactId = queryContactId(rawContactId1); 2128 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2129 assertStoredValue(contactUri, Contacts.STARRED, "0"); 2130 2131 ContentValues values = new ContentValues(); 2132 values.put(RawContacts.STARRED, "1"); 2133 2134 mResolver.update(rawContactUri1, values, null, null); 2135 2136 assertStoredValue(rawContactUri1, RawContacts.STARRED, "1"); 2137 assertStoredValue(rawContactUri2, RawContacts.STARRED, "0"); 2138 assertStoredValue(contactUri, Contacts.STARRED, "1"); 2139 2140 values.put(RawContacts.STARRED, "0"); 2141 mResolver.update(rawContactUri1, values, null, null); 2142 2143 assertStoredValue(rawContactUri1, RawContacts.STARRED, "0"); 2144 assertStoredValue(rawContactUri2, RawContacts.STARRED, "0"); 2145 assertStoredValue(contactUri, Contacts.STARRED, "0"); 2146 2147 values.put(Contacts.STARRED, "1"); 2148 mResolver.update(contactUri, values, null, null); 2149 2150 assertStoredValue(rawContactUri1, RawContacts.STARRED, "1"); 2151 assertStoredValue(rawContactUri2, RawContacts.STARRED, "1"); 2152 assertStoredValue(contactUri, Contacts.STARRED, "1"); 2153 } 2154 2155 public void testLiveFolders() { 2156 long rawContactId1 = createRawContactWithName("James", "Sullivan"); 2157 insertPhoneNumber(rawContactId1, "5234567890"); 2158 long contactId1 = queryContactId(rawContactId1); 2159 2160 long rawContactId2 = createRawContactWithName("Mike", "Wazowski"); 2161 long contactId2 = queryContactId(rawContactId2); 2162 storeValue(Contacts.CONTENT_URI, contactId2, Contacts.STARRED, "1"); 2163 2164 long rawContactId3 = createRawContactWithName("Randall", "Boggs"); 2165 long contactId3 = queryContactId(rawContactId3); 2166 long groupId = createGroup(NO_ACCOUNT, "src1", "VIP"); 2167 insertGroupMembership(rawContactId3, groupId); 2168 2169 assertLiveFolderContents( 2170 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 2171 "live_folders/contacts"), 2172 contactId1, "James Sullivan", 2173 contactId2, "Mike Wazowski", 2174 contactId3, "Randall Boggs"); 2175 2176 assertLiveFolderContents( 2177 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 2178 "live_folders/contacts_with_phones"), 2179 contactId1, "James Sullivan"); 2180 2181 assertLiveFolderContents( 2182 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 2183 "live_folders/favorites"), 2184 contactId2, "Mike Wazowski"); 2185 2186 assertLiveFolderContents( 2187 Uri.withAppendedPath(Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 2188 "live_folders/contacts"), Uri.encode("VIP")), 2189 contactId3, "Randall Boggs"); 2190 } 2191 2192 private void assertLiveFolderContents(Uri uri, Object... expected) { 2193 Cursor c = mResolver.query(uri, new String[]{LiveFolders._ID, LiveFolders.NAME}, 2194 null, null, LiveFolders._ID); 2195 assertEquals(expected.length/2, c.getCount()); 2196 for (int i = 0; i < expected.length/2; i++) { 2197 assertTrue(c.moveToNext()); 2198 assertEquals(((Long)expected[i * 2]).longValue(), c.getLong(0)); 2199 assertEquals(expected[i * 2 + 1], c.getString(1)); 2200 } 2201 c.close(); 2202 } 2203 2204 public void testContactCounts() { 2205 Uri uri = Contacts.CONTENT_URI.buildUpon() 2206 .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build(); 2207 2208 createRawContact(); 2209 createRawContactWithName("James", "Sullivan"); 2210 createRawContactWithName("The Abominable", "Snowman"); 2211 createRawContactWithName("Mike", "Wazowski"); 2212 createRawContactWithName("randall", "boggs"); 2213 createRawContactWithName("Boo", null); 2214 createRawContactWithName("Mary", null); 2215 createRawContactWithName("Roz", null); 2216 2217 Cursor cursor = mResolver.query(uri, 2218 new String[]{Contacts.DISPLAY_NAME}, 2219 null, null, Contacts.SORT_KEY_PRIMARY + " COLLATE LOCALIZED"); 2220 2221 assertFirstLetterValues(cursor, null, "B", "J", "M", "R", "T"); 2222 assertFirstLetterCounts(cursor, 1, 1, 1, 2, 2, 1); 2223 cursor.close(); 2224 2225 cursor = mResolver.query(uri, 2226 new String[]{Contacts.DISPLAY_NAME}, 2227 null, null, Contacts.SORT_KEY_ALTERNATIVE + " COLLATE LOCALIZED DESC"); 2228 2229 assertFirstLetterValues(cursor, "W", "S", "R", "M", "B", null); 2230 assertFirstLetterCounts(cursor, 1, 2, 1, 1, 2, 1); 2231 cursor.close(); 2232 } 2233 2234 private void assertFirstLetterValues(Cursor cursor, String... expected) { 2235 String[] actual = cursor.getExtras() 2236 .getStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES); 2237 MoreAsserts.assertEquals(expected, actual); 2238 } 2239 2240 private void assertFirstLetterCounts(Cursor cursor, int... expected) { 2241 int[] actual = cursor.getExtras() 2242 .getIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS); 2243 MoreAsserts.assertEquals(expected, actual); 2244 } 2245 2246 public void testReadBooleanQueryParameter() { 2247 assertBooleanUriParameter("foo:bar", "bool", true, true); 2248 assertBooleanUriParameter("foo:bar", "bool", false, false); 2249 assertBooleanUriParameter("foo:bar?bool=0", "bool", true, false); 2250 assertBooleanUriParameter("foo:bar?bool=1", "bool", false, true); 2251 assertBooleanUriParameter("foo:bar?bool=false", "bool", true, false); 2252 assertBooleanUriParameter("foo:bar?bool=true", "bool", false, true); 2253 assertBooleanUriParameter("foo:bar?bool=FaLsE", "bool", true, false); 2254 assertBooleanUriParameter("foo:bar?bool=false&some=some", "bool", true, false); 2255 assertBooleanUriParameter("foo:bar?bool=1&some=some", "bool", false, true); 2256 assertBooleanUriParameter("foo:bar?some=bool", "bool", true, true); 2257 assertBooleanUriParameter("foo:bar?bool", "bool", true, true); 2258 } 2259 2260 private void assertBooleanUriParameter(String uriString, String parameter, 2261 boolean defaultValue, boolean expectedValue) { 2262 assertEquals(expectedValue, ContactsProvider2.readBooleanQueryParameter( 2263 Uri.parse(uriString), parameter, defaultValue)); 2264 } 2265 2266 public void testGetQueryParameter() { 2267 assertQueryParameter("foo:bar", "param", null); 2268 assertQueryParameter("foo:bar?param", "param", null); 2269 assertQueryParameter("foo:bar?param=", "param", ""); 2270 assertQueryParameter("foo:bar?param=val", "param", "val"); 2271 assertQueryParameter("foo:bar?param=val&some=some", "param", "val"); 2272 assertQueryParameter("foo:bar?some=some¶m=val", "param", "val"); 2273 assertQueryParameter("foo:bar?some=some¶m=val&else=else", "param", "val"); 2274 assertQueryParameter("foo:bar?param=john%40doe.com", "param", "john@doe.com"); 2275 } 2276 2277 public void testMissingAccountTypeParameter() { 2278 // Try querying for RawContacts only using ACCOUNT_NAME 2279 final Uri queryUri = RawContacts.CONTENT_URI.buildUpon().appendQueryParameter( 2280 RawContacts.ACCOUNT_NAME, "lolwut").build(); 2281 try { 2282 final Cursor cursor = mResolver.query(queryUri, null, null, null, null); 2283 fail("Able to query with incomplete account query parameters"); 2284 } catch (IllegalArgumentException e) { 2285 // Expected behavior. 2286 } 2287 } 2288 2289 public void testInsertInconsistentAccountType() { 2290 // Try inserting RawContact with inconsistent Accounts 2291 final Account red = new Account("red", "red"); 2292 final Account blue = new Account("blue", "blue"); 2293 2294 final ContentValues values = new ContentValues(); 2295 values.put(RawContacts.ACCOUNT_NAME, red.name); 2296 values.put(RawContacts.ACCOUNT_TYPE, red.type); 2297 2298 final Uri insertUri = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, blue); 2299 try { 2300 mResolver.insert(insertUri, values); 2301 fail("Able to insert RawContact with inconsistent account details"); 2302 } catch (IllegalArgumentException e) { 2303 // Expected behavior. 2304 } 2305 } 2306 2307 public void testProviderStatus() throws Exception { 2308 Cursor cursor = mResolver.query(ProviderStatus.CONTENT_URI, 2309 new String[]{ProviderStatus.DATA1, ProviderStatus.STATUS}, null, null, null); 2310 assertTrue(cursor.moveToFirst()); 2311 assertEquals(0, cursor.getLong(0)); 2312 assertEquals(ProviderStatus.STATUS_NORMAL, cursor.getInt(1)); 2313 cursor.close(); 2314 } 2315 2316 public void testProperties() throws Exception { 2317 ContactsProvider2 provider = (ContactsProvider2)getProvider(); 2318 ContactsDatabaseHelper helper = (ContactsDatabaseHelper)provider.getDatabaseHelper(); 2319 assertNull(helper.getProperty("non-existent", null)); 2320 assertEquals("default", helper.getProperty("non-existent", "default")); 2321 2322 helper.setProperty("existent1", "string1"); 2323 helper.setProperty("existent2", "string2"); 2324 assertEquals("string1", helper.getProperty("existent1", "default")); 2325 assertEquals("string2", helper.getProperty("existent2", "default")); 2326 helper.setProperty("existent1", null); 2327 assertEquals("default", helper.getProperty("existent1", "default")); 2328 } 2329 2330 private class VCardTestUriCreator { 2331 private String mLookup1; 2332 private String mLookup2; 2333 2334 public VCardTestUriCreator(String lookup1, String lookup2) { 2335 super(); 2336 mLookup1 = lookup1; 2337 mLookup2 = lookup2; 2338 } 2339 2340 public Uri getUri1() { 2341 return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup1); 2342 } 2343 2344 public Uri getUri2() { 2345 return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup2); 2346 } 2347 2348 public Uri getCombinedUri() { 2349 return Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, 2350 Uri.encode(mLookup1 + ":" + mLookup2)); 2351 } 2352 } 2353 2354 private VCardTestUriCreator createVCardTestContacts() { 2355 final long rawContactId1 = createRawContact(mAccount, RawContacts.SOURCE_ID, "4:12"); 2356 insertStructuredName(rawContactId1, "John", "Doe"); 2357 2358 final long rawContactId2 = createRawContact(mAccount, RawContacts.SOURCE_ID, "3:4%121"); 2359 insertStructuredName(rawContactId2, "Jane", "Doh"); 2360 2361 final long contactId1 = queryContactId(rawContactId1); 2362 final long contactId2 = queryContactId(rawContactId2); 2363 final Uri contact1Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId1); 2364 final Uri contact2Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId2); 2365 final String lookup1 = 2366 Uri.encode(Contacts.getLookupUri(mResolver, contact1Uri).getPathSegments().get(2)); 2367 final String lookup2 = 2368 Uri.encode(Contacts.getLookupUri(mResolver, contact2Uri).getPathSegments().get(2)); 2369 return new VCardTestUriCreator(lookup1, lookup2); 2370 } 2371 2372 public void testQueryMultiVCard() { 2373 // No need to create any contacts here, because the query for multiple vcards 2374 // does not go into the database at all 2375 Uri uri = Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, Uri.encode("123:456")); 2376 Cursor cursor = mResolver.query(uri, null, null, null, null); 2377 assertEquals(1, cursor.getCount()); 2378 assertTrue(cursor.moveToFirst()); 2379 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 2380 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 2381 2382 // The resulting name contains date and time. Ensure that before and after are correct 2383 assertTrue(filename.startsWith("vcards_")); 2384 assertTrue(filename.endsWith(".vcf")); 2385 cursor.close(); 2386 } 2387 2388 public void testQueryFileSingleVCard() { 2389 final VCardTestUriCreator contacts = createVCardTestContacts(); 2390 2391 { 2392 Cursor cursor = mResolver.query(contacts.getUri1(), null, null, null, null); 2393 assertEquals(1, cursor.getCount()); 2394 assertTrue(cursor.moveToFirst()); 2395 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 2396 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 2397 assertEquals("John Doe.vcf", filename); 2398 cursor.close(); 2399 } 2400 2401 { 2402 Cursor cursor = mResolver.query(contacts.getUri2(), null, null, null, null); 2403 assertEquals(1, cursor.getCount()); 2404 assertTrue(cursor.moveToFirst()); 2405 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 2406 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 2407 assertEquals("Jane Doh.vcf", filename); 2408 cursor.close(); 2409 } 2410 } 2411 2412 2413 public void testOpenAssetFileMultiVCard() throws IOException { 2414 final VCardTestUriCreator contacts = createVCardTestContacts(); 2415 2416 final AssetFileDescriptor descriptor = 2417 mResolver.openAssetFileDescriptor(contacts.getCombinedUri(), "r"); 2418 final FileInputStream inputStream = descriptor.createInputStream(); 2419 String data = readToEnd(inputStream); 2420 inputStream.close(); 2421 descriptor.close(); 2422 2423 // Ensure that the resulting VCard has both contacts 2424 assertTrue(data.contains("N:Doe;John;;;")); 2425 assertTrue(data.contains("N:Doh;Jane;;;")); 2426 } 2427 2428 public void testOpenAssetFileSingleVCard() throws IOException { 2429 final VCardTestUriCreator contacts = createVCardTestContacts(); 2430 2431 // Ensure that the right VCard is being created in each case 2432 { 2433 final AssetFileDescriptor descriptor = 2434 mResolver.openAssetFileDescriptor(contacts.getUri1(), "r"); 2435 final FileInputStream inputStream = descriptor.createInputStream(); 2436 final String data = readToEnd(inputStream); 2437 assertTrue(data.contains("N:Doe;John;;;")); 2438 assertFalse(data.contains("N:Doh;Jane;;;")); 2439 2440 inputStream.close(); 2441 descriptor.close(); 2442 } 2443 2444 { 2445 final AssetFileDescriptor descriptor = 2446 mResolver.openAssetFileDescriptor(contacts.getUri2(), "r"); 2447 final FileInputStream inputStream = descriptor.createInputStream(); 2448 final String data = readToEnd(inputStream); 2449 inputStream.close(); 2450 descriptor.close(); 2451 2452 assertFalse(data.contains("N:Doe;John;;;")); 2453 assertTrue(data.contains("N:Doh;Jane;;;")); 2454 } 2455 } 2456 2457 public void testAutoGroupMembership() { 2458 long g1 = createGroup(mAccount, "g1", "t1", 0, true /* autoAdd */, false /* favorite */); 2459 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 2460 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, true /* autoAdd */, false /* favorite */); 2461 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, false/* favorite */); 2462 long r1 = createRawContact(mAccount); 2463 long r2 = createRawContact(mAccountTwo); 2464 long r3 = createRawContact(null); 2465 2466 Cursor c = queryGroupMemberships(mAccount); 2467 try { 2468 assertTrue(c.moveToNext()); 2469 assertEquals(g1, c.getLong(0)); 2470 assertEquals(r1, c.getLong(1)); 2471 assertFalse(c.moveToNext()); 2472 } finally { 2473 c.close(); 2474 } 2475 2476 c = queryGroupMemberships(mAccountTwo); 2477 try { 2478 assertTrue(c.moveToNext()); 2479 assertEquals(g3, c.getLong(0)); 2480 assertEquals(r2, c.getLong(1)); 2481 assertFalse(c.moveToNext()); 2482 } finally { 2483 c.close(); 2484 } 2485 } 2486 2487 public void testNoAutoAddMembershipAfterGroupCreation() { 2488 long r1 = createRawContact(mAccount); 2489 long r2 = createRawContact(mAccount); 2490 long r3 = createRawContact(mAccount); 2491 long r4 = createRawContact(mAccountTwo); 2492 long r5 = createRawContact(mAccountTwo); 2493 long r6 = createRawContact(null); 2494 2495 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 2496 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2497 2498 long g1 = createGroup(mAccount, "g1", "t1", 0, true /* autoAdd */, false /* favorite */); 2499 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 2500 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, true /* autoAdd */, false/* favorite */); 2501 2502 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 2503 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2504 } 2505 2506 // create some starred and non-starred contacts, some associated with account, some not 2507 // favorites group created 2508 // the starred contacts should be added to group 2509 // favorites group removed 2510 // no change to starred status 2511 public void testFavoritesMembershipAfterGroupCreation() { 2512 long r1 = createRawContact(mAccount, RawContacts.STARRED, "1"); 2513 long r2 = createRawContact(mAccount); 2514 long r3 = createRawContact(mAccount, RawContacts.STARRED, "1"); 2515 long r4 = createRawContact(mAccountTwo, RawContacts.STARRED, "1"); 2516 long r5 = createRawContact(mAccountTwo); 2517 long r6 = createRawContact(null, RawContacts.STARRED, "1"); 2518 long r7 = createRawContact(null); 2519 2520 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 2521 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2522 2523 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 2524 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 2525 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, false /* autoAdd */, false/* favorite */); 2526 2527 assertTrue(queryRawContactIsStarred(r1)); 2528 assertFalse(queryRawContactIsStarred(r2)); 2529 assertTrue(queryRawContactIsStarred(r3)); 2530 assertTrue(queryRawContactIsStarred(r4)); 2531 assertFalse(queryRawContactIsStarred(r5)); 2532 assertTrue(queryRawContactIsStarred(r6)); 2533 assertFalse(queryRawContactIsStarred(r7)); 2534 2535 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2536 Cursor c = queryGroupMemberships(mAccount); 2537 try { 2538 assertTrue(c.moveToNext()); 2539 assertEquals(g1, c.getLong(0)); 2540 assertEquals(r1, c.getLong(1)); 2541 assertTrue(c.moveToNext()); 2542 assertEquals(g1, c.getLong(0)); 2543 assertEquals(r3, c.getLong(1)); 2544 assertFalse(c.moveToNext()); 2545 } finally { 2546 c.close(); 2547 } 2548 2549 updateItem(RawContacts.CONTENT_URI, r6, 2550 RawContacts.ACCOUNT_NAME, mAccount.name, 2551 RawContacts.ACCOUNT_TYPE, mAccount.type); 2552 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2553 c = queryGroupMemberships(mAccount); 2554 try { 2555 assertTrue(c.moveToNext()); 2556 assertEquals(g1, c.getLong(0)); 2557 assertEquals(r1, c.getLong(1)); 2558 assertTrue(c.moveToNext()); 2559 assertEquals(g1, c.getLong(0)); 2560 assertEquals(r3, c.getLong(1)); 2561 assertTrue(c.moveToNext()); 2562 assertEquals(g1, c.getLong(0)); 2563 assertEquals(r6, c.getLong(1)); 2564 assertFalse(c.moveToNext()); 2565 } finally { 2566 c.close(); 2567 } 2568 2569 mResolver.delete(ContentUris.withAppendedId(Groups.CONTENT_URI, g1), null, null); 2570 2571 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 2572 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2573 2574 assertTrue(queryRawContactIsStarred(r1)); 2575 assertFalse(queryRawContactIsStarred(r2)); 2576 assertTrue(queryRawContactIsStarred(r3)); 2577 assertTrue(queryRawContactIsStarred(r4)); 2578 assertFalse(queryRawContactIsStarred(r5)); 2579 assertTrue(queryRawContactIsStarred(r6)); 2580 assertFalse(queryRawContactIsStarred(r7)); 2581 } 2582 2583 public void testFavoritesGroupMembershipChangeAfterStarChange() { 2584 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 2585 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false/* favorite */); 2586 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, true /* favorite */); 2587 long g5 = createGroup(mAccountTwo, "g5", "t5", 0, false /* autoAdd */, false/* favorite */); 2588 long r1 = createRawContact(mAccount, RawContacts.STARRED, "1"); 2589 long r2 = createRawContact(mAccount); 2590 long r3 = createRawContact(mAccountTwo); 2591 2592 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2593 Cursor c = queryGroupMemberships(mAccount); 2594 try { 2595 assertTrue(c.moveToNext()); 2596 assertEquals(g1, c.getLong(0)); 2597 assertEquals(r1, c.getLong(1)); 2598 assertFalse(c.moveToNext()); 2599 } finally { 2600 c.close(); 2601 } 2602 2603 // remove the star from r1 2604 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "0")); 2605 2606 // Since no raw contacts are starred, there should be no group memberships. 2607 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 2608 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2609 2610 // mark r1 as starred 2611 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "1")); 2612 // Now that r1 is starred it should have a membership in the one groups from mAccount 2613 // that is marked as a favorite. 2614 // There should be no memberships in mAccountTwo since it has no starred raw contacts. 2615 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2616 c = queryGroupMemberships(mAccount); 2617 try { 2618 assertTrue(c.moveToNext()); 2619 assertEquals(g1, c.getLong(0)); 2620 assertEquals(r1, c.getLong(1)); 2621 assertFalse(c.moveToNext()); 2622 } finally { 2623 c.close(); 2624 } 2625 2626 // remove the star from r1 2627 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "0")); 2628 // Since no raw contacts are starred, there should be no group memberships. 2629 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 2630 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2631 2632 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(r1)); 2633 assertNotNull(contactUri); 2634 2635 // mark r1 as starred via its contact lookup uri 2636 assertEquals(1, updateItem(contactUri, Contacts.STARRED, "1")); 2637 // Now that r1 is starred it should have a membership in the one groups from mAccount 2638 // that is marked as a favorite. 2639 // There should be no memberships in mAccountTwo since it has no starred raw contacts. 2640 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2641 c = queryGroupMemberships(mAccount); 2642 try { 2643 assertTrue(c.moveToNext()); 2644 assertEquals(g1, c.getLong(0)); 2645 assertEquals(r1, c.getLong(1)); 2646 assertFalse(c.moveToNext()); 2647 } finally { 2648 c.close(); 2649 } 2650 2651 // remove the star from r1 2652 updateItem(contactUri, Contacts.STARRED, "0"); 2653 // Since no raw contacts are starred, there should be no group memberships. 2654 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 2655 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2656 } 2657 2658 public void testStarChangedAfterGroupMembershipChange() { 2659 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 2660 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false/* favorite */); 2661 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, true /* favorite */); 2662 long g5 = createGroup(mAccountTwo, "g5", "t5", 0, false /* autoAdd */, false/* favorite */); 2663 long r1 = createRawContact(mAccount); 2664 long r2 = createRawContact(mAccount); 2665 long r3 = createRawContact(mAccountTwo); 2666 2667 assertFalse(queryRawContactIsStarred(r1)); 2668 assertFalse(queryRawContactIsStarred(r2)); 2669 assertFalse(queryRawContactIsStarred(r3)); 2670 2671 Cursor c; 2672 2673 // add r1 to one favorites group 2674 // r1's star should automatically be set 2675 // r1 should automatically be added to the other favorites group 2676 Uri urir1g1 = insertGroupMembership(r1, g1); 2677 assertTrue(queryRawContactIsStarred(r1)); 2678 assertFalse(queryRawContactIsStarred(r2)); 2679 assertFalse(queryRawContactIsStarred(r3)); 2680 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2681 c = queryGroupMemberships(mAccount); 2682 try { 2683 assertTrue(c.moveToNext()); 2684 assertEquals(g1, c.getLong(0)); 2685 assertEquals(r1, c.getLong(1)); 2686 assertFalse(c.moveToNext()); 2687 } finally { 2688 c.close(); 2689 } 2690 2691 // remove r1 from one favorites group 2692 mResolver.delete(urir1g1, null, null); 2693 // r1's star should no longer be set 2694 assertFalse(queryRawContactIsStarred(r1)); 2695 assertFalse(queryRawContactIsStarred(r2)); 2696 assertFalse(queryRawContactIsStarred(r3)); 2697 // there should be no membership rows 2698 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 2699 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2700 2701 // add r3 to the one favorites group for that account 2702 // r3's star should automatically be set 2703 Uri urir3g4 = insertGroupMembership(r3, g4); 2704 assertFalse(queryRawContactIsStarred(r1)); 2705 assertFalse(queryRawContactIsStarred(r2)); 2706 assertTrue(queryRawContactIsStarred(r3)); 2707 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 2708 c = queryGroupMemberships(mAccountTwo); 2709 try { 2710 assertTrue(c.moveToNext()); 2711 assertEquals(g4, c.getLong(0)); 2712 assertEquals(r3, c.getLong(1)); 2713 assertFalse(c.moveToNext()); 2714 } finally { 2715 c.close(); 2716 } 2717 2718 // remove r3 from the favorites group 2719 mResolver.delete(urir3g4, null, null); 2720 // r3's star should automatically be cleared 2721 assertFalse(queryRawContactIsStarred(r1)); 2722 assertFalse(queryRawContactIsStarred(r2)); 2723 assertFalse(queryRawContactIsStarred(r3)); 2724 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 2725 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 2726 } 2727 2728 private Cursor queryGroupMemberships(Account account) { 2729 Cursor c = mResolver.query(maybeAddAccountQueryParameters(Data.CONTENT_URI, account), 2730 new String[]{GroupMembership.GROUP_ROW_ID, GroupMembership.RAW_CONTACT_ID}, 2731 Data.MIMETYPE + "=?", new String[]{GroupMembership.CONTENT_ITEM_TYPE}, 2732 GroupMembership.GROUP_SOURCE_ID); 2733 return c; 2734 } 2735 2736 private String readToEnd(FileInputStream inputStream) { 2737 try { 2738 int ch; 2739 StringBuilder stringBuilder = new StringBuilder(); 2740 while ((ch = inputStream.read()) != -1) 2741 stringBuilder.append((char)ch); 2742 return stringBuilder.toString(); 2743 } catch (IOException e) { 2744 return null; 2745 } 2746 } 2747 2748 private void assertQueryParameter(String uriString, String parameter, String expectedValue) { 2749 assertEquals(expectedValue, ContactsProvider2.getQueryParameter( 2750 Uri.parse(uriString), parameter)); 2751 } 2752 2753 private long createContact(ContentValues values, String firstName, String givenName, 2754 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 2755 long groupId) { 2756 return queryContactId(createRawContact(values, firstName, givenName, phoneNumber, email, 2757 presenceStatus, timesContacted, starred, groupId)); 2758 } 2759 2760 private long createRawContact(ContentValues values, String firstName, String givenName, 2761 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 2762 long groupId) { 2763 long rawContactId = createRawContact(values, phoneNumber, email, presenceStatus, 2764 timesContacted, starred, groupId); 2765 insertStructuredName(rawContactId, firstName, givenName); 2766 return rawContactId; 2767 } 2768 2769 private long createRawContact(ContentValues values, String phoneNumber, String email, 2770 int presenceStatus, int timesContacted, int starred, long groupId) { 2771 values.put(RawContacts.STARRED, starred); 2772 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 2773 values.put(RawContacts.CUSTOM_RINGTONE, "beethoven5"); 2774 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 2775 values.put(RawContacts.TIMES_CONTACTED, timesContacted); 2776 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2777 long rawContactId = ContentUris.parseId(rawContactUri); 2778 Uri photoUri = insertPhoto(rawContactId); 2779 long photoId = ContentUris.parseId(photoUri); 2780 values.put(Contacts.PHOTO_ID, photoId); 2781 insertPhoneNumber(rawContactId, phoneNumber); 2782 insertEmail(rawContactId, email); 2783 2784 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, email, presenceStatus, "hacking"); 2785 2786 if (groupId != 0) { 2787 insertGroupMembership(rawContactId, groupId); 2788 } 2789 return rawContactId; 2790 } 2791 2792 private void putDataValues(ContentValues values, long rawContactId) { 2793 values.put(Data.RAW_CONTACT_ID, rawContactId); 2794 values.put(Data.MIMETYPE, "testmimetype"); 2795 values.put(Data.RES_PACKAGE, "oldpackage"); 2796 values.put(Data.IS_PRIMARY, 1); 2797 values.put(Data.IS_SUPER_PRIMARY, 1); 2798 values.put(Data.DATA1, "one"); 2799 values.put(Data.DATA2, "two"); 2800 values.put(Data.DATA3, "three"); 2801 values.put(Data.DATA4, "four"); 2802 values.put(Data.DATA5, "five"); 2803 values.put(Data.DATA6, "six"); 2804 values.put(Data.DATA7, "seven"); 2805 values.put(Data.DATA8, "eight"); 2806 values.put(Data.DATA9, "nine"); 2807 values.put(Data.DATA10, "ten"); 2808 values.put(Data.DATA11, "eleven"); 2809 values.put(Data.DATA12, "twelve"); 2810 values.put(Data.DATA13, "thirteen"); 2811 values.put(Data.DATA14, "fourteen"); 2812 values.put(Data.DATA15, "fifteen"); 2813 values.put(Data.SYNC1, "sync1"); 2814 values.put(Data.SYNC2, "sync2"); 2815 values.put(Data.SYNC3, "sync3"); 2816 values.put(Data.SYNC4, "sync4"); 2817 } 2818} 2819 2820