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