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