1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.providers.contacts; 18 19 import static com.android.providers.contacts.TestUtils.cv; 20 import static com.android.providers.contacts.TestUtils.dumpCursor; 21 22 import static org.mockito.Mockito.eq; 23 import static org.mockito.Mockito.when; 24 25 import android.accounts.Account; 26 import android.content.BroadcastReceiver; 27 import android.content.ComponentName; 28 import android.content.ContentProviderOperation; 29 import android.content.ContentProviderResult; 30 import android.content.ContentResolver; 31 import android.content.ContentUris; 32 import android.content.ContentValues; 33 import android.content.Entity; 34 import android.content.EntityIterator; 35 import android.content.Intent; 36 import android.content.res.AssetFileDescriptor; 37 import android.database.Cursor; 38 import android.database.DatabaseUtils; 39 import android.database.MatrixCursor; 40 import android.database.sqlite.SQLiteDatabase; 41 import android.net.Uri; 42 import android.os.AsyncTask; 43 import android.os.Bundle; 44 import android.provider.ContactsContract; 45 import android.provider.ContactsContract.AggregationExceptions; 46 import android.provider.ContactsContract.CommonDataKinds.Callable; 47 import android.provider.ContactsContract.CommonDataKinds.Contactables; 48 import android.provider.ContactsContract.CommonDataKinds.Email; 49 import android.provider.ContactsContract.CommonDataKinds.GroupMembership; 50 import android.provider.ContactsContract.CommonDataKinds.Im; 51 import android.provider.ContactsContract.CommonDataKinds.Organization; 52 import android.provider.ContactsContract.CommonDataKinds.Phone; 53 import android.provider.ContactsContract.CommonDataKinds.Photo; 54 import android.provider.ContactsContract.CommonDataKinds.SipAddress; 55 import android.provider.ContactsContract.CommonDataKinds.StructuredName; 56 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 57 import android.provider.ContactsContract.Contacts; 58 import android.provider.ContactsContract.Data; 59 import android.provider.ContactsContract.DataUsageFeedback; 60 import android.provider.ContactsContract.Directory; 61 import android.provider.ContactsContract.DisplayNameSources; 62 import android.provider.ContactsContract.DisplayPhoto; 63 import android.provider.ContactsContract.FullNameStyle; 64 import android.provider.ContactsContract.Groups; 65 import android.provider.ContactsContract.PhoneLookup; 66 import android.provider.ContactsContract.PhoneticNameStyle; 67 import android.provider.ContactsContract.PinnedPositions; 68 import android.provider.ContactsContract.Profile; 69 import android.provider.ContactsContract.ProviderStatus; 70 import android.provider.ContactsContract.RawContacts; 71 import android.provider.ContactsContract.RawContactsEntity; 72 import android.provider.ContactsContract.SearchSnippets; 73 import android.provider.ContactsContract.Settings; 74 import android.provider.ContactsContract.StatusUpdates; 75 import android.provider.ContactsContract.StreamItemPhotos; 76 import android.provider.ContactsContract.StreamItems; 77 import android.provider.OpenableColumns; 78 import android.telecom.PhoneAccountHandle; 79 import android.telecom.TelecomManager; 80 import android.telephony.PhoneNumberUtils; 81 import android.telephony.SubscriptionInfo; 82 import android.test.MoreAsserts; 83 import android.test.suitebuilder.annotation.LargeTest; 84 import android.text.TextUtils; 85 import android.util.ArraySet; 86 87 import com.android.internal.util.ArrayUtils; 88 import com.android.providers.contacts.ContactsActor.AlteringUserContext; 89 import com.android.providers.contacts.ContactsActor.MockUserManager; 90 import com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns; 91 import com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; 92 import com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns; 93 import com.android.providers.contacts.ContactsDatabaseHelper.DataUsageStatColumns; 94 import com.android.providers.contacts.ContactsDatabaseHelper.DbProperties; 95 import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 96 import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 97 import com.android.providers.contacts.ContactsDatabaseHelper.Tables; 98 import com.android.providers.contacts.tests.R; 99 import com.android.providers.contacts.testutil.CommonDatabaseUtils; 100 import com.android.providers.contacts.testutil.ContactUtil; 101 import com.android.providers.contacts.testutil.DataUtil; 102 import com.android.providers.contacts.testutil.DatabaseAsserts; 103 import com.android.providers.contacts.testutil.DeletedContactUtil; 104 import com.android.providers.contacts.testutil.RawContactUtil; 105 import com.android.providers.contacts.testutil.TestUtil; 106 import com.android.providers.contacts.util.NullContentProvider; 107 import com.android.providers.contacts.util.PhoneAccountHandleMigrationUtils; 108 import com.android.providers.contacts.util.UserUtils; 109 110 import com.google.android.collect.Lists; 111 import com.google.android.collect.Sets; 112 113 import java.io.FileInputStream; 114 import java.io.IOException; 115 import java.io.OutputStream; 116 import java.text.Collator; 117 import java.util.ArrayList; 118 import java.util.Arrays; 119 import java.util.HashSet; 120 import java.util.List; 121 import java.util.Locale; 122 import java.util.Set; 123 124 /** 125 * Unit tests for {@link ContactsProvider2}. 126 * 127 * Run the test like this: 128 * <code> 129 adb shell am instrument -e class com.android.providers.contacts.ContactsProvider2Test -w \ 130 com.android.providers.contacts.tests/android.test.InstrumentationTestRunner 131 * </code> 132 */ 133 @LargeTest 134 public class ContactsProvider2Test extends BaseContactsProvider2Test { 135 136 private static final String TAG = ContactsProvider2Test.class.getSimpleName(); 137 138 private static final int MIN_MATCH = 7; 139 140 static final String TELEPHONY_PACKAGE = "com.android.phone"; 141 static final String TELEPHONY_CLASS 142 = "com.android.services.telephony.TelephonyConnectionService"; 143 static final String TEST_PHONE_ACCOUNT_HANDLE_SUB_ID = "666"; 144 static final int TEST_PHONE_ACCOUNT_HANDLE_SUB_ID_INT = 666; 145 static final String TEST_PHONE_ACCOUNT_HANDLE_ICC_ID1 = "T6E6S6T6I6C6C6I6D"; 146 static final String TEST_PHONE_ACCOUNT_HANDLE_ICC_ID2 = "T5E5S5T5I5C5C5I5D"; 147 static final String TEST_COMPONENT_NAME = "foo/bar"; 148 149 private int mOldMinMatch1; 150 private int mOldMinMatch2; 151 152 ContactsDatabaseHelper mMockContactsDatabaseHelper; 153 private ContactsProvider2 mContactsProvider2; 154 private ContactsDatabaseHelper mDbHelper; 155 private BroadcastReceiver mBroadcastReceiver; 156 157 @Override setUp()158 protected void setUp() throws Exception { 159 super.setUp(); 160 mContactsProvider2 = (ContactsProvider2) getProvider(); 161 mDbHelper = mContactsProvider2.getThreadActiveDatabaseHelperForTest(); 162 mBroadcastReceiver = mContactsProvider2.getBroadcastReceiverForTest(); 163 mOldMinMatch1 = PhoneNumberUtils.getMinMatchForTest(); 164 mOldMinMatch2 = mDbHelper.getMinMatchForTest(); 165 PhoneNumberUtils.setMinMatchForTest(MIN_MATCH); 166 mDbHelper.setMinMatchForTest(MIN_MATCH); 167 } 168 169 @Override tearDown()170 protected void tearDown() throws Exception { 171 final ContactsProvider2 cp = (ContactsProvider2) getProvider(); 172 //final ContactsDatabaseHelper dbHelper = cp.getThreadActiveDatabaseHelperForTest(); 173 PhoneNumberUtils.setMinMatchForTest(mOldMinMatch1); 174 mDbHelper.setMinMatchForTest(mOldMinMatch2); 175 super.tearDown(); 176 } 177 getMockContactsDatabaseHelper(String databaseNameForTesting)178 private ContactsDatabaseHelper getMockContactsDatabaseHelper(String databaseNameForTesting) { 179 ContactsDatabaseHelper contactsDatabaseHelper = new ContactsDatabaseHelper( 180 mTestContext, databaseNameForTesting, true, /* isTestInstance=*/ false); 181 SQLiteDatabase db = contactsDatabaseHelper.getWritableDatabase(); 182 db.execSQL("DELETE FROM " + ContactsDatabaseHelper.Tables.DATA); 183 { 184 final ContentValues values = new ContentValues(); 185 values.put(ContactsDatabaseHelper.DataColumns.MIMETYPE_ID, 6666); 186 values.put(Data.RAW_CONTACT_ID, 6666); 187 values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 188 PhoneAccountHandleMigrationUtils.TELEPHONY_COMPONENT_NAME); 189 values.put(Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING, 1); 190 values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, TEST_PHONE_ACCOUNT_HANDLE_ICC_ID1); 191 long count = db.insert(ContactsDatabaseHelper.Tables.DATA, null, values); 192 } 193 { 194 final ContentValues values = new ContentValues(); 195 values.put(ContactsDatabaseHelper.DataColumns.MIMETYPE_ID, 6666); 196 values.put(Data.RAW_CONTACT_ID, 6666); 197 values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 198 PhoneAccountHandleMigrationUtils.TELEPHONY_COMPONENT_NAME); 199 values.put(Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING, 1); 200 values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, TEST_PHONE_ACCOUNT_HANDLE_ICC_ID1); 201 long count = db.insert(ContactsDatabaseHelper.Tables.DATA, null, values); 202 } 203 { 204 final ContentValues values = new ContentValues(); 205 values.put(ContactsDatabaseHelper.DataColumns.MIMETYPE_ID, 6666); 206 values.put(Data.RAW_CONTACT_ID, 6666); 207 values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 208 PhoneAccountHandleMigrationUtils.TELEPHONY_COMPONENT_NAME); 209 values.put(Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING, 1); 210 values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, TEST_PHONE_ACCOUNT_HANDLE_ICC_ID1); 211 long count = db.insert(ContactsDatabaseHelper.Tables.DATA, null, values); 212 } 213 { 214 final ContentValues values = new ContentValues(); 215 values.put(ContactsDatabaseHelper.DataColumns.MIMETYPE_ID, 6666); 216 values.put(Data.RAW_CONTACT_ID, 6666); 217 values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 218 PhoneAccountHandleMigrationUtils.TELEPHONY_COMPONENT_NAME); 219 values.put(Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING, 1); 220 values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, TEST_PHONE_ACCOUNT_HANDLE_ICC_ID1); 221 long count = db.insert(ContactsDatabaseHelper.Tables.DATA, null, values); 222 } 223 { 224 final ContentValues values = new ContentValues(); 225 values.put(ContactsDatabaseHelper.DataColumns.MIMETYPE_ID, 6666); 226 values.put(Data.RAW_CONTACT_ID, 6666); 227 values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 228 PhoneAccountHandleMigrationUtils.TELEPHONY_COMPONENT_NAME); 229 values.put(Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING, 1); 230 values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, "FAKE_ICCID"); 231 long count = db.insert(ContactsDatabaseHelper.Tables.DATA, null, values); 232 } 233 { 234 final ContentValues values = new ContentValues(); 235 values.put(ContactsDatabaseHelper.DataColumns.MIMETYPE_ID, 6666); 236 values.put(Data.RAW_CONTACT_ID, 6666); 237 values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, TEST_COMPONENT_NAME); 238 values.put(Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING, 1); 239 values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, "FAKE_ICCID"); 240 long count = db.insert(ContactsDatabaseHelper.Tables.DATA, null, values); 241 } 242 return contactsDatabaseHelper; 243 } 244 testPhoneAccountHandleMigrationSimEvent()245 public void testPhoneAccountHandleMigrationSimEvent() throws IOException { 246 ContactsDatabaseHelper originalContactsDatabaseHelper 247 = mContactsProvider2.getContactsDatabaseHelperForTest(); 248 249 // Mock SubscriptionManager 250 SubscriptionInfo subscriptionInfo = new SubscriptionInfo( 251 TEST_PHONE_ACCOUNT_HANDLE_SUB_ID_INT, TEST_PHONE_ACCOUNT_HANDLE_ICC_ID1, 252 1, "a", "b", 1, 1, "test", 1, null, null, null, null, false, null, null); 253 when(mSubscriptionManager.getActiveSubscriptionInfo( 254 eq(TEST_PHONE_ACCOUNT_HANDLE_SUB_ID_INT))).thenReturn(subscriptionInfo); 255 256 // Mock ContactsDatabaseHelper 257 ContactsDatabaseHelper contactsDatabaseHelper = getMockContactsDatabaseHelper( 258 "testContactsPhoneAccountHandleMigrationSimEvent.db"); 259 260 // Test setPhoneAccountMigrationStatusPending as false 261 PhoneAccountHandleMigrationUtils phoneAccountHandleMigrationUtils 262 = contactsDatabaseHelper.getPhoneAccountHandleMigrationUtils(); 263 264 // Test ContactsDatabaseHelper.isPhoneAccountMigrationPending as true 265 // and set for testing migration logic 266 phoneAccountHandleMigrationUtils.setPhoneAccountMigrationStatusPending(true); 267 268 mContactsProvider2.setContactsDatabaseHelperForTest(contactsDatabaseHelper); 269 final SQLiteDatabase sqLiteDatabase = contactsDatabaseHelper.getReadableDatabase(); 270 271 // Check each entry in the Data has a new coloumn of 272 // Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING that has a value of 1 273 assertEquals(6 /** pending migration entries in the preconfigured file */, 274 DatabaseUtils.longForQuery(sqLiteDatabase, 275 "select count(*) from " + ContactsDatabaseHelper.Tables.DATA 276 + " where " + Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING 277 + " = 1", null)); 278 279 // Prepare PhoneAccountHandle for the new sim event 280 PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle( 281 new ComponentName(TELEPHONY_PACKAGE, TELEPHONY_CLASS), 282 TEST_PHONE_ACCOUNT_HANDLE_SUB_ID); 283 Intent intent = new Intent(TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED); 284 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); 285 mBroadcastReceiver.onReceive(mTestContext, intent); 286 287 // Check four coloumns of Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING have migrated 288 assertEquals(4 /** entries in the preconfigured database file */, 289 DatabaseUtils.longForQuery(sqLiteDatabase, 290 "select count(*) from " + ContactsDatabaseHelper.Tables.DATA 291 + " where " + Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING 292 + " = 0", null)); 293 // Check two coloumns 294 // of Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING have not migrated 295 assertEquals(2 /** pending migration entries after migration in the preconfigured file */, 296 DatabaseUtils.longForQuery(sqLiteDatabase, 297 "select count(*) from " + ContactsDatabaseHelper.Tables.DATA 298 + " where " + Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING 299 + " = 1", null)); 300 301 mContactsProvider2.setContactsDatabaseHelperForTest(originalContactsDatabaseHelper); 302 } 303 testPhoneAccountHandleMigrationInitiation()304 public void testPhoneAccountHandleMigrationInitiation() throws IOException { 305 ContactsDatabaseHelper originalContactsDatabaseHelper 306 = mContactsProvider2.getContactsDatabaseHelperForTest(); 307 308 // Mock SubscriptionManager 309 SubscriptionInfo subscriptionInfo = new SubscriptionInfo( 310 TEST_PHONE_ACCOUNT_HANDLE_SUB_ID_INT, TEST_PHONE_ACCOUNT_HANDLE_ICC_ID1, 311 1, "a", "b", 1, 1, "test", 1, null, null, null, null, false, null, null); 312 List<SubscriptionInfo> subscriptionInfoList = new ArrayList<>(); 313 subscriptionInfoList.add(subscriptionInfo); 314 when(mSubscriptionManager.getAllSubscriptionInfoList()).thenReturn(subscriptionInfoList); 315 316 // Mock ContactsDatabaseHelper 317 ContactsDatabaseHelper contactsDatabaseHelper = getMockContactsDatabaseHelper( 318 "testContactsPhoneAccountHandleMigrationInitiation.db"); 319 320 // Test setPhoneAccountMigrationStatusPending as false 321 PhoneAccountHandleMigrationUtils phoneAccountHandleMigrationUtils 322 = contactsDatabaseHelper.getPhoneAccountHandleMigrationUtils(); 323 324 // Test ContactsDatabaseHelper.isPhoneAccountMigrationPending as true 325 // and set for testing migration logic 326 phoneAccountHandleMigrationUtils.setPhoneAccountMigrationStatusPending(true); 327 328 mContactsProvider2.setContactsDatabaseHelperForTest(contactsDatabaseHelper); 329 final SQLiteDatabase sqLiteDatabase = contactsDatabaseHelper.getReadableDatabase(); 330 331 // Check each entry in the Data has a new coloumn of 332 // Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING that has a value of 1 333 assertEquals(6, DatabaseUtils.longForQuery(sqLiteDatabase, 334 "select count(*) from " + ContactsDatabaseHelper.Tables.DATA 335 + " where " + Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING 336 + " = 1", null)); 337 338 // Prepare Task for BACKGROUND_TASK_MIGRATE_PHONE_ACCOUNT_HANDLES 339 mContactsProvider2.performBackgroundTask( 340 mContactsProvider2.BACKGROUND_TASK_MIGRATE_PHONE_ACCOUNT_HANDLES, null); 341 342 // Check four coloumns of Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING have migrated 343 assertEquals(4, DatabaseUtils.longForQuery(sqLiteDatabase, 344 "select count(*) from " + ContactsDatabaseHelper.Tables.DATA 345 + " where " + Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING 346 + " = 0", null)); 347 // Check two coloumns of Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING have not migrated 348 assertEquals(2, DatabaseUtils.longForQuery(sqLiteDatabase, 349 "select count(*) from " + ContactsDatabaseHelper.Tables.DATA 350 + " where " + Data.IS_PHONE_ACCOUNT_MIGRATION_PENDING 351 + " = 1", null)); 352 353 // Verify the pending status of phone account migration. 354 assertTrue(phoneAccountHandleMigrationUtils.isPhoneAccountMigrationPending()); 355 356 mContactsProvider2.setContactsDatabaseHelperForTest(originalContactsDatabaseHelper); 357 } 358 testPhoneAccountHandleMigrationPendingStatus()359 public void testPhoneAccountHandleMigrationPendingStatus() { 360 // Mock ContactsDatabaseHelper 361 ContactsDatabaseHelper contactsDatabaseHelper = getMockContactsDatabaseHelper( 362 "testPhoneAccountHandleMigrationPendingStatus.db"); 363 364 // Test setPhoneAccountMigrationStatusPending as false 365 PhoneAccountHandleMigrationUtils phoneAccountHandleMigrationUtils 366 = contactsDatabaseHelper.getPhoneAccountHandleMigrationUtils(); 367 phoneAccountHandleMigrationUtils.setPhoneAccountMigrationStatusPending(false); 368 assertFalse(phoneAccountHandleMigrationUtils.isPhoneAccountMigrationPending()); 369 370 // Test ContactsDatabaseHelper.isPhoneAccountMigrationPending as true 371 // and set for testing migration logic 372 phoneAccountHandleMigrationUtils.setPhoneAccountMigrationStatusPending(true); 373 assertTrue(phoneAccountHandleMigrationUtils.isPhoneAccountMigrationPending()); 374 } 375 testConvertEnterpriseUriWithEnterpriseDirectoryToLocalUri()376 public void testConvertEnterpriseUriWithEnterpriseDirectoryToLocalUri() { 377 String phoneNumber = "886"; 378 String directory = String.valueOf(Directory.ENTERPRISE_DEFAULT); 379 boolean isSip = true; 380 Uri enterpriseUri = Phone.ENTERPRISE_CONTENT_URI.buildUpon().appendPath(phoneNumber) 381 .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, directory) 382 .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, 383 String.valueOf(isSip)).build(); 384 Uri localUri = ContactsProvider2.convertToLocalUri(enterpriseUri, Phone.CONTENT_URI); 385 Uri expectedUri = Phone.CONTENT_URI.buildUpon().appendPath(phoneNumber) 386 .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 387 String.valueOf(Directory.DEFAULT)) 388 .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, 389 String.valueOf(isSip)).build(); 390 assertUriEquals(expectedUri, localUri); 391 } 392 testConvertEnterpriseUriWithPersonalDirectoryToLocalUri()393 public void testConvertEnterpriseUriWithPersonalDirectoryToLocalUri() { 394 String phoneNumber = "886"; 395 String directory = String.valueOf(Directory.DEFAULT); 396 boolean isSip = true; 397 Uri enterpriseUri = Phone.ENTERPRISE_CONTENT_URI.buildUpon().appendPath(phoneNumber) 398 .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, directory) 399 .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, 400 String.valueOf(isSip)).build(); 401 Uri localUri = ContactsProvider2.convertToLocalUri(enterpriseUri, Phone.CONTENT_URI); 402 Uri expectedUri = Phone.CONTENT_URI.buildUpon().appendPath(phoneNumber) 403 .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 404 String.valueOf(Directory.DEFAULT)) 405 .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, 406 String.valueOf(isSip)).build(); 407 assertUriEquals(expectedUri, localUri); 408 } 409 testConvertEnterpriseUriWithoutDirectoryToLocalUri()410 public void testConvertEnterpriseUriWithoutDirectoryToLocalUri() { 411 String phoneNumber = "886"; 412 boolean isSip = true; 413 Uri enterpriseUri = Phone.ENTERPRISE_CONTENT_URI.buildUpon().appendPath(phoneNumber) 414 .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, 415 String.valueOf(isSip)).build(); 416 Uri localUri = ContactsProvider2.convertToLocalUri(enterpriseUri, Phone.CONTENT_URI); 417 Uri expectedUri = Phone.CONTENT_URI.buildUpon().appendPath(phoneNumber) 418 .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, 419 String.valueOf(isSip)).build(); 420 assertUriEquals(expectedUri, localUri); 421 } 422 testContactsProjection()423 public void testContactsProjection() { 424 assertProjection(Contacts.CONTENT_URI, new String[]{ 425 Contacts._ID, 426 Contacts.DISPLAY_NAME_PRIMARY, 427 Contacts.DISPLAY_NAME_ALTERNATIVE, 428 Contacts.DISPLAY_NAME_SOURCE, 429 Contacts.PHONETIC_NAME, 430 Contacts.PHONETIC_NAME_STYLE, 431 Contacts.SORT_KEY_PRIMARY, 432 Contacts.SORT_KEY_ALTERNATIVE, 433 ContactsColumns.PHONEBOOK_LABEL_PRIMARY, 434 ContactsColumns.PHONEBOOK_BUCKET_PRIMARY, 435 ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, 436 ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE, 437 Contacts.LAST_TIME_CONTACTED, 438 Contacts.TIMES_CONTACTED, 439 Contacts.STARRED, 440 Contacts.PINNED, 441 Contacts.IN_DEFAULT_DIRECTORY, 442 Contacts.IN_VISIBLE_GROUP, 443 Contacts.PHOTO_ID, 444 Contacts.PHOTO_FILE_ID, 445 Contacts.PHOTO_URI, 446 Contacts.PHOTO_THUMBNAIL_URI, 447 Contacts.CUSTOM_RINGTONE, 448 Contacts.HAS_PHONE_NUMBER, 449 Contacts.SEND_TO_VOICEMAIL, 450 Contacts.IS_USER_PROFILE, 451 Contacts.LOOKUP_KEY, 452 Contacts.NAME_RAW_CONTACT_ID, 453 Contacts.CONTACT_PRESENCE, 454 Contacts.CONTACT_CHAT_CAPABILITY, 455 Contacts.CONTACT_STATUS, 456 Contacts.CONTACT_STATUS_TIMESTAMP, 457 Contacts.CONTACT_STATUS_RES_PACKAGE, 458 Contacts.CONTACT_STATUS_LABEL, 459 Contacts.CONTACT_STATUS_ICON, 460 Contacts.CONTACT_LAST_UPDATED_TIMESTAMP 461 }); 462 } 463 testContactsStrequentProjection()464 public void testContactsStrequentProjection() { 465 assertProjection(Contacts.CONTENT_STREQUENT_URI, new String[]{ 466 Contacts._ID, 467 Contacts.DISPLAY_NAME_PRIMARY, 468 Contacts.DISPLAY_NAME_ALTERNATIVE, 469 Contacts.DISPLAY_NAME_SOURCE, 470 Contacts.PHONETIC_NAME, 471 Contacts.PHONETIC_NAME_STYLE, 472 Contacts.SORT_KEY_PRIMARY, 473 Contacts.SORT_KEY_ALTERNATIVE, 474 ContactsColumns.PHONEBOOK_LABEL_PRIMARY, 475 ContactsColumns.PHONEBOOK_BUCKET_PRIMARY, 476 ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, 477 ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE, 478 Contacts.LAST_TIME_CONTACTED, 479 Contacts.TIMES_CONTACTED, 480 Contacts.STARRED, 481 Contacts.PINNED, 482 Contacts.IN_DEFAULT_DIRECTORY, 483 Contacts.IN_VISIBLE_GROUP, 484 Contacts.PHOTO_ID, 485 Contacts.PHOTO_FILE_ID, 486 Contacts.PHOTO_URI, 487 Contacts.PHOTO_THUMBNAIL_URI, 488 Contacts.CUSTOM_RINGTONE, 489 Contacts.HAS_PHONE_NUMBER, 490 Contacts.SEND_TO_VOICEMAIL, 491 Contacts.IS_USER_PROFILE, 492 Contacts.LOOKUP_KEY, 493 Contacts.NAME_RAW_CONTACT_ID, 494 Contacts.CONTACT_PRESENCE, 495 Contacts.CONTACT_CHAT_CAPABILITY, 496 Contacts.CONTACT_STATUS, 497 Contacts.CONTACT_STATUS_TIMESTAMP, 498 Contacts.CONTACT_STATUS_RES_PACKAGE, 499 Contacts.CONTACT_STATUS_LABEL, 500 Contacts.CONTACT_STATUS_ICON, 501 Contacts.CONTACT_LAST_UPDATED_TIMESTAMP, 502 DataUsageStatColumns.LR_TIMES_USED, 503 DataUsageStatColumns.LR_LAST_TIME_USED, 504 }); 505 } 506 testContactsStrequentPhoneOnlyProjection()507 public void testContactsStrequentPhoneOnlyProjection() { 508 assertProjection(Contacts.CONTENT_STREQUENT_URI.buildUpon() 509 .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true").build(), 510 new String[] { 511 Contacts._ID, 512 Contacts.DISPLAY_NAME_PRIMARY, 513 Contacts.DISPLAY_NAME_ALTERNATIVE, 514 Contacts.DISPLAY_NAME_SOURCE, 515 Contacts.PHONETIC_NAME, 516 Contacts.PHONETIC_NAME_STYLE, 517 Contacts.SORT_KEY_PRIMARY, 518 Contacts.SORT_KEY_ALTERNATIVE, 519 ContactsColumns.PHONEBOOK_LABEL_PRIMARY, 520 ContactsColumns.PHONEBOOK_BUCKET_PRIMARY, 521 ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, 522 ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE, 523 Contacts.LAST_TIME_CONTACTED, 524 Contacts.TIMES_CONTACTED, 525 Contacts.STARRED, 526 Contacts.PINNED, 527 Contacts.IN_DEFAULT_DIRECTORY, 528 Contacts.IN_VISIBLE_GROUP, 529 Contacts.PHOTO_ID, 530 Contacts.PHOTO_FILE_ID, 531 Contacts.PHOTO_URI, 532 Contacts.PHOTO_THUMBNAIL_URI, 533 Contacts.CUSTOM_RINGTONE, 534 Contacts.HAS_PHONE_NUMBER, 535 Contacts.SEND_TO_VOICEMAIL, 536 Contacts.IS_USER_PROFILE, 537 Contacts.LOOKUP_KEY, 538 Contacts.NAME_RAW_CONTACT_ID, 539 Contacts.CONTACT_PRESENCE, 540 Contacts.CONTACT_CHAT_CAPABILITY, 541 Contacts.CONTACT_STATUS, 542 Contacts.CONTACT_STATUS_TIMESTAMP, 543 Contacts.CONTACT_STATUS_RES_PACKAGE, 544 Contacts.CONTACT_STATUS_LABEL, 545 Contacts.CONTACT_STATUS_ICON, 546 Contacts.CONTACT_LAST_UPDATED_TIMESTAMP, 547 DataUsageStatColumns.LR_TIMES_USED, 548 DataUsageStatColumns.LR_LAST_TIME_USED, 549 Phone.NUMBER, 550 Phone.TYPE, 551 Phone.LABEL, 552 Phone.IS_SUPER_PRIMARY, 553 Phone.CONTACT_ID 554 }); 555 } 556 testContactsWithSnippetProjection()557 public void testContactsWithSnippetProjection() { 558 assertProjection(Contacts.CONTENT_FILTER_URI.buildUpon().appendPath("nothing").build(), 559 new String[]{ 560 Contacts._ID, 561 Contacts.DISPLAY_NAME_PRIMARY, 562 Contacts.DISPLAY_NAME_ALTERNATIVE, 563 Contacts.DISPLAY_NAME_SOURCE, 564 Contacts.PHONETIC_NAME, 565 Contacts.PHONETIC_NAME_STYLE, 566 Contacts.SORT_KEY_PRIMARY, 567 Contacts.SORT_KEY_ALTERNATIVE, 568 ContactsColumns.PHONEBOOK_LABEL_PRIMARY, 569 ContactsColumns.PHONEBOOK_BUCKET_PRIMARY, 570 ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, 571 ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE, 572 Contacts.LAST_TIME_CONTACTED, 573 Contacts.TIMES_CONTACTED, 574 Contacts.STARRED, 575 Contacts.PINNED, 576 Contacts.IN_DEFAULT_DIRECTORY, 577 Contacts.IN_VISIBLE_GROUP, 578 Contacts.PHOTO_ID, 579 Contacts.PHOTO_FILE_ID, 580 Contacts.PHOTO_URI, 581 Contacts.PHOTO_THUMBNAIL_URI, 582 Contacts.CUSTOM_RINGTONE, 583 Contacts.HAS_PHONE_NUMBER, 584 Contacts.SEND_TO_VOICEMAIL, 585 Contacts.IS_USER_PROFILE, 586 Contacts.LOOKUP_KEY, 587 Contacts.NAME_RAW_CONTACT_ID, 588 Contacts.CONTACT_PRESENCE, 589 Contacts.CONTACT_CHAT_CAPABILITY, 590 Contacts.CONTACT_STATUS, 591 Contacts.CONTACT_STATUS_TIMESTAMP, 592 Contacts.CONTACT_STATUS_RES_PACKAGE, 593 Contacts.CONTACT_STATUS_LABEL, 594 Contacts.CONTACT_STATUS_ICON, 595 Contacts.CONTACT_LAST_UPDATED_TIMESTAMP, 596 SearchSnippets.SNIPPET, 597 }); 598 } 599 testRawContactsProjection()600 public void testRawContactsProjection() { 601 assertProjection(RawContacts.CONTENT_URI, new String[]{ 602 RawContacts._ID, 603 RawContacts.CONTACT_ID, 604 RawContacts.ACCOUNT_NAME, 605 RawContacts.ACCOUNT_TYPE, 606 RawContacts.DATA_SET, 607 RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 608 RawContacts.SOURCE_ID, 609 RawContacts.BACKUP_ID, 610 RawContacts.VERSION, 611 RawContacts.RAW_CONTACT_IS_USER_PROFILE, 612 RawContacts.DIRTY, 613 RawContacts.METADATA_DIRTY, 614 RawContacts.DELETED, 615 RawContacts.DISPLAY_NAME_PRIMARY, 616 RawContacts.DISPLAY_NAME_ALTERNATIVE, 617 RawContacts.DISPLAY_NAME_SOURCE, 618 RawContacts.PHONETIC_NAME, 619 RawContacts.PHONETIC_NAME_STYLE, 620 RawContacts.SORT_KEY_PRIMARY, 621 RawContacts.SORT_KEY_ALTERNATIVE, 622 RawContactsColumns.PHONEBOOK_LABEL_PRIMARY, 623 RawContactsColumns.PHONEBOOK_BUCKET_PRIMARY, 624 RawContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, 625 RawContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE, 626 RawContacts.TIMES_CONTACTED, 627 RawContacts.LAST_TIME_CONTACTED, 628 RawContacts.CUSTOM_RINGTONE, 629 RawContacts.SEND_TO_VOICEMAIL, 630 RawContacts.STARRED, 631 RawContacts.PINNED, 632 RawContacts.AGGREGATION_MODE, 633 RawContacts.SYNC1, 634 RawContacts.SYNC2, 635 RawContacts.SYNC3, 636 RawContacts.SYNC4, 637 }); 638 } 639 testDataProjection()640 public void testDataProjection() { 641 assertProjection(Data.CONTENT_URI, new String[]{ 642 Data._ID, 643 Data.RAW_CONTACT_ID, 644 Data.HASH_ID, 645 Data.DATA_VERSION, 646 Data.IS_PRIMARY, 647 Data.IS_SUPER_PRIMARY, 648 Data.RES_PACKAGE, 649 Data.MIMETYPE, 650 Data.DATA1, 651 Data.DATA2, 652 Data.DATA3, 653 Data.DATA4, 654 Data.DATA5, 655 Data.DATA6, 656 Data.DATA7, 657 Data.DATA8, 658 Data.DATA9, 659 Data.DATA10, 660 Data.DATA11, 661 Data.DATA12, 662 Data.DATA13, 663 Data.DATA14, 664 Data.DATA15, 665 Data.CARRIER_PRESENCE, 666 Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 667 Data.PREFERRED_PHONE_ACCOUNT_ID, 668 Data.SYNC1, 669 Data.SYNC2, 670 Data.SYNC3, 671 Data.SYNC4, 672 Data.CONTACT_ID, 673 Data.PRESENCE, 674 Data.CHAT_CAPABILITY, 675 Data.STATUS, 676 Data.STATUS_TIMESTAMP, 677 Data.STATUS_RES_PACKAGE, 678 Data.STATUS_LABEL, 679 Data.STATUS_ICON, 680 Data.TIMES_USED, 681 Data.LAST_TIME_USED, 682 RawContacts.ACCOUNT_NAME, 683 RawContacts.ACCOUNT_TYPE, 684 RawContacts.DATA_SET, 685 RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 686 RawContacts.SOURCE_ID, 687 RawContacts.BACKUP_ID, 688 RawContacts.VERSION, 689 RawContacts.DIRTY, 690 RawContacts.RAW_CONTACT_IS_USER_PROFILE, 691 Contacts._ID, 692 Contacts.DISPLAY_NAME_PRIMARY, 693 Contacts.DISPLAY_NAME_ALTERNATIVE, 694 Contacts.DISPLAY_NAME_SOURCE, 695 Contacts.PHONETIC_NAME, 696 Contacts.PHONETIC_NAME_STYLE, 697 Contacts.SORT_KEY_PRIMARY, 698 Contacts.SORT_KEY_ALTERNATIVE, 699 ContactsColumns.PHONEBOOK_LABEL_PRIMARY, 700 ContactsColumns.PHONEBOOK_BUCKET_PRIMARY, 701 ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, 702 ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE, 703 Contacts.LAST_TIME_CONTACTED, 704 Contacts.TIMES_CONTACTED, 705 Contacts.STARRED, 706 Contacts.PINNED, 707 Contacts.IN_DEFAULT_DIRECTORY, 708 Contacts.IN_VISIBLE_GROUP, 709 Contacts.PHOTO_ID, 710 Contacts.PHOTO_FILE_ID, 711 Contacts.PHOTO_URI, 712 Contacts.PHOTO_THUMBNAIL_URI, 713 Contacts.CUSTOM_RINGTONE, 714 Contacts.SEND_TO_VOICEMAIL, 715 Contacts.LOOKUP_KEY, 716 Contacts.NAME_RAW_CONTACT_ID, 717 Contacts.HAS_PHONE_NUMBER, 718 Contacts.CONTACT_PRESENCE, 719 Contacts.CONTACT_CHAT_CAPABILITY, 720 Contacts.CONTACT_STATUS, 721 Contacts.CONTACT_STATUS_TIMESTAMP, 722 Contacts.CONTACT_STATUS_RES_PACKAGE, 723 Contacts.CONTACT_STATUS_LABEL, 724 Contacts.CONTACT_STATUS_ICON, 725 Contacts.CONTACT_LAST_UPDATED_TIMESTAMP, 726 GroupMembership.GROUP_SOURCE_ID, 727 }); 728 } 729 testDistinctDataProjection()730 public void testDistinctDataProjection() { 731 assertProjection(Phone.CONTENT_FILTER_URI.buildUpon().appendPath("123").build(), 732 new String[]{ 733 Data._ID, 734 Data.HASH_ID, 735 Data.DATA_VERSION, 736 Data.IS_PRIMARY, 737 Data.IS_SUPER_PRIMARY, 738 Data.RES_PACKAGE, 739 Data.MIMETYPE, 740 Data.DATA1, 741 Data.DATA2, 742 Data.DATA3, 743 Data.DATA4, 744 Data.DATA5, 745 Data.DATA6, 746 Data.DATA7, 747 Data.DATA8, 748 Data.DATA9, 749 Data.DATA10, 750 Data.DATA11, 751 Data.DATA12, 752 Data.DATA13, 753 Data.DATA14, 754 Data.DATA15, 755 Data.CARRIER_PRESENCE, 756 Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 757 Data.PREFERRED_PHONE_ACCOUNT_ID, 758 Data.SYNC1, 759 Data.SYNC2, 760 Data.SYNC3, 761 Data.SYNC4, 762 Data.CONTACT_ID, 763 Data.PRESENCE, 764 Data.CHAT_CAPABILITY, 765 Data.STATUS, 766 Data.STATUS_TIMESTAMP, 767 Data.STATUS_RES_PACKAGE, 768 Data.STATUS_LABEL, 769 Data.STATUS_ICON, 770 Data.TIMES_USED, 771 Data.LAST_TIME_USED, 772 RawContacts.RAW_CONTACT_IS_USER_PROFILE, 773 Contacts._ID, 774 Contacts.DISPLAY_NAME_PRIMARY, 775 Contacts.DISPLAY_NAME_ALTERNATIVE, 776 Contacts.DISPLAY_NAME_SOURCE, 777 Contacts.PHONETIC_NAME, 778 Contacts.PHONETIC_NAME_STYLE, 779 Contacts.SORT_KEY_PRIMARY, 780 Contacts.SORT_KEY_ALTERNATIVE, 781 ContactsColumns.PHONEBOOK_LABEL_PRIMARY, 782 ContactsColumns.PHONEBOOK_BUCKET_PRIMARY, 783 ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, 784 ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE, 785 Contacts.LAST_TIME_CONTACTED, 786 Contacts.TIMES_CONTACTED, 787 Contacts.STARRED, 788 Contacts.PINNED, 789 Contacts.IN_DEFAULT_DIRECTORY, 790 Contacts.IN_VISIBLE_GROUP, 791 Contacts.PHOTO_ID, 792 Contacts.PHOTO_FILE_ID, 793 Contacts.PHOTO_URI, 794 Contacts.PHOTO_THUMBNAIL_URI, 795 Contacts.HAS_PHONE_NUMBER, 796 Contacts.CUSTOM_RINGTONE, 797 Contacts.SEND_TO_VOICEMAIL, 798 Contacts.LOOKUP_KEY, 799 Contacts.CONTACT_PRESENCE, 800 Contacts.CONTACT_CHAT_CAPABILITY, 801 Contacts.CONTACT_STATUS, 802 Contacts.CONTACT_STATUS_TIMESTAMP, 803 Contacts.CONTACT_STATUS_RES_PACKAGE, 804 Contacts.CONTACT_STATUS_LABEL, 805 Contacts.CONTACT_STATUS_ICON, 806 Contacts.CONTACT_LAST_UPDATED_TIMESTAMP, 807 GroupMembership.GROUP_SOURCE_ID, 808 }); 809 } 810 testEntityProjection()811 public void testEntityProjection() { 812 assertProjection( 813 Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, 0), 814 Contacts.Entity.CONTENT_DIRECTORY), 815 new String[]{ 816 Contacts.Entity._ID, 817 Contacts.Entity.DATA_ID, 818 Contacts.Entity.RAW_CONTACT_ID, 819 Data.DATA_VERSION, 820 Data.IS_PRIMARY, 821 Data.IS_SUPER_PRIMARY, 822 Data.RES_PACKAGE, 823 Data.MIMETYPE, 824 Data.DATA1, 825 Data.DATA2, 826 Data.DATA3, 827 Data.DATA4, 828 Data.DATA5, 829 Data.DATA6, 830 Data.DATA7, 831 Data.DATA8, 832 Data.DATA9, 833 Data.DATA10, 834 Data.DATA11, 835 Data.DATA12, 836 Data.DATA13, 837 Data.DATA14, 838 Data.DATA15, 839 Data.CARRIER_PRESENCE, 840 Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 841 Data.PREFERRED_PHONE_ACCOUNT_ID, 842 Data.SYNC1, 843 Data.SYNC2, 844 Data.SYNC3, 845 Data.SYNC4, 846 Data.CONTACT_ID, 847 Data.PRESENCE, 848 Data.CHAT_CAPABILITY, 849 Data.STATUS, 850 Data.STATUS_TIMESTAMP, 851 Data.STATUS_RES_PACKAGE, 852 Data.STATUS_LABEL, 853 Data.STATUS_ICON, 854 RawContacts.ACCOUNT_NAME, 855 RawContacts.ACCOUNT_TYPE, 856 RawContacts.DATA_SET, 857 RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 858 RawContacts.SOURCE_ID, 859 RawContacts.BACKUP_ID, 860 RawContacts.VERSION, 861 RawContacts.DELETED, 862 RawContacts.DIRTY, 863 RawContacts.SYNC1, 864 RawContacts.SYNC2, 865 RawContacts.SYNC3, 866 RawContacts.SYNC4, 867 Contacts._ID, 868 Contacts.DISPLAY_NAME_PRIMARY, 869 Contacts.DISPLAY_NAME_ALTERNATIVE, 870 Contacts.DISPLAY_NAME_SOURCE, 871 Contacts.PHONETIC_NAME, 872 Contacts.PHONETIC_NAME_STYLE, 873 Contacts.SORT_KEY_PRIMARY, 874 Contacts.SORT_KEY_ALTERNATIVE, 875 ContactsColumns.PHONEBOOK_LABEL_PRIMARY, 876 ContactsColumns.PHONEBOOK_BUCKET_PRIMARY, 877 ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, 878 ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE, 879 Contacts.LAST_TIME_CONTACTED, 880 Contacts.TIMES_CONTACTED, 881 Contacts.STARRED, 882 Contacts.PINNED, 883 Contacts.IN_DEFAULT_DIRECTORY, 884 Contacts.IN_VISIBLE_GROUP, 885 Contacts.PHOTO_ID, 886 Contacts.PHOTO_FILE_ID, 887 Contacts.PHOTO_URI, 888 Contacts.PHOTO_THUMBNAIL_URI, 889 Contacts.CUSTOM_RINGTONE, 890 Contacts.SEND_TO_VOICEMAIL, 891 Contacts.IS_USER_PROFILE, 892 Contacts.LOOKUP_KEY, 893 Contacts.NAME_RAW_CONTACT_ID, 894 Contacts.HAS_PHONE_NUMBER, 895 Contacts.CONTACT_PRESENCE, 896 Contacts.CONTACT_CHAT_CAPABILITY, 897 Contacts.CONTACT_STATUS, 898 Contacts.CONTACT_STATUS_TIMESTAMP, 899 Contacts.CONTACT_STATUS_RES_PACKAGE, 900 Contacts.CONTACT_STATUS_LABEL, 901 Contacts.CONTACT_STATUS_ICON, 902 Contacts.CONTACT_LAST_UPDATED_TIMESTAMP, 903 GroupMembership.GROUP_SOURCE_ID, 904 Contacts.Entity.TIMES_USED, 905 Contacts.Entity.LAST_TIME_USED, 906 }); 907 } 908 testRawEntityProjection()909 public void testRawEntityProjection() { 910 assertProjection(RawContactsEntity.CONTENT_URI, new String[]{ 911 RawContacts.Entity.DATA_ID, 912 RawContacts._ID, 913 RawContacts.CONTACT_ID, 914 RawContacts.ACCOUNT_NAME, 915 RawContacts.ACCOUNT_TYPE, 916 RawContacts.DATA_SET, 917 RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 918 RawContacts.SOURCE_ID, 919 RawContacts.BACKUP_ID, 920 RawContacts.VERSION, 921 RawContacts.DIRTY, 922 RawContacts.DELETED, 923 RawContacts.SYNC1, 924 RawContacts.SYNC2, 925 RawContacts.SYNC3, 926 RawContacts.SYNC4, 927 RawContacts.STARRED, 928 RawContacts.RAW_CONTACT_IS_USER_PROFILE, 929 Data.DATA_VERSION, 930 Data.IS_PRIMARY, 931 Data.IS_SUPER_PRIMARY, 932 Data.RES_PACKAGE, 933 Data.MIMETYPE, 934 Data.DATA1, 935 Data.DATA2, 936 Data.DATA3, 937 Data.DATA4, 938 Data.DATA5, 939 Data.DATA6, 940 Data.DATA7, 941 Data.DATA8, 942 Data.DATA9, 943 Data.DATA10, 944 Data.DATA11, 945 Data.DATA12, 946 Data.DATA13, 947 Data.DATA14, 948 Data.DATA15, 949 Data.CARRIER_PRESENCE, 950 Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 951 Data.PREFERRED_PHONE_ACCOUNT_ID, 952 Data.SYNC1, 953 Data.SYNC2, 954 Data.SYNC3, 955 Data.SYNC4, 956 GroupMembership.GROUP_SOURCE_ID, 957 }); 958 } 959 testPhoneLookupProjection()960 public void testPhoneLookupProjection() { 961 assertProjection(PhoneLookup.CONTENT_FILTER_URI.buildUpon().appendPath("123").build(), 962 new String[]{ 963 PhoneLookup._ID, 964 PhoneLookup.CONTACT_ID, 965 PhoneLookup.DATA_ID, 966 PhoneLookup.LOOKUP_KEY, 967 PhoneLookup.DISPLAY_NAME_SOURCE, 968 PhoneLookup.DISPLAY_NAME, 969 PhoneLookup.DISPLAY_NAME_ALTERNATIVE, 970 PhoneLookup.PHONETIC_NAME, 971 PhoneLookup.PHONETIC_NAME_STYLE, 972 PhoneLookup.SORT_KEY_PRIMARY, 973 PhoneLookup.SORT_KEY_ALTERNATIVE, 974 PhoneLookup.LAST_TIME_CONTACTED, 975 PhoneLookup.TIMES_CONTACTED, 976 PhoneLookup.STARRED, 977 PhoneLookup.IN_DEFAULT_DIRECTORY, 978 PhoneLookup.IN_VISIBLE_GROUP, 979 PhoneLookup.PHOTO_FILE_ID, 980 PhoneLookup.PHOTO_ID, 981 PhoneLookup.PHOTO_URI, 982 PhoneLookup.PHOTO_THUMBNAIL_URI, 983 PhoneLookup.CUSTOM_RINGTONE, 984 PhoneLookup.HAS_PHONE_NUMBER, 985 PhoneLookup.SEND_TO_VOICEMAIL, 986 PhoneLookup.NUMBER, 987 PhoneLookup.TYPE, 988 PhoneLookup.LABEL, 989 PhoneLookup.NORMALIZED_NUMBER, 990 Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 991 Data.PREFERRED_PHONE_ACCOUNT_ID, 992 }); 993 } 994 testPhoneLookupEnterpriseProjection()995 public void testPhoneLookupEnterpriseProjection() { 996 assertProjection(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI 997 .buildUpon().appendPath("123").build(), 998 new String[]{ 999 PhoneLookup._ID, 1000 PhoneLookup.CONTACT_ID, 1001 PhoneLookup.DATA_ID, 1002 PhoneLookup.LOOKUP_KEY, 1003 PhoneLookup.DISPLAY_NAME_SOURCE, 1004 PhoneLookup.DISPLAY_NAME, 1005 PhoneLookup.DISPLAY_NAME_ALTERNATIVE, 1006 PhoneLookup.PHONETIC_NAME, 1007 PhoneLookup.PHONETIC_NAME_STYLE, 1008 PhoneLookup.SORT_KEY_PRIMARY, 1009 PhoneLookup.SORT_KEY_ALTERNATIVE, 1010 PhoneLookup.LAST_TIME_CONTACTED, 1011 PhoneLookup.TIMES_CONTACTED, 1012 PhoneLookup.STARRED, 1013 PhoneLookup.IN_DEFAULT_DIRECTORY, 1014 PhoneLookup.IN_VISIBLE_GROUP, 1015 PhoneLookup.PHOTO_FILE_ID, 1016 PhoneLookup.PHOTO_ID, 1017 PhoneLookup.PHOTO_URI, 1018 PhoneLookup.PHOTO_THUMBNAIL_URI, 1019 PhoneLookup.CUSTOM_RINGTONE, 1020 PhoneLookup.HAS_PHONE_NUMBER, 1021 PhoneLookup.SEND_TO_VOICEMAIL, 1022 PhoneLookup.NUMBER, 1023 PhoneLookup.TYPE, 1024 PhoneLookup.LABEL, 1025 PhoneLookup.NORMALIZED_NUMBER, 1026 Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, 1027 Data.PREFERRED_PHONE_ACCOUNT_ID, 1028 }); 1029 } 1030 testSipPhoneLookupProjection()1031 public void testSipPhoneLookupProjection() { 1032 assertContainProjection(PhoneLookup.CONTENT_FILTER_URI.buildUpon().appendPath("123") 1033 .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, "1") 1034 .build(), 1035 new String[] { 1036 PhoneLookup._ID, 1037 PhoneLookup.CONTACT_ID, 1038 PhoneLookup.DATA_ID, 1039 PhoneLookup.LOOKUP_KEY, 1040 PhoneLookup.DISPLAY_NAME, 1041 PhoneLookup.LAST_TIME_CONTACTED, 1042 PhoneLookup.TIMES_CONTACTED, 1043 PhoneLookup.STARRED, 1044 PhoneLookup.IN_DEFAULT_DIRECTORY, 1045 PhoneLookup.IN_VISIBLE_GROUP, 1046 PhoneLookup.PHOTO_FILE_ID, 1047 PhoneLookup.PHOTO_ID, 1048 PhoneLookup.PHOTO_URI, 1049 PhoneLookup.PHOTO_THUMBNAIL_URI, 1050 PhoneLookup.CUSTOM_RINGTONE, 1051 PhoneLookup.HAS_PHONE_NUMBER, 1052 PhoneLookup.SEND_TO_VOICEMAIL, 1053 PhoneLookup.NUMBER, 1054 PhoneLookup.TYPE, 1055 PhoneLookup.LABEL, 1056 PhoneLookup.NORMALIZED_NUMBER, 1057 }); 1058 } 1059 testSipPhoneLookupEnterpriseProjection()1060 public void testSipPhoneLookupEnterpriseProjection() { 1061 assertContainProjection(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI 1062 .buildUpon() 1063 .appendPath("123") 1064 .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, "1") 1065 .build(), 1066 new String[] { 1067 PhoneLookup._ID, 1068 PhoneLookup.CONTACT_ID, 1069 PhoneLookup.DATA_ID, 1070 PhoneLookup.LOOKUP_KEY, 1071 PhoneLookup.DISPLAY_NAME, 1072 PhoneLookup.LAST_TIME_CONTACTED, 1073 PhoneLookup.TIMES_CONTACTED, 1074 PhoneLookup.STARRED, 1075 PhoneLookup.IN_DEFAULT_DIRECTORY, 1076 PhoneLookup.IN_VISIBLE_GROUP, 1077 PhoneLookup.PHOTO_FILE_ID, 1078 PhoneLookup.PHOTO_ID, 1079 PhoneLookup.PHOTO_URI, 1080 PhoneLookup.PHOTO_THUMBNAIL_URI, 1081 PhoneLookup.CUSTOM_RINGTONE, 1082 PhoneLookup.HAS_PHONE_NUMBER, 1083 PhoneLookup.SEND_TO_VOICEMAIL, 1084 PhoneLookup.NUMBER, 1085 PhoneLookup.TYPE, 1086 PhoneLookup.LABEL, 1087 PhoneLookup.NORMALIZED_NUMBER, 1088 }); 1089 } 1090 testGroupsProjection()1091 public void testGroupsProjection() { 1092 assertProjection(Groups.CONTENT_URI, new String[]{ 1093 Groups._ID, 1094 Groups.ACCOUNT_NAME, 1095 Groups.ACCOUNT_TYPE, 1096 Groups.DATA_SET, 1097 Groups.ACCOUNT_TYPE_AND_DATA_SET, 1098 Groups.SOURCE_ID, 1099 Groups.DIRTY, 1100 Groups.VERSION, 1101 Groups.RES_PACKAGE, 1102 Groups.TITLE, 1103 Groups.TITLE_RES, 1104 Groups.GROUP_VISIBLE, 1105 Groups.SYSTEM_ID, 1106 Groups.DELETED, 1107 Groups.NOTES, 1108 Groups.SHOULD_SYNC, 1109 Groups.FAVORITES, 1110 Groups.AUTO_ADD, 1111 Groups.GROUP_IS_READ_ONLY, 1112 Groups.SYNC1, 1113 Groups.SYNC2, 1114 Groups.SYNC3, 1115 Groups.SYNC4, 1116 }); 1117 } 1118 testGroupsSummaryProjection()1119 public void testGroupsSummaryProjection() { 1120 assertProjection(Groups.CONTENT_SUMMARY_URI, new String[]{ 1121 Groups._ID, 1122 Groups.ACCOUNT_NAME, 1123 Groups.ACCOUNT_TYPE, 1124 Groups.DATA_SET, 1125 Groups.ACCOUNT_TYPE_AND_DATA_SET, 1126 Groups.SOURCE_ID, 1127 Groups.DIRTY, 1128 Groups.VERSION, 1129 Groups.RES_PACKAGE, 1130 Groups.TITLE, 1131 Groups.TITLE_RES, 1132 Groups.GROUP_VISIBLE, 1133 Groups.SYSTEM_ID, 1134 Groups.DELETED, 1135 Groups.NOTES, 1136 Groups.SHOULD_SYNC, 1137 Groups.FAVORITES, 1138 Groups.AUTO_ADD, 1139 Groups.GROUP_IS_READ_ONLY, 1140 Groups.SYNC1, 1141 Groups.SYNC2, 1142 Groups.SYNC3, 1143 Groups.SYNC4, 1144 Groups.SUMMARY_COUNT, 1145 Groups.SUMMARY_WITH_PHONES, 1146 Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 1147 }); 1148 } 1149 testAggregateExceptionProjection()1150 public void testAggregateExceptionProjection() { 1151 assertProjection(AggregationExceptions.CONTENT_URI, new String[]{ 1152 AggregationExceptionColumns._ID, 1153 AggregationExceptions.TYPE, 1154 AggregationExceptions.RAW_CONTACT_ID1, 1155 AggregationExceptions.RAW_CONTACT_ID2, 1156 }); 1157 } 1158 testSettingsProjection()1159 public void testSettingsProjection() { 1160 assertProjection(Settings.CONTENT_URI, new String[]{ 1161 Settings.ACCOUNT_NAME, 1162 Settings.ACCOUNT_TYPE, 1163 Settings.DATA_SET, 1164 Settings.UNGROUPED_VISIBLE, 1165 Settings.SHOULD_SYNC, 1166 Settings.ANY_UNSYNCED, 1167 Settings.UNGROUPED_COUNT, 1168 Settings.UNGROUPED_WITH_PHONES, 1169 }); 1170 } 1171 testStatusUpdatesProjection()1172 public void testStatusUpdatesProjection() { 1173 assertProjection(StatusUpdates.CONTENT_URI, new String[]{ 1174 PresenceColumns.RAW_CONTACT_ID, 1175 StatusUpdates.DATA_ID, 1176 StatusUpdates.IM_ACCOUNT, 1177 StatusUpdates.IM_HANDLE, 1178 StatusUpdates.PROTOCOL, 1179 StatusUpdates.CUSTOM_PROTOCOL, 1180 StatusUpdates.PRESENCE, 1181 StatusUpdates.CHAT_CAPABILITY, 1182 StatusUpdates.STATUS, 1183 StatusUpdates.STATUS_TIMESTAMP, 1184 StatusUpdates.STATUS_RES_PACKAGE, 1185 StatusUpdates.STATUS_ICON, 1186 StatusUpdates.STATUS_LABEL, 1187 }); 1188 } 1189 testDirectoryProjection()1190 public void testDirectoryProjection() { 1191 assertProjection(Directory.CONTENT_URI, new String[]{ 1192 Directory._ID, 1193 Directory.PACKAGE_NAME, 1194 Directory.TYPE_RESOURCE_ID, 1195 Directory.DISPLAY_NAME, 1196 Directory.DIRECTORY_AUTHORITY, 1197 Directory.ACCOUNT_TYPE, 1198 Directory.ACCOUNT_NAME, 1199 Directory.EXPORT_SUPPORT, 1200 Directory.SHORTCUT_SUPPORT, 1201 Directory.PHOTO_SUPPORT, 1202 }); 1203 } 1204 testProviderStatusProjection()1205 public void testProviderStatusProjection() { 1206 assertProjection(ProviderStatus.CONTENT_URI, new String[]{ 1207 ProviderStatus.STATUS, 1208 ProviderStatus.DATABASE_CREATION_TIMESTAMP, 1209 }); 1210 } 1211 testRawContactsInsert()1212 public void testRawContactsInsert() { 1213 ContentValues values = new ContentValues(); 1214 1215 values.put(RawContacts.ACCOUNT_NAME, "a"); 1216 values.put(RawContacts.ACCOUNT_TYPE, "b"); 1217 values.put(RawContacts.DATA_SET, "ds"); 1218 values.put(RawContacts.SOURCE_ID, "c"); 1219 values.put(RawContacts.VERSION, 42); 1220 values.put(RawContacts.DIRTY, 1); 1221 values.put(RawContacts.DELETED, 1); 1222 values.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 1223 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 1224 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 1225 values.put(RawContacts.LAST_TIME_CONTACTED, 86400 + 123); 1226 values.put(RawContacts.TIMES_CONTACTED, 12); 1227 values.put(RawContacts.STARRED, 1); 1228 values.put(RawContacts.SYNC1, "e"); 1229 values.put(RawContacts.SYNC2, "f"); 1230 values.put(RawContacts.SYNC3, "g"); 1231 values.put(RawContacts.SYNC4, "h"); 1232 1233 Uri rowUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1234 long rawContactId = ContentUris.parseId(rowUri); 1235 1236 values.put(RawContacts.LAST_TIME_CONTACTED, 0); 1237 values.put(RawContacts.TIMES_CONTACTED, 0); 1238 1239 assertStoredValues(rowUri, values); 1240 assertNetworkNotified(true); 1241 } 1242 testDataDirectoryWithLookupUri()1243 public void testDataDirectoryWithLookupUri() { 1244 ContentValues values = new ContentValues(); 1245 1246 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 1247 insertPhoneNumber(rawContactId, "555-GOOG-411"); 1248 insertEmail(rawContactId, "google@android.com"); 1249 1250 long contactId = queryContactId(rawContactId); 1251 String lookupKey = queryLookupKey(contactId); 1252 1253 // Complete and valid lookup URI 1254 Uri lookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey); 1255 Uri dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY); 1256 1257 assertDataRows(dataUri, values); 1258 1259 // Complete but stale lookup URI 1260 lookupUri = ContactsContract.Contacts.getLookupUri(contactId + 1, lookupKey); 1261 dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY); 1262 assertDataRows(dataUri, values); 1263 1264 // Incomplete lookup URI (lookup key only, no contact ID) 1265 dataUri = Uri.withAppendedPath(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, 1266 lookupKey), Contacts.Data.CONTENT_DIRECTORY); 1267 assertDataRows(dataUri, values); 1268 } 1269 assertDataRows(Uri dataUri, ContentValues values)1270 private void assertDataRows(Uri dataUri, ContentValues values) { 1271 Cursor cursor = mResolver.query(dataUri, new String[]{ Data.DATA1 }, null, null, Data._ID); 1272 assertEquals(3, cursor.getCount()); 1273 cursor.moveToFirst(); 1274 values.put(Data.DATA1, "John Doe"); 1275 assertCursorValues(cursor, values); 1276 1277 cursor.moveToNext(); 1278 values.put(Data.DATA1, "555-GOOG-411"); 1279 assertCursorValues(cursor, values); 1280 1281 cursor.moveToNext(); 1282 values.put(Data.DATA1, "google@android.com"); 1283 assertCursorValues(cursor, values); 1284 1285 cursor.close(); 1286 } 1287 testContactEntitiesWithIdBasedUri()1288 public void testContactEntitiesWithIdBasedUri() { 1289 ContentValues values = new ContentValues(); 1290 Account account1 = new Account("act1", "actype1"); 1291 Account account2 = new Account("act2", "actype2"); 1292 1293 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, account1); 1294 insertImHandle(rawContactId1, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk"); 1295 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", StatusUpdates.IDLE, "Busy", 90, 1296 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 1297 1298 long rawContactId2 = RawContactUtil.createRawContact(mResolver, account2); 1299 setAggregationException( 1300 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 1301 1302 long contactId = queryContactId(rawContactId1); 1303 1304 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1305 Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY); 1306 1307 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 1308 } 1309 testContactEntitiesWithLookupUri()1310 public void testContactEntitiesWithLookupUri() { 1311 ContentValues values = new ContentValues(); 1312 Account account1 = new Account("act1", "actype1"); 1313 Account account2 = new Account("act2", "actype2"); 1314 1315 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, account1); 1316 insertImHandle(rawContactId1, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk"); 1317 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", StatusUpdates.IDLE, "Busy", 90, 1318 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 1319 1320 long rawContactId2 = RawContactUtil.createRawContact(mResolver, account2); 1321 setAggregationException( 1322 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 1323 1324 long contactId = queryContactId(rawContactId1); 1325 String lookupKey = queryLookupKey(contactId); 1326 1327 // First try with a matching contact ID 1328 Uri contactLookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey); 1329 Uri entityUri = Uri.withAppendedPath(contactLookupUri, Contacts.Entity.CONTENT_DIRECTORY); 1330 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 1331 1332 // Now try with a contact ID mismatch 1333 contactLookupUri = ContactsContract.Contacts.getLookupUri(contactId + 1, lookupKey); 1334 entityUri = Uri.withAppendedPath(contactLookupUri, Contacts.Entity.CONTENT_DIRECTORY); 1335 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 1336 1337 // Now try without an ID altogether 1338 contactLookupUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey); 1339 entityUri = Uri.withAppendedPath(contactLookupUri, Contacts.Entity.CONTENT_DIRECTORY); 1340 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 1341 } 1342 assertEntityRows(Uri entityUri, long contactId, long rawContactId1, long rawContactId2)1343 private void assertEntityRows(Uri entityUri, long contactId, long rawContactId1, 1344 long rawContactId2) { 1345 ContentValues values = new ContentValues(); 1346 1347 Cursor cursor = mResolver.query(entityUri, null, null, null, 1348 Contacts.Entity.RAW_CONTACT_ID + "," + Contacts.Entity.DATA_ID); 1349 assertEquals(3, cursor.getCount()); 1350 1351 // First row - name 1352 cursor.moveToFirst(); 1353 values.put(Contacts.Entity.CONTACT_ID, contactId); 1354 values.put(Contacts.Entity.RAW_CONTACT_ID, rawContactId1); 1355 values.put(Contacts.Entity.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 1356 values.put(Contacts.Entity.DATA1, "John Doe"); 1357 values.put(Contacts.Entity.ACCOUNT_NAME, "act1"); 1358 values.put(Contacts.Entity.ACCOUNT_TYPE, "actype1"); 1359 values.put(Contacts.Entity.DISPLAY_NAME, "John Doe"); 1360 values.put(Contacts.Entity.DISPLAY_NAME_ALTERNATIVE, "Doe, John"); 1361 values.put(Contacts.Entity.NAME_RAW_CONTACT_ID, rawContactId1); 1362 values.put(Contacts.Entity.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 1363 values.put(Contacts.Entity.CONTACT_PRESENCE, StatusUpdates.IDLE); 1364 values.put(Contacts.Entity.CONTACT_STATUS, "Busy"); 1365 values.putNull(Contacts.Entity.PRESENCE); 1366 assertCursorValues(cursor, values); 1367 1368 // Second row - IM 1369 cursor.moveToNext(); 1370 values.put(Contacts.Entity.CONTACT_ID, contactId); 1371 values.put(Contacts.Entity.RAW_CONTACT_ID, rawContactId1); 1372 values.put(Contacts.Entity.MIMETYPE, Im.CONTENT_ITEM_TYPE); 1373 values.put(Contacts.Entity.DATA1, "gtalk"); 1374 values.put(Contacts.Entity.ACCOUNT_NAME, "act1"); 1375 values.put(Contacts.Entity.ACCOUNT_TYPE, "actype1"); 1376 values.put(Contacts.Entity.DISPLAY_NAME, "John Doe"); 1377 values.put(Contacts.Entity.DISPLAY_NAME_ALTERNATIVE, "Doe, John"); 1378 values.put(Contacts.Entity.NAME_RAW_CONTACT_ID, rawContactId1); 1379 values.put(Contacts.Entity.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 1380 values.put(Contacts.Entity.CONTACT_PRESENCE, StatusUpdates.IDLE); 1381 values.put(Contacts.Entity.CONTACT_STATUS, "Busy"); 1382 values.put(Contacts.Entity.PRESENCE, StatusUpdates.IDLE); 1383 assertCursorValues(cursor, values); 1384 1385 // Third row - second raw contact, not data 1386 cursor.moveToNext(); 1387 values.put(Contacts.Entity.CONTACT_ID, contactId); 1388 values.put(Contacts.Entity.RAW_CONTACT_ID, rawContactId2); 1389 values.putNull(Contacts.Entity.MIMETYPE); 1390 values.putNull(Contacts.Entity.DATA_ID); 1391 values.putNull(Contacts.Entity.DATA1); 1392 values.put(Contacts.Entity.ACCOUNT_NAME, "act2"); 1393 values.put(Contacts.Entity.ACCOUNT_TYPE, "actype2"); 1394 values.put(Contacts.Entity.DISPLAY_NAME, "John Doe"); 1395 values.put(Contacts.Entity.DISPLAY_NAME_ALTERNATIVE, "Doe, John"); 1396 values.put(Contacts.Entity.NAME_RAW_CONTACT_ID, rawContactId1); 1397 values.put(Contacts.Entity.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 1398 values.put(Contacts.Entity.CONTACT_PRESENCE, StatusUpdates.IDLE); 1399 values.put(Contacts.Entity.CONTACT_STATUS, "Busy"); 1400 values.putNull(Contacts.Entity.PRESENCE); 1401 assertCursorValues(cursor, values); 1402 1403 cursor.close(); 1404 } 1405 testDataInsert()1406 public void testDataInsert() { 1407 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe"); 1408 1409 ContentValues values = new ContentValues(); 1410 putDataValues(values, rawContactId); 1411 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 1412 long dataId = ContentUris.parseId(dataUri); 1413 1414 long contactId = queryContactId(rawContactId); 1415 values.put(RawContacts.CONTACT_ID, contactId); 1416 assertStoredValues(dataUri, values); 1417 1418 values.remove(Photo.PHOTO);// Remove byte[] value. 1419 assertSelection(Data.CONTENT_URI, values, Data._ID, dataId); 1420 1421 // Access the same data through the directory under RawContacts 1422 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 1423 Uri rawContactDataUri = 1424 Uri.withAppendedPath(rawContactUri, RawContacts.Data.CONTENT_DIRECTORY); 1425 assertSelection(rawContactDataUri, values, Data._ID, dataId); 1426 1427 // Access the same data through the directory under Contacts 1428 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1429 Uri contactDataUri = Uri.withAppendedPath(contactUri, Contacts.Data.CONTENT_DIRECTORY); 1430 assertSelection(contactDataUri, values, Data._ID, dataId); 1431 assertNetworkNotified(true); 1432 } 1433 testDataInsertAndUpdateHashId()1434 public void testDataInsertAndUpdateHashId() { 1435 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe"); 1436 1437 // Insert a data with non-photo mimetype. 1438 ContentValues values = new ContentValues(); 1439 putDataValues(values, rawContactId); 1440 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 1441 1442 final ContactsProvider2 cp = (ContactsProvider2) getProvider(); 1443 final ContactsDatabaseHelper helper = cp.getDatabaseHelper(); 1444 String data1 = values.getAsString(Data.DATA1); 1445 String data2 = values.getAsString(Data.DATA2); 1446 String combineString = data1+data2; 1447 String hashId = helper.generateHashIdForData(combineString.getBytes()); 1448 assertStoredValue(dataUri, Data.HASH_ID, hashId); 1449 1450 // Update the data with primary, and check if hash_id is not changed. 1451 values.remove(Data.DATA1); 1452 values.remove(Data.DATA2); 1453 values.remove(Data.DATA15); 1454 values.put(Data.IS_PRIMARY, "1"); 1455 mResolver.update(dataUri, values, null, null); 1456 assertStoredValue(dataUri, Data.IS_PRIMARY, "1"); 1457 assertStoredValue(dataUri, Data.HASH_ID, hashId); 1458 1459 // Update the data with new data1. 1460 values = new ContentValues(); 1461 putDataValues(values, rawContactId); 1462 String newData1 = "Newone"; 1463 values.put(Data.DATA1, newData1); 1464 mResolver.update(dataUri, values, null, null); 1465 combineString = newData1+data2; 1466 String newHashId = helper.generateHashIdForData(combineString.getBytes()); 1467 assertStoredValue(dataUri, Data.HASH_ID, newHashId); 1468 1469 // Update the data with a new Data2. 1470 values.remove(Data.DATA1); 1471 values.put(Data.DATA2, "Newtwo"); 1472 combineString = "NewoneNewtwo"; 1473 String testHashId = helper.generateHashIdForData(combineString.getBytes()); 1474 mResolver.update(dataUri, values, null, null); 1475 assertStoredValue(dataUri, Data.HASH_ID, testHashId); 1476 1477 // Update the data with a new data1 + data2. 1478 values.put(Data.DATA1, "one"); 1479 combineString = "oneNewtwo"; 1480 testHashId = helper.generateHashIdForData(combineString.getBytes()); 1481 mResolver.update(dataUri, values, null, null); 1482 assertStoredValue(dataUri, Data.HASH_ID, testHashId); 1483 1484 // Update the data with null data1 and null data2. 1485 values.putNull(Data.DATA1); 1486 values.putNull(Data.DATA2); 1487 mResolver.update(dataUri, values, null, null); 1488 assertStoredValue(dataUri, Data.HASH_ID, null); 1489 } 1490 testDataInsertAndUpdateHashId_Photo()1491 public void testDataInsertAndUpdateHashId_Photo() { 1492 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe"); 1493 1494 // Insert a data with photo mimetype. 1495 ContentValues values = new ContentValues(); 1496 values.put(Data.RAW_CONTACT_ID, rawContactId); 1497 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 1498 values.put(Data.DATA1, "testData1"); 1499 values.put(Data.DATA2, "testData2"); 1500 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 1501 1502 // Check for photo data's hashId is correct or not. 1503 final ContactsProvider2 cp = (ContactsProvider2) getProvider(); 1504 final ContactsDatabaseHelper helper = cp.getDatabaseHelper(); 1505 String hashId = helper.getPhotoHashId(); 1506 assertStoredValue(dataUri, Data.HASH_ID, hashId); 1507 1508 // Update the data with new DATA1, and check if hash_id is not changed. 1509 values.put(Data.DATA1, "newData1"); 1510 mResolver.update(dataUri, values, null, null); 1511 assertStoredValue(dataUri, Data.DATA1, "newData1"); 1512 assertStoredValue(dataUri, Data.HASH_ID, hashId); 1513 } 1514 testDataInsertPhoneNumberTooLongIsTrimmed()1515 public void testDataInsertPhoneNumberTooLongIsTrimmed() { 1516 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe"); 1517 1518 ContentValues values = new ContentValues(); 1519 values.put(Data.RAW_CONTACT_ID, rawContactId); 1520 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1521 final StringBuilder sb = new StringBuilder(); 1522 for (int i = 0; i < 300; i++) { 1523 sb.append("12345"); 1524 } 1525 final String phoneNumber1500Chars = sb.toString(); 1526 values.put(Phone.NUMBER, phoneNumber1500Chars); 1527 1528 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 1529 final long dataId = ContentUris.parseId(dataUri); 1530 1531 sb.setLength(0); 1532 for (int i = 0; i < 200; i++) { 1533 sb.append("12345"); 1534 } 1535 final String phoneNumber1000Chars = sb.toString(); 1536 final ContentValues expected = new ContentValues(); 1537 expected.put(Phone.NUMBER, phoneNumber1000Chars); 1538 assertSelection(dataUri, expected, Data._ID, dataId); 1539 } 1540 testRawContactDataQuery()1541 public void testRawContactDataQuery() { 1542 Account account1 = new Account("a", "b"); 1543 Account account2 = new Account("c", "d"); 1544 long rawContactId1 = RawContactUtil.createRawContact(mResolver, account1); 1545 Uri dataUri1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "John", "Doe"); 1546 long rawContactId2 = RawContactUtil.createRawContact(mResolver, account2); 1547 Uri dataUri2 = DataUtil.insertStructuredName(mResolver, rawContactId2, "Jane", "Doe"); 1548 1549 Uri uri1 = TestUtil.maybeAddAccountQueryParameters(dataUri1, account1); 1550 Uri uri2 = TestUtil.maybeAddAccountQueryParameters(dataUri2, account2); 1551 assertStoredValue(uri1, Data._ID, ContentUris.parseId(dataUri1)) ; 1552 assertStoredValue(uri2, Data._ID, ContentUris.parseId(dataUri2)) ; 1553 } 1554 testPhonesQuery()1555 public void testPhonesQuery() { 1556 1557 ContentValues values = new ContentValues(); 1558 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 1559 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 1560 values.put(RawContacts.LAST_TIME_CONTACTED, 86400 + 5); 1561 values.put(RawContacts.TIMES_CONTACTED, 54321); 1562 values.put(RawContacts.STARRED, 1); 1563 1564 Uri rawContactUri = insertRawContact(values); 1565 long rawContactId = ContentUris.parseId(rawContactUri); 1566 1567 DataUtil.insertStructuredName(mResolver, rawContactId, "Meghan", "Knox"); 1568 Uri uri = insertPhoneNumber(rawContactId, "18004664411"); 1569 long phoneId = ContentUris.parseId(uri); 1570 1571 1572 long contactId = queryContactId(rawContactId); 1573 values.clear(); 1574 values.put(Data._ID, phoneId); 1575 values.put(Data.RAW_CONTACT_ID, rawContactId); 1576 values.put(RawContacts.CONTACT_ID, contactId); 1577 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1578 values.put(Phone.NUMBER, "18004664411"); 1579 values.put(Phone.TYPE, Phone.TYPE_HOME); 1580 values.putNull(Phone.LABEL); 1581 values.put(Contacts.DISPLAY_NAME, "Meghan Knox"); 1582 values.put(Contacts.CUSTOM_RINGTONE, "d"); 1583 values.put(Contacts.SEND_TO_VOICEMAIL, 1); 1584 values.put(Contacts.LAST_TIME_CONTACTED, 0); 1585 values.put(Contacts.TIMES_CONTACTED, 0); 1586 values.put(Contacts.STARRED, 1); 1587 1588 assertStoredValues(ContentUris.withAppendedId(Phone.CONTENT_URI, phoneId), values); 1589 } 1590 testPhonesWithMergedContacts()1591 public void testPhonesWithMergedContacts() { 1592 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1593 insertPhoneNumber(rawContactId1, "123456789", true); 1594 1595 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1596 insertPhoneNumber(rawContactId2, "123456789", true); 1597 1598 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 1599 rawContactId1, rawContactId2); 1600 assertNotAggregated(rawContactId1, rawContactId2); 1601 1602 ContentValues values1 = new ContentValues(); 1603 values1.put(Contacts.DISPLAY_NAME, "123456789"); 1604 values1.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1605 values1.put(Phone.NUMBER, "123456789"); 1606 1607 // There are two phone numbers, so we should get two rows. 1608 assertStoredValues(Phone.CONTENT_URI, new ContentValues[] {values1, values1}); 1609 1610 // Now set the dedupe flag. But still we should get two rows, because they're two 1611 // different contacts. We only dedupe within each contact. 1612 final Uri dedupeUri = Phone.CONTENT_URI.buildUpon() 1613 .appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true") 1614 .build(); 1615 assertStoredValues(dedupeUri, new ContentValues[] {values1, values1}); 1616 1617 // Now join them into a single contact. 1618 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1619 rawContactId1, rawContactId2); 1620 1621 assertAggregated(rawContactId1, rawContactId2, "123456789"); 1622 1623 // Contact merge won't affect the default result of Phone Uri, where we don't dedupe. 1624 assertStoredValues(Phone.CONTENT_URI, new ContentValues[] {values1, values1}); 1625 1626 // Now we dedupe them. 1627 assertStoredValues(dedupeUri, values1); 1628 } 1629 testPhonesNormalizedNumber()1630 public void testPhonesNormalizedNumber() { 1631 final long rawContactId = RawContactUtil.createRawContact(mResolver); 1632 1633 // Write both a number and a normalized number. Those should be written as-is 1634 final ContentValues values = new ContentValues(); 1635 values.put(Data.RAW_CONTACT_ID, rawContactId); 1636 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1637 values.put(Phone.NUMBER, "1234"); 1638 values.put(Phone.NORMALIZED_NUMBER, "5678"); 1639 values.put(Phone.TYPE, Phone.TYPE_HOME); 1640 1641 final Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 1642 1643 // Check the lookup table. 1644 assertEquals(1, 1645 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "1234"), null, null)); 1646 assertEquals(1, 1647 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "5678"), null, null)); 1648 1649 // Check the data table. 1650 assertStoredValues(dataUri, 1651 cv(Phone.NUMBER, "1234", Phone.NORMALIZED_NUMBER, "5678") 1652 ); 1653 1654 // Replace both in an UPDATE 1655 values.clear(); 1656 values.put(Phone.NUMBER, "4321"); 1657 values.put(Phone.NORMALIZED_NUMBER, "8765"); 1658 mResolver.update(dataUri, values, null, null); 1659 assertEquals(0, 1660 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "1234"), null, null)); 1661 assertEquals(1, 1662 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "4321"), null, null)); 1663 assertEquals(0, 1664 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "5678"), null, null)); 1665 assertEquals(1, 1666 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "8765"), null, null)); 1667 1668 assertStoredValues(dataUri, 1669 cv(Phone.NUMBER, "4321", Phone.NORMALIZED_NUMBER, "8765") 1670 ); 1671 1672 // Replace only NUMBER ==> NORMALIZED_NUMBER will be inferred (we test that by making 1673 // sure the old manual value can not be found anymore) 1674 values.clear(); 1675 values.put(Phone.NUMBER, "+1-800-466-5432"); 1676 mResolver.update(dataUri, values, null, null); 1677 assertEquals( 1678 1, 1679 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "+1-800-466-5432"), null, 1680 null)); 1681 assertEquals(0, 1682 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "8765"), null, null)); 1683 1684 assertStoredValues(dataUri, 1685 cv(Phone.NUMBER, "+1-800-466-5432", Phone.NORMALIZED_NUMBER, "+18004665432") 1686 ); 1687 1688 // Replace only NORMALIZED_NUMBER ==> call is ignored, things will be unchanged 1689 values.clear(); 1690 values.put(Phone.NORMALIZED_NUMBER, "8765"); 1691 mResolver.update(dataUri, values, null, null); 1692 assertEquals( 1693 1, 1694 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "+1-800-466-5432"), null, 1695 null)); 1696 assertEquals(0, 1697 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "8765"), null, null)); 1698 1699 assertStoredValues(dataUri, 1700 cv(Phone.NUMBER, "+1-800-466-5432", Phone.NORMALIZED_NUMBER, "+18004665432") 1701 ); 1702 1703 // Replace NUMBER with an "invalid" number which can't be normalized. It should clear 1704 // NORMALIZED_NUMBER. 1705 1706 // 1. Set 999 to NORMALIZED_NUMBER explicitly. 1707 values.clear(); 1708 values.put(Phone.NUMBER, "888"); 1709 values.put(Phone.NORMALIZED_NUMBER, "999"); 1710 mResolver.update(dataUri, values, null, null); 1711 1712 assertEquals(1, 1713 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "999"), null, null)); 1714 1715 assertStoredValues(dataUri, 1716 cv(Phone.NUMBER, "888", Phone.NORMALIZED_NUMBER, "999") 1717 ); 1718 1719 // 2. Set an invalid number to NUMBER. 1720 values.clear(); 1721 values.put(Phone.NUMBER, "1"); 1722 mResolver.update(dataUri, values, null, null); 1723 1724 assertEquals(0, 1725 getCount(Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "999"), null, null)); 1726 1727 assertStoredValues(dataUri, 1728 cv(Phone.NUMBER, "1", Phone.NORMALIZED_NUMBER, null) 1729 ); 1730 } 1731 testPhonesFilterQuery()1732 public void testPhonesFilterQuery() { 1733 testPhonesFilterQueryInter(Phone.CONTENT_FILTER_URI); 1734 } 1735 1736 /** 1737 * A convenient method for {@link #testPhonesFilterQuery()} and 1738 * {@link #testCallablesFilterQuery()}. 1739 * 1740 * This confirms if both URIs return identical results for phone-only contacts and 1741 * appropriately different results for contacts with sip addresses. 1742 * 1743 * @param baseFilterUri Either {@link Phone#CONTENT_FILTER_URI} or 1744 * {@link Callable#CONTENT_FILTER_URI}. 1745 */ testPhonesFilterQueryInter(Uri baseFilterUri)1746 private void testPhonesFilterQueryInter(Uri baseFilterUri) { 1747 assertTrue("Unsupported Uri (" + baseFilterUri + ")", 1748 Phone.CONTENT_FILTER_URI.equals(baseFilterUri) 1749 || Callable.CONTENT_FILTER_URI.equals(baseFilterUri)); 1750 1751 final long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "Hot", 1752 "Tamale", TestUtil.ACCOUNT_1); 1753 insertPhoneNumber(rawContactId1, "1-800-466-4411"); 1754 1755 final long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "Chilled", 1756 "Guacamole", TestUtil.ACCOUNT_2); 1757 insertPhoneNumber(rawContactId2, "1-800-466-5432"); 1758 insertPhoneNumber(rawContactId2, "0@example.com", false, Phone.TYPE_PAGER); 1759 insertPhoneNumber(rawContactId2, "1@example.com", false, Phone.TYPE_PAGER); 1760 1761 final Uri filterUri1 = Uri.withAppendedPath(baseFilterUri, "tamale"); 1762 ContentValues values = new ContentValues(); 1763 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 1764 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1765 values.put(Phone.NUMBER, "1-800-466-4411"); 1766 values.put(Phone.TYPE, Phone.TYPE_HOME); 1767 values.putNull(Phone.LABEL); 1768 assertStoredValuesWithProjection(filterUri1, values); 1769 1770 final Uri filterUri2 = Uri.withAppendedPath(baseFilterUri, "1-800-GOOG-411"); 1771 assertStoredValues(filterUri2, values); 1772 1773 final Uri filterUri3 = Uri.withAppendedPath(baseFilterUri, "18004664"); 1774 assertStoredValues(filterUri3, values); 1775 1776 final Uri filterUri4 = Uri.withAppendedPath(baseFilterUri, "encilada"); 1777 assertEquals(0, getCount(filterUri4, null, null)); 1778 1779 final Uri filterUri5 = Uri.withAppendedPath(baseFilterUri, "*"); 1780 assertEquals(0, getCount(filterUri5, null, null)); 1781 1782 ContentValues values1 = new ContentValues(); 1783 values1.put(Contacts.DISPLAY_NAME, "Chilled Guacamole"); 1784 values1.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1785 values1.put(Phone.NUMBER, "1-800-466-5432"); 1786 values1.put(Phone.TYPE, Phone.TYPE_HOME); 1787 values1.putNull(Phone.LABEL); 1788 1789 ContentValues values2 = new ContentValues(); 1790 values2.put(Contacts.DISPLAY_NAME, "Chilled Guacamole"); 1791 values2.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1792 values2.put(Phone.NUMBER, "0@example.com"); 1793 values2.put(Phone.TYPE, Phone.TYPE_PAGER); 1794 values2.putNull(Phone.LABEL); 1795 1796 ContentValues values3 = new ContentValues(); 1797 values3.put(Contacts.DISPLAY_NAME, "Chilled Guacamole"); 1798 values3.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 1799 values3.put(Phone.NUMBER, "1@example.com"); 1800 values3.put(Phone.TYPE, Phone.TYPE_PAGER); 1801 values3.putNull(Phone.LABEL); 1802 1803 final Uri filterUri6 = Uri.withAppendedPath(baseFilterUri, "Chilled"); 1804 assertStoredValues(filterUri6, new ContentValues[]{values1, values2, values3}); 1805 1806 // Insert a SIP address. From here, Phone URI and Callable URI may return different results 1807 // than each other. 1808 insertSipAddress(rawContactId1, "sip_hot_tamale@example.com"); 1809 insertSipAddress(rawContactId1, "sip:sip_hot@example.com"); 1810 1811 final Uri filterUri7 = Uri.withAppendedPath(baseFilterUri, "sip_hot"); 1812 final Uri filterUri8 = Uri.withAppendedPath(baseFilterUri, "sip_hot_tamale"); 1813 if (Callable.CONTENT_FILTER_URI.equals(baseFilterUri)) { 1814 ContentValues values4 = new ContentValues(); 1815 values4.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 1816 values4.put(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE); 1817 values4.put(SipAddress.SIP_ADDRESS, "sip_hot_tamale@example.com"); 1818 1819 ContentValues values5 = new ContentValues(); 1820 values5.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 1821 values5.put(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE); 1822 values5.put(SipAddress.SIP_ADDRESS, "sip:sip_hot@example.com"); 1823 assertStoredValues(filterUri1, new ContentValues[] {values, values4, values5}); 1824 1825 assertStoredValues(filterUri7, new ContentValues[] {values4, values5}); 1826 assertStoredValues(filterUri8, values4); 1827 } else { 1828 // Sip address should not affect Phone URI. 1829 assertStoredValuesWithProjection(filterUri1, values); 1830 assertEquals(0, getCount(filterUri7, null, null)); 1831 } 1832 1833 // Sanity test. Run tests for "Chilled Guacamole" again and see nothing changes 1834 // after the Sip address being inserted. 1835 assertStoredValues(filterUri2, values); 1836 assertEquals(0, getCount(filterUri4, null, null)); 1837 assertEquals(0, getCount(filterUri5, null, null)); 1838 assertStoredValues(filterUri6, new ContentValues[] {values1, values2, values3} ); 1839 } 1840 testPhonesFilterSearchParams()1841 public void testPhonesFilterSearchParams() { 1842 final long rid1 = RawContactUtil.createRawContactWithName(mResolver, "Dad", null); 1843 insertPhoneNumber(rid1, "123-456-7890"); 1844 1845 final long rid2 = RawContactUtil.createRawContactWithName(mResolver, "Mam", null); 1846 insertPhoneNumber(rid2, "323-123-4567"); 1847 1848 // By default, "dad" will match both the display name and the phone number. 1849 // Because "dad" is "323" after the dialpad conversion, it'll match "Mam" too. 1850 assertStoredValues( 1851 Phone.CONTENT_FILTER_URI.buildUpon().appendPath("dad").build(), 1852 cv(Phone.DISPLAY_NAME, "Dad", Phone.NUMBER, "123-456-7890"), 1853 cv(Phone.DISPLAY_NAME, "Mam", Phone.NUMBER, "323-123-4567") 1854 ); 1855 assertStoredValues( 1856 Phone.CONTENT_FILTER_URI.buildUpon().appendPath("dad") 1857 .appendQueryParameter(Phone.SEARCH_PHONE_NUMBER_KEY, "0") 1858 .build(), 1859 cv(Phone.DISPLAY_NAME, "Dad", Phone.NUMBER, "123-456-7890") 1860 ); 1861 1862 assertStoredValues( 1863 Phone.CONTENT_FILTER_URI.buildUpon().appendPath("dad") 1864 .appendQueryParameter(Phone.SEARCH_DISPLAY_NAME_KEY, "0") 1865 .build(), 1866 cv(Phone.DISPLAY_NAME, "Mam", Phone.NUMBER, "323-123-4567") 1867 ); 1868 assertStoredValues( 1869 Phone.CONTENT_FILTER_URI.buildUpon().appendPath("dad") 1870 .appendQueryParameter(Phone.SEARCH_DISPLAY_NAME_KEY, "0") 1871 .appendQueryParameter(Phone.SEARCH_PHONE_NUMBER_KEY, "0") 1872 .build() 1873 ); 1874 } 1875 testPhoneLookup()1876 public void testPhoneLookup() { 1877 ContentValues values = new ContentValues(); 1878 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 1879 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 1880 1881 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1882 long rawContactId = ContentUris.parseId(rawContactUri); 1883 1884 DataUtil.insertStructuredName(mResolver, rawContactId, "Hot", "Tamale"); 1885 long dataId = 1886 Long.parseLong(insertPhoneNumber(rawContactId, "18004664411").getLastPathSegment()); 1887 1888 // We'll create two lookup records, 18004664411 and +18004664411, and the below lookup 1889 // will match both. 1890 1891 Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411"); 1892 1893 values.clear(); 1894 values.put(PhoneLookup._ID, queryContactId(rawContactId)); 1895 values.put(PhoneLookup.CONTACT_ID, queryContactId(rawContactId)); 1896 values.put(PhoneLookup.DATA_ID, dataId); 1897 values.put(PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 1898 values.put(PhoneLookup.NUMBER, "18004664411"); 1899 values.put(PhoneLookup.TYPE, Phone.TYPE_HOME); 1900 values.putNull(PhoneLookup.LABEL); 1901 values.put(PhoneLookup.CUSTOM_RINGTONE, "d"); 1902 values.put(PhoneLookup.SEND_TO_VOICEMAIL, 1); 1903 assertStoredValues(lookupUri1, null, null, new ContentValues[] {values, values}); 1904 1905 // In the context that 8004664411 is a valid number, "4664411" as a 1906 // call id should not match to either "8004664411" or "+18004664411". 1907 Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "4664411"); 1908 assertEquals(0, getCount(lookupUri2, null, null)); 1909 1910 // A wrong area code 799 vs 800 should not be matched 1911 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "7994664411"); 1912 assertEquals(0, getCount(lookupUri2, null, null)); 1913 } 1914 testSipPhoneLookup()1915 public void testSipPhoneLookup() { 1916 ContentValues values = new ContentValues(); 1917 1918 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1919 long rawContactId = ContentUris.parseId(rawContactUri); 1920 1921 DataUtil.insertStructuredName(mResolver, rawContactId, "Hot", "Tamale"); 1922 long dataId = 1923 Long.parseLong(insertSipAddress(rawContactId, "abc@sip").getLastPathSegment()); 1924 1925 Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "abc@sip") 1926 .buildUpon() 1927 .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, "1") 1928 .build(); 1929 1930 values.clear(); 1931 values.put(PhoneLookup._ID, dataId); 1932 values.put(PhoneLookup.CONTACT_ID, queryContactId(rawContactId)); 1933 values.put(PhoneLookup.DATA_ID, dataId); 1934 values.put(PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 1935 values.put(PhoneLookup.NUMBER, "abc@sip"); 1936 values.putNull(PhoneLookup.LABEL); 1937 assertStoredValues(lookupUri1, null, null, new ContentValues[] {values}); 1938 1939 // A wrong sip address should not be matched 1940 Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "wrong@sip"); 1941 assertEquals(0, getCount(lookupUri2, null, null)); 1942 } 1943 testPhoneLookupStarUseCases()1944 public void testPhoneLookupStarUseCases() { 1945 // Create two raw contacts with numbers "*123" and "12 3". This is a real life example 1946 // from b/13195334. 1947 final ContentValues values = new ContentValues(); 1948 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1949 long rawContactId = ContentUris.parseId(rawContactUri); 1950 DataUtil.insertStructuredName(mResolver, rawContactId, "Emergency", /* familyName =*/ null); 1951 insertPhoneNumber(rawContactId, "*123"); 1952 1953 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1954 rawContactId = ContentUris.parseId(rawContactUri); 1955 DataUtil.insertStructuredName(mResolver, rawContactId, "Voicemail", /* familyName =*/ null); 1956 insertPhoneNumber(rawContactId, "12 3"); 1957 1958 // Verify: "123" returns the "Voicemail" raw contact id. It should not match 1959 // a phone number that starts with a "*". 1960 Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "123"); 1961 values.clear(); 1962 values.put(PhoneLookup.DISPLAY_NAME, "Voicemail"); 1963 assertStoredValues(lookupUri, null, null, new ContentValues[] {values}); 1964 1965 lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "(1) 23"); 1966 values.clear(); 1967 values.put(PhoneLookup.DISPLAY_NAME, "Voicemail"); 1968 assertStoredValues(lookupUri, null, null, new ContentValues[] {values}); 1969 1970 // Verify: "*123" returns the "Emergency" raw contact id. 1971 lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "*1-23"); 1972 values.clear(); 1973 values.put(PhoneLookup.DISPLAY_NAME, "Emergency"); 1974 assertStoredValues(lookupUri, null, null, new ContentValues[] {values}); 1975 } 1976 testPhoneLookupReturnsNothingRatherThanStar()1977 public void testPhoneLookupReturnsNothingRatherThanStar() { 1978 // Create Emergency raw contact with "*123456789" number. 1979 final ContentValues values = new ContentValues(); 1980 final Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1981 final long rawContactId1 = ContentUris.parseId(rawContactUri); 1982 DataUtil.insertStructuredName(mResolver, rawContactId1, "Emergency", 1983 /* familyName =*/ null); 1984 insertPhoneNumber(rawContactId1, "*123456789"); 1985 1986 // Lookup should return no results. It does not ignore stars even when no other matches. 1987 final Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "123456789"); 1988 assertEquals(0, getCount(lookupUri, null, null)); 1989 } 1990 testPhoneLookupReturnsNothingRatherThanMissStar()1991 public void testPhoneLookupReturnsNothingRatherThanMissStar() { 1992 // Create Voice Mail raw contact with "123456789" number. 1993 final ContentValues values = new ContentValues(); 1994 final Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1995 final long rawContactId1 = ContentUris.parseId(rawContactUri); 1996 DataUtil.insertStructuredName(mResolver, rawContactId1, "Voice mail", 1997 /* familyName =*/ null); 1998 insertPhoneNumber(rawContactId1, "123456789"); 1999 2000 // Lookup should return no results. It does not ignore stars even when no other matches. 2001 final Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "*123456789"); 2002 assertEquals(0, getCount(lookupUri, null, null)); 2003 } 2004 testPhoneLookupStarNoFallbackMatch()2005 public void testPhoneLookupStarNoFallbackMatch() { 2006 final ContentValues values = new ContentValues(); 2007 final Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2008 final long rawContactId1 = ContentUris.parseId(rawContactUri); 2009 DataUtil.insertStructuredName(mResolver, rawContactId1, "Voice mail", 2010 /* familyName =*/ null); 2011 insertPhoneNumber(rawContactId1, "*011123456789"); 2012 2013 // The numbers "+123456789" and "*011123456789" are a "fallback" match. The + is equivalent 2014 // to "011". This lookup should return no results. Lookup does not ignore 2015 // stars, even when doing a fallback lookup. 2016 final Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+123456789"); 2017 assertEquals(0, getCount(lookupUri, null, null)); 2018 } 2019 testPhoneLookupStarNotBreakFallbackMatching()2020 public void testPhoneLookupStarNotBreakFallbackMatching() { 2021 // Create a raw contact with a phone number starting with "011" 2022 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues()); 2023 long rawContactId = ContentUris.parseId(rawContactUri); 2024 DataUtil.insertStructuredName(mResolver, rawContactId, "No star", 2025 /* familyName =*/ null); 2026 insertPhoneNumber(rawContactId, "011123456789"); 2027 2028 // Create a raw contact with a phone number starting with "*011" 2029 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues()); 2030 rawContactId = ContentUris.parseId(rawContactUri); 2031 DataUtil.insertStructuredName(mResolver, rawContactId, "Has star", 2032 /* familyName =*/ null); 2033 insertPhoneNumber(rawContactId, "*011123456789"); 2034 2035 // A phone number starting with "+" can (fallback) match the same phone number starting 2036 // with "001". Verify that this fallback matching still occurs in the presence of 2037 // numbers starting with "*"s. 2038 final Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, 2039 "+123456789"); 2040 final ContentValues values = new ContentValues(); 2041 values.put(PhoneLookup.DISPLAY_NAME, "No star"); 2042 assertStoredValues(lookupUri1, null, null, new ContentValues[]{values}); 2043 } 2044 testPhoneLookupExplicitProjection()2045 public void testPhoneLookupExplicitProjection() { 2046 final ContentValues values = new ContentValues(); 2047 final Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2048 final long rawContactId1 = ContentUris.parseId(rawContactUri); 2049 DataUtil.insertStructuredName(mResolver, rawContactId1, "Voice mail", 2050 /* familyName =*/ null); 2051 insertPhoneNumber(rawContactId1, "+1234567"); 2052 2053 // Performing a query with a non-null projection with or without PhoneLookup.Number inside 2054 // it should not cause a crash. 2055 Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "1234567"); 2056 String[] projection = new String[] {PhoneLookup.DISPLAY_NAME}; 2057 mResolver.query(lookupUri, projection, null, null, null); 2058 projection = new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup.NUMBER}; 2059 mResolver.query(lookupUri, projection, null, null, null); 2060 2061 // Shouldn't crash for a fallback query either 2062 lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "*0111234567"); 2063 projection = new String[] {PhoneLookup.DISPLAY_NAME}; 2064 mResolver.query(lookupUri, projection, null, null, null); 2065 projection = new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup.NUMBER}; 2066 mResolver.query(lookupUri, projection, null, null, null); 2067 } 2068 testPhoneLookupUseCases()2069 public void testPhoneLookupUseCases() { 2070 ContentValues values = new ContentValues(); 2071 Uri rawContactUri; 2072 long rawContactId; 2073 Uri lookupUri2; 2074 2075 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 2076 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 2077 2078 // International format in contacts 2079 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2080 rawContactId = ContentUris.parseId(rawContactUri); 2081 2082 DataUtil.insertStructuredName(mResolver, rawContactId, "Hot", "Tamale"); 2083 insertPhoneNumber(rawContactId, "+1-650-861-0000"); 2084 2085 values.clear(); 2086 2087 // match with international format 2088 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0000"); 2089 assertEquals(1, getCount(lookupUri2, null, null)); 2090 2091 // match with national format 2092 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0000"); 2093 assertEquals(1, getCount(lookupUri2, null, null)); 2094 2095 // does not match with wrong area code 2096 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "649 861 0000"); 2097 assertEquals(0, getCount(lookupUri2, null, null)); 2098 2099 // does not match with missing digits in mistyped area code 2100 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "5 861 0000"); 2101 assertEquals(0, getCount(lookupUri2, null, null)); 2102 2103 // does not match with missing digit in mistyped area code 2104 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "65 861 0000"); 2105 assertEquals(0, getCount(lookupUri2, null, null)); 2106 2107 // National format in contacts 2108 values.clear(); 2109 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 2110 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 2111 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2112 rawContactId = ContentUris.parseId(rawContactUri); 2113 2114 DataUtil.insertStructuredName(mResolver, rawContactId, "Hot1", "Tamale"); 2115 insertPhoneNumber(rawContactId, "650-861-0001"); 2116 2117 values.clear(); 2118 2119 // match with international format 2120 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0001"); 2121 assertEquals(2, getCount(lookupUri2, null, null)); 2122 2123 // match with national format 2124 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0001"); 2125 assertEquals(2, getCount(lookupUri2, null, null)); 2126 2127 // Local format in contacts 2128 values.clear(); 2129 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 2130 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 2131 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2132 rawContactId = ContentUris.parseId(rawContactUri); 2133 2134 DataUtil.insertStructuredName(mResolver, rawContactId, "Hot2", "Tamale"); 2135 insertPhoneNumber(rawContactId, "861-0002"); 2136 2137 values.clear(); 2138 2139 // No match with international format 2140 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0002"); 2141 assertEquals(0, getCount(lookupUri2, null, null)); 2142 2143 // No match with national format 2144 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0002"); 2145 assertEquals(0, getCount(lookupUri2, null, null)); 2146 } 2147 testIntlPhoneLookupUseCases()2148 public void testIntlPhoneLookupUseCases() { 2149 // Checks the logic that relies on phone_number_compare_loose(Gingerbread) as a fallback 2150 //for phone number lookups. 2151 String fullNumber = "01197297427289"; 2152 2153 ContentValues values = new ContentValues(); 2154 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 2155 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 2156 long rawContactId = ContentUris.parseId(mResolver.insert(RawContacts.CONTENT_URI, values)); 2157 DataUtil.insertStructuredName(mResolver, rawContactId, "Senor", "Chang"); 2158 insertPhoneNumber(rawContactId, fullNumber); 2159 2160 // Full number should definitely match. 2161 assertEquals(2, getCount(Uri.withAppendedPath( 2162 PhoneLookup.CONTENT_FILTER_URI, fullNumber), null, null)); 2163 2164 // Shorter (local) number with 0 prefix should not match. 2165 assertEquals(0, getCount(Uri.withAppendedPath( 2166 PhoneLookup.CONTENT_FILTER_URI, "097427289"), null, null)); 2167 2168 // Number with international (+972) prefix should also match. 2169 assertEquals(1, getCount(Uri.withAppendedPath( 2170 PhoneLookup.CONTENT_FILTER_URI, "+97297427289"), null, null)); 2171 2172 // Same shorter number with dashes should not match. 2173 assertEquals(0, getCount(Uri.withAppendedPath( 2174 PhoneLookup.CONTENT_FILTER_URI, "09-742-7289"), null, null)); 2175 2176 // Same shorter number with spaces should not match. 2177 assertEquals(0, getCount(Uri.withAppendedPath( 2178 PhoneLookup.CONTENT_FILTER_URI, "09 742 7289"), null, null)); 2179 2180 // Some other number should not match. 2181 assertEquals(0, getCount(Uri.withAppendedPath( 2182 PhoneLookup.CONTENT_FILTER_URI, "049102395"), null, null)); 2183 } 2184 testPhoneLookupB5252190()2185 public void testPhoneLookupB5252190() { 2186 // Test cases from b/5252190 2187 String storedNumber = "796010101"; 2188 2189 ContentValues values = new ContentValues(); 2190 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 2191 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 2192 long rawContactId = ContentUris.parseId(mResolver.insert(RawContacts.CONTENT_URI, values)); 2193 DataUtil.insertStructuredName(mResolver, rawContactId, "Senor", "Chang"); 2194 insertPhoneNumber(rawContactId, storedNumber); 2195 2196 assertEquals(1, getCount(Uri.withAppendedPath( 2197 PhoneLookup.CONTENT_FILTER_URI, "0796010101"), null, null)); 2198 2199 assertEquals(0, getCount(Uri.withAppendedPath( 2200 PhoneLookup.CONTENT_FILTER_URI, "+48796010101"), null, null)); 2201 2202 assertEquals(0, getCount(Uri.withAppendedPath( 2203 PhoneLookup.CONTENT_FILTER_URI, "48796010101"), null, null)); 2204 2205 assertEquals(0, getCount(Uri.withAppendedPath( 2206 PhoneLookup.CONTENT_FILTER_URI, "4-879-601-0101"), null, null)); 2207 2208 assertEquals(0, getCount(Uri.withAppendedPath( 2209 PhoneLookup.CONTENT_FILTER_URI, "4 879 601 0101"), null, null)); 2210 } 2211 testPhoneLookupUseStrictPhoneNumberCompare()2212 public void testPhoneLookupUseStrictPhoneNumberCompare() { 2213 // Test lookup cases when mUseStrictPhoneNumberComparison is true 2214 final ContactsProvider2 cp = (ContactsProvider2) getProvider(); 2215 final ContactsDatabaseHelper dbHelper = cp.getThreadActiveDatabaseHelperForTest(); 2216 // Get and save the original value of mUseStrictPhoneNumberComparison so that we 2217 // can restore it when we are done with the test 2218 final boolean oldUseStrict = dbHelper.getUseStrictPhoneNumberComparisonForTest(); 2219 dbHelper.setUseStrictPhoneNumberComparisonForTest(true); 2220 2221 2222 try { 2223 String fullNumber = "01197297427289"; 2224 ContentValues values = new ContentValues(); 2225 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 2226 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 2227 long rawContactId = ContentUris.parseId( 2228 mResolver.insert(RawContacts.CONTENT_URI, values)); 2229 DataUtil.insertStructuredName(mResolver, rawContactId, "Senor", "Chang"); 2230 insertPhoneNumber(rawContactId, fullNumber); 2231 insertPhoneNumber(rawContactId, "5103337596"); 2232 insertPhoneNumber(rawContactId, "+19012345678"); 2233 // One match for full number 2234 assertEquals(1, getCount(Uri.withAppendedPath( 2235 PhoneLookup.CONTENT_FILTER_URI, fullNumber), null, null)); 2236 2237 // No matches for extra digit at the front 2238 assertEquals(0, getCount(Uri.withAppendedPath( 2239 PhoneLookup.CONTENT_FILTER_URI, "55103337596"), null, null)); 2240 // No matches for mispelled area code 2241 assertEquals(0, getCount(Uri.withAppendedPath( 2242 PhoneLookup.CONTENT_FILTER_URI, "5123337596"), null, null)); 2243 2244 // One match for matching number with dashes 2245 assertEquals(1, getCount(Uri.withAppendedPath( 2246 PhoneLookup.CONTENT_FILTER_URI, "510-333-7596"), null, null)); 2247 2248 // One match for matching number with international code 2249 assertEquals(1, getCount(Uri.withAppendedPath( 2250 PhoneLookup.CONTENT_FILTER_URI, "+1-510-333-7596"), null, null)); 2251 values.clear(); 2252 2253 // No matches for extra 0 in front 2254 assertEquals(0, getCount(Uri.withAppendedPath( 2255 PhoneLookup.CONTENT_FILTER_URI, "0-510-333-7596"), null, null)); 2256 values.clear(); 2257 2258 // No matches for different country code 2259 assertEquals(0, getCount(Uri.withAppendedPath( 2260 PhoneLookup.CONTENT_FILTER_URI, "+819012345678"), null, null)); 2261 values.clear(); 2262 } finally { 2263 // restore the original value of mUseStrictPhoneNumberComparison 2264 // upon test completion or failure 2265 dbHelper.setUseStrictPhoneNumberComparisonForTest(oldUseStrict); 2266 } 2267 } 2268 2269 /** 2270 * Test for enterprise caller-id, but with no corp profile. 2271 */ testPhoneLookupEnterprise_noCorpProfile()2272 public void testPhoneLookupEnterprise_noCorpProfile() throws Exception { 2273 2274 Uri uri1 = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, "408-111-1111"); 2275 2276 // No contacts profile, no data. 2277 assertEquals(0, getCount(uri1)); 2278 2279 // Insert a contact into the primary CP2. 2280 long rawContactId = ContentUris.parseId( 2281 mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); 2282 DataUtil.insertStructuredName(mResolver, rawContactId, "Contact1", "Doe"); 2283 insertPhoneNumber(rawContactId, "408-111-1111"); 2284 2285 // Do the query again and check the result. 2286 Cursor c = mResolver.query(uri1, null, null, null, null); 2287 try { 2288 assertEquals(1, c.getCount()); 2289 c.moveToPosition(0); 2290 long contactId = c.getLong(c.getColumnIndex(PhoneLookup._ID)); 2291 assertFalse(Contacts.isEnterpriseContactId(contactId)); // Make sure it's not rewritten. 2292 } finally { 2293 c.close(); 2294 } 2295 } 2296 2297 /** 2298 * Test for enterprise caller-id. Corp profile exists, but it returns a null cursor. 2299 */ testPhoneLookupEnterprise_withCorpProfile_nullResult()2300 public void testPhoneLookupEnterprise_withCorpProfile_nullResult() throws Exception { 2301 setUpNullCorpProvider(); 2302 2303 Uri uri1 = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, "408-111-1111"); 2304 2305 // No contacts profile, no data. 2306 assertEquals(0, getCount(uri1)); 2307 2308 // Insert a contact into the primary CP2. 2309 long rawContactId = ContentUris.parseId( 2310 mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); 2311 DataUtil.insertStructuredName(mResolver, rawContactId, "Contact1", "Doe"); 2312 insertPhoneNumber(rawContactId, "408-111-1111"); 2313 2314 // Do the query again and check the result. 2315 Cursor c = mResolver.query(uri1, null, null, null, null); 2316 try { 2317 assertEquals(1, c.getCount()); 2318 c.moveToPosition(0); 2319 long contactId = c.getLong(c.getColumnIndex(PhoneLookup._ID)); 2320 assertFalse(Contacts.isEnterpriseContactId(contactId)); // Make sure it's not rewritten. 2321 } finally { 2322 c.close(); 2323 } 2324 } 2325 2326 /** 2327 * Set up the corp user / CP2 and returns the corp CP2 instance. 2328 * 2329 * Create a second instance of CP2, and add it to the resolver, with the "user-id@" authority. 2330 */ setUpCorpProvider()2331 private SynchronousContactsProvider2 setUpCorpProvider() throws Exception { 2332 mActor.mockUserManager.setUsers(MockUserManager.PRIMARY_USER, MockUserManager.CORP_USER); 2333 2334 // Note here we use a standalone CP2 so it'll have its own db helper. 2335 // Also use AlteringUserContext here to report the corp user id. 2336 final int userId = MockUserManager.CORP_USER.id; 2337 SynchronousContactsProvider2 provider = mActor.addProvider( 2338 new SecondaryUserContactsProvider2(userId), 2339 "" + userId + "@com.android.contacts", 2340 new AlteringUserContext(mActor.getProviderContext(), userId)); 2341 provider.wipeData(); 2342 return provider; 2343 } 2344 2345 /** 2346 * Similar to {@link #setUpCorpProvider}, but the corp CP2 set up with this will always return 2347 * null from query(). 2348 */ setUpNullCorpProvider()2349 private void setUpNullCorpProvider() throws Exception { 2350 mActor.mockUserManager.setUsers(MockUserManager.PRIMARY_USER, MockUserManager.CORP_USER); 2351 2352 mActor.addProvider( 2353 NullContentProvider.class, 2354 "" + MockUserManager.CORP_USER.id + "@com.android.contacts", 2355 new AlteringUserContext(mActor.getProviderContext(), MockUserManager.CORP_USER.id)); 2356 } 2357 2358 /** 2359 * Test for query of merged primary and work contacts. 2360 * <p/> 2361 * Note: in this test, we add one more provider instance for the authority 2362 * "10@com.android.contacts" and use it as the corp cp2. 2363 */ testQueryMergedDataPhones()2364 public void testQueryMergedDataPhones() throws Exception { 2365 mActor.addPermissions("android.permission.INTERACT_ACROSS_USERS"); 2366 2367 // Insert a contact to the primary CP2. 2368 long rawContactId = ContentUris.parseId( 2369 mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); 2370 DataUtil.insertStructuredName(mResolver, rawContactId, "Contact1", "Primary"); 2371 2372 insertPhoneNumber(rawContactId, "111-111-1111", false, false, Phone.TYPE_MOBILE); 2373 2374 // Insert a contact to the corp CP2, with different name and phone number. 2375 final SynchronousContactsProvider2 corpCp2 = setUpCorpProvider(); 2376 rawContactId = ContentUris.parseId( 2377 corpCp2.insert(RawContacts.CONTENT_URI, new ContentValues())); 2378 // Insert a name. 2379 ContentValues cv = cv( 2380 Data.RAW_CONTACT_ID, rawContactId, 2381 Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE, 2382 StructuredName.DISPLAY_NAME, "Contact2 Corp", 2383 StructuredName.GIVEN_NAME, "Contact2", 2384 StructuredName.FAMILY_NAME, "Corp"); 2385 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 2386 // Insert a number. 2387 cv = cv( 2388 Data.RAW_CONTACT_ID, rawContactId, 2389 Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE, 2390 Phone.NUMBER, "222-222-2222", 2391 Phone.TYPE, Phone.TYPE_MOBILE); 2392 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 2393 2394 // Insert another contact to to corp CP2, with different name phone number and phone type 2395 rawContactId = ContentUris.parseId( 2396 corpCp2.insert(RawContacts.CONTENT_URI, new ContentValues())); 2397 // Insert a name. 2398 cv = cv( 2399 Data.RAW_CONTACT_ID, rawContactId, 2400 Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE, 2401 StructuredName.DISPLAY_NAME, "Contact3 Corp", 2402 StructuredName.GIVEN_NAME, "Contact3", 2403 StructuredName.FAMILY_NAME, "Corp"); 2404 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 2405 // Insert a number 2406 cv = cv( 2407 Data.RAW_CONTACT_ID, rawContactId, 2408 Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE, 2409 Phone.NUMBER, "333-333-3333", 2410 Phone.TYPE, Phone.TYPE_HOME); 2411 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 2412 2413 // Execute the query to get the merged result. 2414 Cursor c = mResolver.query(Phone.ENTERPRISE_CONTENT_URI, new String[]{Phone.CONTACT_ID, 2415 Phone.DISPLAY_NAME, Phone.NUMBER}, Phone.TYPE + " = ?", 2416 new String[]{String.valueOf(Phone.TYPE_MOBILE)}, null); 2417 try { 2418 // Verify the primary contact. 2419 assertEquals(2, c.getCount()); 2420 assertEquals(3, c.getColumnCount()); 2421 c.moveToPosition(0); 2422 assertEquals("Contact1 Primary", c.getString(c.getColumnIndex(Phone.DISPLAY_NAME))); 2423 assertEquals("111-111-1111", c.getString(c.getColumnIndex(Phone.NUMBER))); 2424 long contactId = c.getLong(c.getColumnIndex(Phone.CONTACT_ID)); 2425 assertFalse(Contacts.isEnterpriseContactId(contactId)); 2426 2427 // Verify the enterprise contact. 2428 c.moveToPosition(1); 2429 assertEquals("Contact2 Corp", c.getString(c.getColumnIndex(Phone.DISPLAY_NAME))); 2430 assertEquals("222-222-2222", c.getString(c.getColumnIndex(Phone.NUMBER))); 2431 contactId = c.getLong(c.getColumnIndex(Phone.CONTACT_ID)); 2432 assertTrue(Contacts.isEnterpriseContactId(contactId)); 2433 } finally { 2434 c.close(); 2435 } 2436 } 2437 2438 /** 2439 * Test for query of merged primary and work contacts. 2440 * <p/> 2441 * Note: in this test, we add one more provider instance for the authority 2442 * "10@com.android.contacts" and use it as the corp cp2. 2443 */ testQueryMergedDataPhones_nullCorp()2444 public void testQueryMergedDataPhones_nullCorp() throws Exception { 2445 mActor.addPermissions("android.permission.INTERACT_ACROSS_USERS"); 2446 2447 // Insert a contact to the primary CP2. 2448 long rawContactId = ContentUris.parseId( 2449 mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); 2450 DataUtil.insertStructuredName(mResolver, rawContactId, "Contact1", "Primary"); 2451 2452 insertPhoneNumber(rawContactId, "111-111-1111", false, false, Phone.TYPE_MOBILE); 2453 2454 // Insert a contact to the corp CP2, with different name and phone number. 2455 setUpNullCorpProvider(); 2456 2457 // Execute the query to get the merged result. 2458 Cursor c = mResolver.query(Phone.ENTERPRISE_CONTENT_URI, new String[]{Phone.CONTACT_ID, 2459 Phone.DISPLAY_NAME, Phone.NUMBER}, Phone.TYPE + " = ?", 2460 new String[]{String.valueOf(Phone.TYPE_MOBILE)}, null); 2461 try { 2462 // Verify the primary contact. 2463 assertEquals(1, c.getCount()); 2464 assertEquals(3, c.getColumnCount()); 2465 c.moveToPosition(0); 2466 assertEquals("Contact1 Primary", c.getString(c.getColumnIndex(Phone.DISPLAY_NAME))); 2467 assertEquals("111-111-1111", c.getString(c.getColumnIndex(Phone.NUMBER))); 2468 long contactId = c.getLong(c.getColumnIndex(Phone.CONTACT_ID)); 2469 assertFalse(Contacts.isEnterpriseContactId(contactId)); 2470 } finally { 2471 c.close(); 2472 } 2473 } 2474 2475 /** 2476 * Test for enterprise caller-id, with the corp profile. 2477 * 2478 * Note: in this test, we add one more provider instance for the authority 2479 * "10@com.android.contacts" and use it as the corp cp2. 2480 */ testPhoneLookupEnterprise_withCorpProfile()2481 public void testPhoneLookupEnterprise_withCorpProfile() throws Exception { 2482 final SynchronousContactsProvider2 corpCp2 = setUpCorpProvider(); 2483 2484 Uri uri1 = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, "408-111-1111"); 2485 Uri uri2 = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, "408-222-2222"); 2486 2487 // First, test with no contacts on either profile. 2488 assertEquals(0, getCount(uri1)); 2489 2490 // Insert a contact to the primary CP2. 2491 long rawContactId = ContentUris.parseId( 2492 mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); 2493 DataUtil.insertStructuredName(mResolver, rawContactId, "Contact1", "Doe"); 2494 insertPhoneNumber(rawContactId, "408-111-1111"); 2495 2496 // Insert a contact to the corp CP2, with the same phone number, but with a different name. 2497 rawContactId = ContentUris.parseId( 2498 corpCp2.insert(RawContacts.CONTENT_URI, new ContentValues())); 2499 // Insert a name 2500 ContentValues cv = cv( 2501 Data.RAW_CONTACT_ID, rawContactId, 2502 Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE, 2503 StructuredName.DISPLAY_NAME, "Contact2 Corp", 2504 StructuredName.GIVEN_NAME, "Contact2", 2505 StructuredName.FAMILY_NAME, "Corp"); 2506 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 2507 2508 // Insert a number 2509 cv = cv( 2510 Data.RAW_CONTACT_ID, rawContactId, 2511 Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE, 2512 Phone.NUMBER, "408-111-1111", 2513 Phone.TYPE, Phone.TYPE_HOME); 2514 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 2515 2516 // Insert one more contact to the corp CP2, with a different number. 2517 rawContactId = ContentUris.parseId( 2518 corpCp2.insert(RawContacts.CONTENT_URI, new ContentValues())); 2519 // Insert a name 2520 cv = cv( 2521 Data.RAW_CONTACT_ID, rawContactId, 2522 Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE, 2523 StructuredName.DISPLAY_NAME, "Contact3 Corp", 2524 StructuredName.GIVEN_NAME, "Contact3", 2525 StructuredName.FAMILY_NAME, "Corp"); 2526 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 2527 2528 // Insert a number 2529 cv = cv( 2530 Data.RAW_CONTACT_ID, rawContactId, 2531 Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE, 2532 Phone.NUMBER, "408-222-2222", 2533 Phone.TYPE, Phone.TYPE_HOME); 2534 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 2535 2536 // Okay, now execute queries and check the result. 2537 2538 // The first URL hits the contact in the primary CP2. 2539 // There's also a contact with this phone number in the corp CP2, but that will be ignored. 2540 Cursor c = mResolver.query(uri1, null, null, null, null); 2541 try { 2542 assertEquals(1, c.getCount()); 2543 c.moveToPosition(0); 2544 assertEquals("Contact1 Doe", c.getString(c.getColumnIndex(PhoneLookup.DISPLAY_NAME))); 2545 2546 // Make sure it has a personal contact ID. 2547 long contactId = c.getLong(c.getColumnIndex(PhoneLookup._ID)); 2548 assertFalse(Contacts.isEnterpriseContactId(contactId)); 2549 } finally { 2550 c.close(); 2551 } 2552 2553 // Test for the second phone number, which only exists in the corp cp2. 2554 c = mResolver.query(uri2, null, null, null, null); 2555 try { 2556 // This one actually returns 2 identical rows, probably because of the join 2557 // in phone_lookup. Callers only care the first row, so returning multiple identical 2558 // rows should be fine. 2559 assertTrue(c.getCount() > 0); 2560 c.moveToPosition(0); 2561 assertEquals("Contact3 Corp", c.getString(c.getColumnIndex(PhoneLookup.DISPLAY_NAME))); 2562 2563 // Make sure it has a corp contact ID. 2564 long contactId = c.getLong(c.getColumnIndex(PhoneLookup._ID)); 2565 assertTrue(Contacts.isEnterpriseContactId(contactId)); 2566 } finally { 2567 c.close(); 2568 } 2569 } 2570 testQueryRawContactEntitiesCorp_noCorpProfile()2571 public void testQueryRawContactEntitiesCorp_noCorpProfile() { 2572 mActor.addPermissions("android.permission.INTERACT_ACROSS_USERS"); 2573 2574 // Insert a contact into the primary CP2. 2575 long rawContactId = ContentUris.parseId( 2576 mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); 2577 DataUtil.insertStructuredName(mResolver, rawContactId, "Contact1", "Doe"); 2578 insertPhoneNumber(rawContactId, "408-111-1111"); 2579 2580 // No corp profile, no data. 2581 assertEquals(0, getCount(RawContactsEntity.CORP_CONTENT_URI)); 2582 } 2583 testQueryRawContactEntitiesCorp_withCorpProfile()2584 public void testQueryRawContactEntitiesCorp_withCorpProfile() throws Exception { 2585 mActor.addPermissions("android.permission.INTERACT_ACROSS_USERS"); 2586 2587 // Insert a contact into the primary CP2. 2588 long rawContactId = ContentUris.parseId( 2589 mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); 2590 DataUtil.insertStructuredName(mResolver, rawContactId, "Contact1", "Doe"); 2591 insertPhoneNumber(rawContactId, "408-111-1111"); 2592 2593 // Insert a contact into corp CP2. 2594 final SynchronousContactsProvider2 corpCp2 = setUpCorpProvider(); 2595 rawContactId = ContentUris.parseId( 2596 corpCp2.insert(RawContacts.CONTENT_URI, new ContentValues())); 2597 // Insert a name. 2598 ContentValues cv = cv( 2599 Data.RAW_CONTACT_ID, rawContactId, 2600 Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE, 2601 StructuredName.DISPLAY_NAME, "Contact2 Corp"); 2602 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 2603 // Insert a number. 2604 cv = cv( 2605 Data.RAW_CONTACT_ID, rawContactId, 2606 Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE, 2607 Phone.NUMBER, "222-222-2222", 2608 Phone.TYPE, Phone.TYPE_MOBILE); 2609 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 2610 2611 // Do the query 2612 Cursor c = mResolver.query(RawContactsEntity.CORP_CONTENT_URI, 2613 new String[]{RawContactsEntity._ID, RawContactsEntity.DATA1}, 2614 RawContactsEntity.MIMETYPE + "=?", new String[]{ 2615 StructuredName.CONTENT_ITEM_TYPE}, null); 2616 // The result should only contains corp data. 2617 assertEquals(1, c.getCount()); 2618 assertEquals(2, c.getColumnCount()); 2619 c.moveToPosition(0); 2620 long id = c.getLong(c.getColumnIndex(RawContactsEntity._ID)); 2621 String data1 = c.getString(c.getColumnIndex(RawContactsEntity.DATA1)); 2622 assertEquals("Contact2 Corp", data1); 2623 assertEquals(rawContactId, id); 2624 c.close(); 2625 } 2626 testRewriteCorpDirectories()2627 public void testRewriteCorpDirectories() { 2628 // 6 columns 2629 final MatrixCursor c = new MatrixCursor(new String[] { 2630 Directory._ID, 2631 Directory.PACKAGE_NAME, 2632 Directory.TYPE_RESOURCE_ID, 2633 Directory.DISPLAY_NAME, 2634 Directory.ACCOUNT_TYPE, 2635 Directory.ACCOUNT_NAME, 2636 }); 2637 2638 // First, convert and make sure it returns an empty cursor. 2639 Cursor rewritten = ContactsProvider2.rewriteCorpDirectories(c); 2640 2641 assertEquals(0, rewritten.getCount()); 2642 assertEquals(6, rewritten.getColumnCount()); 2643 2644 c.addRow(new Object[] { 2645 5L, // Directory._ID 2646 "name", // Directory.PACKAGE_NAME 2647 123, // Directory.TYPE_RESOURCE_ID 2648 "display", // Directory.DISPLAY_NAME 2649 "atype", // Directory.ACCOUNT_TYPE 2650 "aname", // Directory.ACCOUNT_NAME 2651 }); 2652 2653 rewritten = ContactsProvider2.rewriteCorpDirectories(c); 2654 assertEquals(1, rewritten.getCount()); 2655 assertEquals(6, rewritten.getColumnCount()); 2656 2657 rewritten.moveToPosition(0); 2658 int column = 0; 2659 assertEquals(1000000005L, rewritten.getLong(column++)); 2660 assertEquals("name", rewritten.getString(column++)); 2661 assertEquals(123, rewritten.getInt(column++)); 2662 assertEquals("display", rewritten.getString(column++)); 2663 assertEquals("atype", rewritten.getString(column++)); 2664 assertEquals("aname", rewritten.getString(column++)); 2665 } 2666 testPhoneUpdate()2667 public void testPhoneUpdate() { 2668 ContentValues values = new ContentValues(); 2669 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2670 long rawContactId = ContentUris.parseId(rawContactUri); 2671 2672 DataUtil.insertStructuredName(mResolver, rawContactId, "Hot", "Tamale"); 2673 Uri phoneUri = insertPhoneNumber(rawContactId, "18004664411"); 2674 2675 Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411"); 2676 Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664422"); 2677 assertEquals(2, getCount(lookupUri1, null, null)); 2678 assertEquals(0, getCount(lookupUri2, null, null)); 2679 2680 values.clear(); 2681 values.put(Phone.NUMBER, "18004664422"); 2682 mResolver.update(phoneUri, values, null, null); 2683 2684 assertEquals(0, getCount(lookupUri1, null, null)); 2685 assertEquals(2, getCount(lookupUri2, null, null)); 2686 2687 // Setting number to null will remove the phone lookup record 2688 values.clear(); 2689 values.putNull(Phone.NUMBER); 2690 mResolver.update(phoneUri, values, null, null); 2691 2692 assertEquals(0, getCount(lookupUri1, null, null)); 2693 assertEquals(0, getCount(lookupUri2, null, null)); 2694 2695 // Let's restore that phone lookup record 2696 values.clear(); 2697 values.put(Phone.NUMBER, "18004664422"); 2698 mResolver.update(phoneUri, values, null, null); 2699 assertEquals(0, getCount(lookupUri1, null, null)); 2700 assertEquals(2, getCount(lookupUri2, null, null)); 2701 assertNetworkNotified(true); 2702 } 2703 2704 /** Tests if {@link Callable#CONTENT_URI} returns both phones and sip addresses. */ testCallablesQuery()2705 public void testCallablesQuery() { 2706 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "Meghan", "Knox"); 2707 long phoneId1 = ContentUris.parseId(insertPhoneNumber(rawContactId1, "18004664411")); 2708 long contactId1 = queryContactId(rawContactId1); 2709 2710 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe"); 2711 long sipAddressId2 = ContentUris.parseId( 2712 insertSipAddress(rawContactId2, "sip@example.com")); 2713 long contactId2 = queryContactId(rawContactId2); 2714 2715 ContentValues values1 = new ContentValues(); 2716 values1.put(Data._ID, phoneId1); 2717 values1.put(Data.RAW_CONTACT_ID, rawContactId1); 2718 values1.put(RawContacts.CONTACT_ID, contactId1); 2719 values1.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 2720 values1.put(Phone.NUMBER, "18004664411"); 2721 values1.put(Phone.TYPE, Phone.TYPE_HOME); 2722 values1.putNull(Phone.LABEL); 2723 values1.put(Contacts.DISPLAY_NAME, "Meghan Knox"); 2724 2725 ContentValues values2 = new ContentValues(); 2726 values2.put(Data._ID, sipAddressId2); 2727 values2.put(Data.RAW_CONTACT_ID, rawContactId2); 2728 values2.put(RawContacts.CONTACT_ID, contactId2); 2729 values2.put(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE); 2730 values2.put(SipAddress.SIP_ADDRESS, "sip@example.com"); 2731 values2.put(Contacts.DISPLAY_NAME, "John Doe"); 2732 2733 assertEquals(2, getCount(Callable.CONTENT_URI, null, null)); 2734 assertStoredValues(Callable.CONTENT_URI, new ContentValues[] { values1, values2 }); 2735 } 2736 testCallablesFilterQuery()2737 public void testCallablesFilterQuery() { 2738 testPhonesFilterQueryInter(Callable.CONTENT_FILTER_URI); 2739 } 2740 testEmailsQuery()2741 public void testEmailsQuery() { 2742 ContentValues values = new ContentValues(); 2743 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 2744 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 2745 values.put(RawContacts.LAST_TIME_CONTACTED, 86400 + 5); 2746 values.put(RawContacts.TIMES_CONTACTED, 54321); 2747 values.put(RawContacts.STARRED, 1); 2748 2749 Uri rawContactUri = insertRawContact(values); 2750 final long rawContactId = ContentUris.parseId(rawContactUri); 2751 2752 DataUtil.insertStructuredName(mResolver, rawContactId, "Meghan", "Knox"); 2753 final Uri emailUri = insertEmail(rawContactId, "meghan@acme.com"); 2754 final long emailId = ContentUris.parseId(emailUri); 2755 2756 final long contactId = queryContactId(rawContactId); 2757 values.clear(); 2758 values.put(Data._ID, emailId); 2759 values.put(Data.RAW_CONTACT_ID, rawContactId); 2760 values.put(RawContacts.CONTACT_ID, contactId); 2761 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 2762 values.put(Email.DATA, "meghan@acme.com"); 2763 values.put(Email.TYPE, Email.TYPE_HOME); 2764 values.putNull(Email.LABEL); 2765 values.put(Contacts.DISPLAY_NAME, "Meghan Knox"); 2766 values.put(Contacts.CUSTOM_RINGTONE, "d"); 2767 values.put(Contacts.SEND_TO_VOICEMAIL, 1); 2768 values.put(Contacts.LAST_TIME_CONTACTED, 0); 2769 values.put(Contacts.TIMES_CONTACTED, 0); 2770 values.put(Contacts.STARRED, 1); 2771 2772 assertStoredValues(Email.CONTENT_URI, values); 2773 assertStoredValues(ContentUris.withAppendedId(Email.CONTENT_URI, emailId), values); 2774 2775 // Check if the provider detects duplicated email addresses. 2776 final Uri emailUri2 = insertEmail(rawContactId, "meghan@acme.com"); 2777 final long emailId2 = ContentUris.parseId(emailUri2); 2778 final ContentValues values2 = new ContentValues(values); 2779 values2.put(Data._ID, emailId2); 2780 2781 final Uri dedupeUri = Email.CONTENT_URI.buildUpon() 2782 .appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true") 2783 .build(); 2784 2785 // URI with ID should return a correct result. 2786 assertStoredValues(ContentUris.withAppendedId(Email.CONTENT_URI, emailId), values); 2787 assertStoredValues(ContentUris.withAppendedId(dedupeUri, emailId), values); 2788 assertStoredValues(ContentUris.withAppendedId(Email.CONTENT_URI, emailId2), values2); 2789 assertStoredValues(ContentUris.withAppendedId(dedupeUri, emailId2), values2); 2790 2791 assertStoredValues(Email.CONTENT_URI, new ContentValues[] {values, values2}); 2792 2793 // If requested to remove duplicates, the query should return just one result, 2794 // whose _ID won't be deterministic. 2795 values.remove(Data._ID); 2796 assertStoredValues(dedupeUri, values); 2797 } 2798 testEmailsLookupQuery()2799 public void testEmailsLookupQuery() { 2800 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale"); 2801 insertEmail(rawContactId, "tamale@acme.com"); 2802 2803 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "tamale@acme.com"); 2804 ContentValues values = new ContentValues(); 2805 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 2806 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 2807 values.put(Email.DATA, "tamale@acme.com"); 2808 values.put(Email.TYPE, Email.TYPE_HOME); 2809 values.putNull(Email.LABEL); 2810 assertStoredValues(filterUri1, values); 2811 2812 Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "Ta<TaMale@acme.com>"); 2813 assertStoredValues(filterUri2, values); 2814 2815 Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "encilada@acme.com"); 2816 assertEquals(0, getCount(filterUri3, null, null)); 2817 } 2818 testEmailsFilterQuery()2819 public void testEmailsFilterQuery() { 2820 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale", 2821 TestUtil.ACCOUNT_1); 2822 insertEmail(rawContactId1, "tamale@acme.com"); 2823 insertEmail(rawContactId1, "tamale@acme.com"); 2824 2825 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "Hot", "Tamale", 2826 TestUtil.ACCOUNT_2); 2827 insertEmail(rawContactId2, "tamale@acme.com"); 2828 2829 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tam"); 2830 ContentValues values = new ContentValues(); 2831 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 2832 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 2833 values.put(Email.DATA, "tamale@acme.com"); 2834 values.put(Email.TYPE, Email.TYPE_HOME); 2835 values.putNull(Email.LABEL); 2836 assertStoredValuesWithProjection(filterUri1, values); 2837 2838 Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hot"); 2839 assertStoredValuesWithProjection(filterUri2, values); 2840 2841 Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hot tamale"); 2842 assertStoredValuesWithProjection(filterUri3, values); 2843 2844 Uri filterUri4 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tamale@acme"); 2845 assertStoredValuesWithProjection(filterUri4, values); 2846 2847 Uri filterUri5 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "encilada"); 2848 assertEquals(0, getCount(filterUri5, null, null)); 2849 } 2850 2851 /** 2852 * Tests if ContactsProvider2 returns addresses according to registration order. 2853 */ testEmailFilterDefaultSortOrder()2854 public void testEmailFilterDefaultSortOrder() { 2855 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 2856 insertEmail(rawContactId1, "address1@email.com"); 2857 insertEmail(rawContactId1, "address2@email.com"); 2858 insertEmail(rawContactId1, "address3@email.com"); 2859 ContentValues v1 = new ContentValues(); 2860 v1.put(Email.ADDRESS, "address1@email.com"); 2861 ContentValues v2 = new ContentValues(); 2862 v2.put(Email.ADDRESS, "address2@email.com"); 2863 ContentValues v3 = new ContentValues(); 2864 v3.put(Email.ADDRESS, "address3@email.com"); 2865 2866 Uri filterUri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "address"); 2867 assertStoredValuesOrderly(filterUri, new ContentValues[]{v1, v2, v3}); 2868 } 2869 2870 /** 2871 * Tests if ContactsProvider2 returns primary addresses before the other addresses. 2872 */ testEmailFilterPrimaryAddress()2873 public void testEmailFilterPrimaryAddress() { 2874 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 2875 insertEmail(rawContactId1, "address1@email.com"); 2876 insertEmail(rawContactId1, "address2@email.com", true); 2877 ContentValues v1 = new ContentValues(); 2878 v1.put(Email.ADDRESS, "address1@email.com"); 2879 ContentValues v2 = new ContentValues(); 2880 v2.put(Email.ADDRESS, "address2@email.com"); 2881 2882 Uri filterUri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "address"); 2883 assertStoredValuesOrderly(filterUri, new ContentValues[] { v2, v1 }); 2884 } 2885 2886 /** 2887 * Tests if ContactsProvider2 has email address associated with a primary account before the 2888 * other address. 2889 */ testEmailFilterPrimaryAccount()2890 public void testEmailFilterPrimaryAccount() { 2891 long rawContactId1 = RawContactUtil.createRawContact(mResolver, TestUtil.ACCOUNT_1); 2892 insertEmail(rawContactId1, "account1@email.com"); 2893 long rawContactId2 = RawContactUtil.createRawContact(mResolver, TestUtil.ACCOUNT_2); 2894 insertEmail(rawContactId2, "account2@email.com"); 2895 ContentValues v1 = new ContentValues(); 2896 v1.put(Email.ADDRESS, "account1@email.com"); 2897 ContentValues v2 = new ContentValues(); 2898 v2.put(Email.ADDRESS, "account2@email.com"); 2899 2900 Uri filterUri1 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc") 2901 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, TestUtil.ACCOUNT_1.name) 2902 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE, TestUtil.ACCOUNT_1.type) 2903 .build(); 2904 assertStoredValuesOrderly(filterUri1, new ContentValues[] { v1, v2 }); 2905 2906 Uri filterUri2 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc") 2907 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, TestUtil.ACCOUNT_2.name) 2908 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE, TestUtil.ACCOUNT_2.type) 2909 .build(); 2910 assertStoredValuesOrderly(filterUri2, new ContentValues[] { v2, v1 }); 2911 2912 // Just with PRIMARY_ACCOUNT_NAME 2913 Uri filterUri3 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc") 2914 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, TestUtil.ACCOUNT_1.name) 2915 .build(); 2916 assertStoredValuesOrderly(filterUri3, new ContentValues[]{v1, v2}); 2917 2918 Uri filterUri4 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc") 2919 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, TestUtil.ACCOUNT_2.name) 2920 .build(); 2921 assertStoredValuesOrderly(filterUri4, new ContentValues[] { v2, v1 }); 2922 } 2923 2924 /** 2925 * Test emails with the same domain as primary account are ordered first. 2926 */ testEmailFilterSameDomainAccountOrder()2927 public void testEmailFilterSameDomainAccountOrder() { 2928 final Account account = new Account("tester@email.com", "not_used"); 2929 final long rawContactId = RawContactUtil.createRawContact(mResolver, account); 2930 insertEmail(rawContactId, "account1@testemail.com"); 2931 insertEmail(rawContactId, "account1@email.com"); 2932 2933 final ContentValues v1 = cv(Email.ADDRESS, "account1@testemail.com"); 2934 final ContentValues v2 = cv(Email.ADDRESS, "account1@email.com"); 2935 2936 Uri filterUri1 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc") 2937 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, account.name) 2938 .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE, account.type) 2939 .build(); 2940 assertStoredValuesOrderly(filterUri1, v2, v1); 2941 } 2942 2943 /** 2944 * Test "default" emails are sorted above emails used last. 2945 */ testEmailFilterSuperPrimaryOverUsageSort()2946 public void testEmailFilterSuperPrimaryOverUsageSort() { 2947 final long rawContactId = RawContactUtil.createRawContact(mResolver, TestUtil.ACCOUNT_1); 2948 final Uri emailUri1 = insertEmail(rawContactId, "account1@testemail.com"); 2949 final Uri emailUri2 = insertEmail(rawContactId, "account2@testemail.com"); 2950 insertEmail(rawContactId, "account3@testemail.com", true, true); 2951 2952 // Update account1 and account 2 to have higher usage. 2953 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, emailUri1); 2954 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, emailUri1); 2955 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, emailUri2); 2956 2957 final ContentValues v1 = cv(Email.ADDRESS, "account1@testemail.com"); 2958 final ContentValues v2 = cv(Email.ADDRESS, "account2@testemail.com"); 2959 final ContentValues v3 = cv(Email.ADDRESS, "account3@testemail.com"); 2960 2961 // Test that account 3 is first even though account 1 and 2 have higher usage. 2962 Uri filterUri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "acc"); 2963 assertStoredValuesOrderly(filterUri, v3, v1, v2); 2964 } 2965 testEmailFilterUsageOverPrimarySort()2966 public void testEmailFilterUsageOverPrimarySort() { 2967 final long rawContactId = RawContactUtil.createRawContact(mResolver, TestUtil.ACCOUNT_1); 2968 final Uri emailUri1 = insertEmail(rawContactId, "account1@testemail.com"); 2969 final Uri emailUri2 = insertEmail(rawContactId, "account2@testemail.com"); 2970 insertEmail(rawContactId, "account3@testemail.com", true); 2971 2972 // Update account1 and account 2 to have higher usage. 2973 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, emailUri1); 2974 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, emailUri1); 2975 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, emailUri2); 2976 2977 final ContentValues v1 = cv(Email.ADDRESS, "account1@testemail.com"); 2978 final ContentValues v2 = cv(Email.ADDRESS, "account2@testemail.com"); 2979 final ContentValues v3 = cv(Email.ADDRESS, "account3@testemail.com"); 2980 2981 // No usage stats any more, so v3 is still the first. 2982 Uri filterUri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "acc"); 2983 assertStoredValuesOrderly(filterUri, v3, v1, v2); 2984 } 2985 2986 /** Tests {@link DataUsageFeedback} correctly promotes a data row instead of a raw contact. */ testEmailFilterSortOrderWithFeedback()2987 public void testEmailFilterSortOrderWithFeedback() { 2988 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 2989 String address1 = "address1@email.com"; 2990 insertEmail(rawContactId1, address1); 2991 2992 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 2993 String address2 = "address2@email.com"; 2994 insertEmail(rawContactId2, address2); 2995 String address3 = "address3@email.com"; 2996 ContentUris.parseId(insertEmail(rawContactId2, address3)); 2997 2998 ContentValues v1 = new ContentValues(); 2999 v1.put(Email.ADDRESS, "address1@email.com"); 3000 ContentValues v2 = new ContentValues(); 3001 v2.put(Email.ADDRESS, "address2@email.com"); 3002 ContentValues v3 = new ContentValues(); 3003 v3.put(Email.ADDRESS, "address3@email.com"); 3004 3005 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "address"); 3006 Uri filterUri2 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("address") 3007 .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, 3008 DataUsageFeedback.USAGE_TYPE_CALL) 3009 .build(); 3010 Uri filterUri3 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("address") 3011 .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, 3012 DataUsageFeedback.USAGE_TYPE_LONG_TEXT) 3013 .build(); 3014 Uri filterUri4 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("address") 3015 .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, 3016 DataUsageFeedback.USAGE_TYPE_SHORT_TEXT) 3017 .build(); 3018 assertStoredValuesOrderly(filterUri1, new ContentValues[] { v1, v2, v3 }); 3019 assertStoredValuesOrderly(filterUri2, new ContentValues[] { v1, v2, v3 }); 3020 assertStoredValuesOrderly(filterUri3, new ContentValues[] { v1, v2, v3 }); 3021 assertStoredValuesOrderly(filterUri4, new ContentValues[] { v1, v2, v3 }); 3022 3023 sendFeedback(address3, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, v3); 3024 3025 assertStoredValuesWithProjection(RawContacts.CONTENT_URI, 3026 cv(RawContacts._ID, rawContactId1, 3027 RawContacts.TIMES_CONTACTED, 0 3028 ), 3029 cv(RawContacts._ID, rawContactId2, 3030 RawContacts.TIMES_CONTACTED, 0 3031 ) 3032 ); 3033 3034 // No more interaction counter, so the order doesn't change. 3035 assertStoredValuesOrderly(filterUri1, new ContentValues[] { v1, v2, v3 }); 3036 assertStoredValuesOrderly(filterUri3, new ContentValues[] { v1, v2, v3 }); 3037 } 3038 testAddQueryParametersFromUri()3039 public void testAddQueryParametersFromUri() { 3040 final ContactsProvider2 provider = (ContactsProvider2) getProvider(); 3041 final Uri originalUri = Phone.CONTENT_FILTER_URI.buildUpon() 3042 .appendQueryParameter("a", "a") 3043 .appendQueryParameter("b", "b") 3044 .appendQueryParameter("c", "c").build(); 3045 final Uri.Builder targetBuilder = Phone.CONTENT_FILTER_URI.buildUpon(); 3046 provider.addQueryParametersFromUri(targetBuilder, originalUri, 3047 new ArraySet<String>(Arrays.asList(new String[] { 3048 "b" 3049 }))); 3050 final Uri targetUri = targetBuilder.build(); 3051 assertEquals(1, targetUri.getQueryParameters("a").size()); 3052 assertEquals(0, targetUri.getQueryParameters("b").size()); 3053 assertEquals(1, targetUri.getQueryParameters("c").size()); 3054 } 3055 buildContactsFilterUriWithDirectory(String directory)3056 private Uri buildContactsFilterUriWithDirectory(String directory) { 3057 return Contacts.CONTENT_FILTER_URI.buildUpon() 3058 .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, directory).build(); 3059 } 3060 testTestInvalidDirectory()3061 public void testTestInvalidDirectory() throws Exception { 3062 final ContactsProvider2 provider = (ContactsProvider2) getProvider(); 3063 assertTrue(provider.isDirectoryParamValid(Contacts.CONTENT_FILTER_URI)); 3064 assertFalse(provider.isDirectoryParamValid(buildContactsFilterUriWithDirectory(""))); 3065 assertTrue(provider.isDirectoryParamValid(buildContactsFilterUriWithDirectory("0"))); 3066 assertTrue(provider.isDirectoryParamValid(buildContactsFilterUriWithDirectory("123"))); 3067 assertFalse(provider.isDirectoryParamValid(buildContactsFilterUriWithDirectory("abc"))); 3068 } 3069 testQueryCorpContactsProvider()3070 public void testQueryCorpContactsProvider() throws Exception { 3071 final ContactsProvider2 provider = (ContactsProvider2) getProvider(); 3072 final MockUserManager um = mActor.mockUserManager; 3073 final Uri enterpriseUri = 3074 Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, "408-222-2222"); 3075 final Uri invalidAuthorityUri = android.provider.Settings.Secure.CONTENT_URI; 3076 3077 // No corp user. Primary only. 3078 assertEquals(-1, UserUtils.getCorpUserId(mActor.getProviderContext())); 3079 assertEquals(0, provider.queryCorpContactsProvider(enterpriseUri, null, null, null, 3080 null, null).getCount()); 3081 3082 final SynchronousContactsProvider2 corpCp2 = setUpCorpProvider(); 3083 // Insert a contact to the corp CP2 3084 long rawContactId = ContentUris.parseId( 3085 corpCp2.insert(RawContacts.CONTENT_URI, new ContentValues())); 3086 // Insert a name 3087 ContentValues cv = cv( 3088 Data.RAW_CONTACT_ID, rawContactId, 3089 Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE, 3090 StructuredName.DISPLAY_NAME, "Contact2 Corp", 3091 StructuredName.GIVEN_NAME, "Contact2", 3092 StructuredName.FAMILY_NAME, "Corp"); 3093 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 3094 // Insert a number 3095 cv = cv( 3096 Data.RAW_CONTACT_ID, rawContactId, 3097 Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE, 3098 Phone.NUMBER, "408-222-2222", 3099 Phone.TYPE, Phone.TYPE_HOME); 3100 corpCp2.insert(ContactsContract.Data.CONTENT_URI, cv); 3101 // Primary + corp 3102 um.setUsers(MockUserManager.PRIMARY_USER, MockUserManager.CORP_USER); 3103 // It returns 2 identical rows, probably because of the join in phone_lookup. 3104 assertEquals(2, provider.queryCorpContactsProvider(enterpriseUri, null, null, null, 3105 null, null).getCount()); 3106 try { 3107 provider.queryCorpContactsProvider(invalidAuthorityUri, null, null, 3108 null, null, null); 3109 fail(invalidAuthorityUri.toString() + " should throw IllegalArgumentException"); 3110 } catch (IllegalArgumentException e) { 3111 // Expected 3112 } 3113 } 3114 testPostalsQuery()3115 public void testPostalsQuery() { 3116 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Alice", "Nextore"); 3117 Uri dataUri = insertPostalAddress(rawContactId, "1600 Amphiteatre Ave, Mountain View"); 3118 final long dataId = ContentUris.parseId(dataUri); 3119 3120 final long contactId = queryContactId(rawContactId); 3121 ContentValues values = new ContentValues(); 3122 values.put(Data._ID, dataId); 3123 values.put(Data.RAW_CONTACT_ID, rawContactId); 3124 values.put(RawContacts.CONTACT_ID, contactId); 3125 values.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE); 3126 values.put(StructuredPostal.FORMATTED_ADDRESS, "1600 Amphiteatre Ave, Mountain View"); 3127 values.put(Contacts.DISPLAY_NAME, "Alice Nextore"); 3128 3129 assertStoredValues(StructuredPostal.CONTENT_URI, values); 3130 assertStoredValues(ContentUris.withAppendedId(StructuredPostal.CONTENT_URI, dataId), 3131 values); 3132 assertSelection(StructuredPostal.CONTENT_URI, values, Data._ID, dataId); 3133 3134 // Check if the provider detects duplicated addresses. 3135 Uri dataUri2 = insertPostalAddress(rawContactId, "1600 Amphiteatre Ave, Mountain View"); 3136 final long dataId2 = ContentUris.parseId(dataUri2); 3137 final ContentValues values2 = new ContentValues(values); 3138 values2.put(Data._ID, dataId2); 3139 3140 final Uri dedupeUri = StructuredPostal.CONTENT_URI.buildUpon() 3141 .appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true") 3142 .build(); 3143 3144 // URI with ID should return a correct result. 3145 assertStoredValues(ContentUris.withAppendedId(StructuredPostal.CONTENT_URI, dataId), 3146 values); 3147 assertStoredValues(ContentUris.withAppendedId(dedupeUri, dataId), values); 3148 assertStoredValues(ContentUris.withAppendedId(StructuredPostal.CONTENT_URI, dataId2), 3149 values2); 3150 assertStoredValues(ContentUris.withAppendedId(dedupeUri, dataId2), values2); 3151 3152 assertStoredValues(StructuredPostal.CONTENT_URI, new ContentValues[] {values, values2}); 3153 3154 // If requested to remove duplicates, the query should return just one result, 3155 // whose _ID won't be deterministic. 3156 values.remove(Data._ID); 3157 assertStoredValues(dedupeUri, values); 3158 } 3159 testDataContentUriInvisibleQuery()3160 public void testDataContentUriInvisibleQuery() { 3161 final ContentValues values = new ContentValues(); 3162 final long contactId = createContact(values, "John", "Doe", 3163 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 3164 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO); 3165 3166 final Uri uri = Data.CONTENT_URI.buildUpon(). 3167 appendQueryParameter(Data.VISIBLE_CONTACTS_ONLY, "true").build(); 3168 assertEquals(4, getCount(uri, null, null)); 3169 3170 markInvisible(contactId); 3171 3172 assertEquals(0, getCount(uri, null, null)); 3173 } 3174 testInDefaultDirectoryData()3175 public void testInDefaultDirectoryData() { 3176 final ContentValues values = new ContentValues(); 3177 final long contactId = createContact(values, "John", "Doe", 3178 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 3179 StatusUpdates.CAPABILITY_HAS_CAMERA); 3180 3181 final StringBuilder query = new StringBuilder() 3182 .append(Data.MIMETYPE).append("='").append(Email.CONTENT_ITEM_TYPE) 3183 .append("' AND ").append(Email.DATA).append("=? AND ") 3184 .append(Contacts.IN_DEFAULT_DIRECTORY).append("=1"); 3185 3186 assertEquals(1, 3187 getCount(Email.CONTENT_URI, query.toString(), new String[]{"goog411@acme.com"})); 3188 3189 // Fire! 3190 markInvisible(contactId); 3191 3192 // Verify: making a contact visible changes the IN_DEFAULT_DIRECTORY data value. 3193 assertEquals(0, 3194 getCount(Email.CONTENT_URI, query.toString(), new String[]{"goog411@acme.com"})); 3195 } 3196 testContactablesQuery()3197 public void testContactablesQuery() { 3198 final long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", 3199 "Tamale"); 3200 3201 insertPhoneNumber(rawContactId, "510-123-5769"); 3202 insertEmail(rawContactId, "tamale@acme.com"); 3203 3204 final ContentValues cv1 = new ContentValues(); 3205 cv1.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 3206 cv1.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 3207 cv1.put(Email.DATA, "tamale@acme.com"); 3208 cv1.put(Email.TYPE, Email.TYPE_HOME); 3209 cv1.putNull(Email.LABEL); 3210 3211 final ContentValues cv2 = new ContentValues(); 3212 cv2.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 3213 cv2.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 3214 cv2.put(Phone.DATA, "510-123-5769"); 3215 cv2.put(Phone.TYPE, Phone.TYPE_HOME); 3216 cv2.putNull(Phone.LABEL); 3217 3218 final Uri filterUri0 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, ""); 3219 assertEquals(0, getCount(filterUri0, null, null)); 3220 3221 final Uri filterUri1 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "tamale"); 3222 assertStoredValues(filterUri1, cv1, cv2); 3223 3224 final Uri filterUri2 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "hot"); 3225 assertStoredValues(filterUri2, cv1, cv2); 3226 3227 final Uri filterUri3 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "tamale@ac"); 3228 assertStoredValues(filterUri3, cv1, cv2); 3229 3230 final Uri filterUri4 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "510"); 3231 assertStoredValues(filterUri4, cv1, cv2); 3232 3233 final Uri filterUri5 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "cold"); 3234 assertEquals(0, getCount(filterUri5, null, null)); 3235 3236 final Uri filterUri6 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, 3237 "tamale@google"); 3238 assertEquals(0, getCount(filterUri6, null, null)); 3239 3240 final Uri filterUri7 = Contactables.CONTENT_URI; 3241 assertStoredValues(filterUri7, cv1, cv2); 3242 } 3243 testContactablesMultipleQuery()3244 public void testContactablesMultipleQuery() { 3245 3246 final long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Hot", 3247 "Tamale"); 3248 insertPhoneNumber(rawContactId, "510-123-5769"); 3249 insertEmail(rawContactId, "tamale@acme.com"); 3250 insertEmail(rawContactId, "hot@google.com"); 3251 3252 final long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "Cold", 3253 "Tamago"); 3254 insertEmail(rawContactId2, "eggs@farmers.org"); 3255 3256 final long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe"); 3257 insertPhoneNumber(rawContactId3, "518-354-1111"); 3258 insertEmail(rawContactId3, "doeadeer@afemaledeer.com"); 3259 3260 final ContentValues cv1 = new ContentValues(); 3261 cv1.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 3262 cv1.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 3263 cv1.put(Email.DATA, "tamale@acme.com"); 3264 cv1.put(Email.TYPE, Email.TYPE_HOME); 3265 cv1.putNull(Email.LABEL); 3266 3267 final ContentValues cv2 = new ContentValues(); 3268 cv2.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 3269 cv2.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 3270 cv2.put(Phone.DATA, "510-123-5769"); 3271 cv2.put(Phone.TYPE, Phone.TYPE_HOME); 3272 cv2.putNull(Phone.LABEL); 3273 3274 final ContentValues cv3 = new ContentValues(); 3275 cv3.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 3276 cv3.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 3277 cv3.put(Email.DATA, "hot@google.com"); 3278 cv3.put(Email.TYPE, Email.TYPE_HOME); 3279 cv3.putNull(Email.LABEL); 3280 3281 final ContentValues cv4 = new ContentValues(); 3282 cv4.put(Contacts.DISPLAY_NAME, "Cold Tamago"); 3283 cv4.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 3284 cv4.put(Email.DATA, "eggs@farmers.org"); 3285 cv4.put(Email.TYPE, Email.TYPE_HOME); 3286 cv4.putNull(Email.LABEL); 3287 3288 final ContentValues cv5 = new ContentValues(); 3289 cv5.put(Contacts.DISPLAY_NAME, "John Doe"); 3290 cv5.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 3291 cv5.put(Email.DATA, "doeadeer@afemaledeer.com"); 3292 cv5.put(Email.TYPE, Email.TYPE_HOME); 3293 cv5.putNull(Email.LABEL); 3294 3295 final ContentValues cv6 = new ContentValues(); 3296 cv6.put(Contacts.DISPLAY_NAME, "John Doe"); 3297 cv6.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 3298 cv6.put(Phone.DATA, "518-354-1111"); 3299 cv6.put(Phone.TYPE, Phone.TYPE_HOME); 3300 cv6.putNull(Phone.LABEL); 3301 3302 final Uri filterUri1 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "tamale"); 3303 3304 assertStoredValues(filterUri1, cv1, cv2, cv3); 3305 3306 final Uri filterUri2 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "hot"); 3307 assertStoredValues(filterUri2, cv1, cv2, cv3); 3308 3309 final Uri filterUri3 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "tam"); 3310 assertStoredValues(filterUri3, cv1, cv2, cv3, cv4); 3311 3312 final Uri filterUri4 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "518"); 3313 assertStoredValues(filterUri4, cv5, cv6); 3314 3315 final Uri filterUri5 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "doe"); 3316 assertStoredValues(filterUri5, cv5, cv6); 3317 3318 final Uri filterUri6 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, "51"); 3319 assertStoredValues(filterUri6, cv1, cv2, cv3, cv5, cv6); 3320 3321 final Uri filterUri7 = Uri.withAppendedPath(Contactables.CONTENT_FILTER_URI, 3322 "tamale@google"); 3323 assertEquals(0, getCount(filterUri7, null, null)); 3324 3325 final Uri filterUri8 = Contactables.CONTENT_URI; 3326 assertStoredValues(filterUri8, cv1, cv2, cv3, cv4, cv5, cv6); 3327 3328 // test VISIBLE_CONTACTS_ONLY boolean parameter 3329 final Uri filterUri9 = filterUri6.buildUpon().appendQueryParameter( 3330 Contactables.VISIBLE_CONTACTS_ONLY, "true").build(); 3331 assertStoredValues(filterUri9, cv1, cv2, cv3, cv5, cv6); 3332 // mark Hot Tamale as invisible - cv1, cv2, and cv3 should no longer be in the cursor 3333 markInvisible(queryContactId(rawContactId)); 3334 assertStoredValues(filterUri9, cv5, cv6); 3335 } 3336 3337 testQueryContactData()3338 public void testQueryContactData() { 3339 ContentValues values = new ContentValues(); 3340 long contactId = createContact(values, "John", "Doe", 3341 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 3342 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO); 3343 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 3344 3345 values.put(Contacts.TIMES_CONTACTED, 0); 3346 assertStoredValues(contactUri, values); 3347 } 3348 testQueryContactWithStatusUpdate()3349 public void testQueryContactWithStatusUpdate() { 3350 ContentValues values = new ContentValues(); 3351 long contactId = createContact(values, "John", "Doe", 3352 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 3353 StatusUpdates.CAPABILITY_HAS_CAMERA); 3354 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 3355 values.put(Contacts.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 3356 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 3357 3358 values.put(Contacts.TIMES_CONTACTED, 0); 3359 3360 assertStoredValuesWithProjection(contactUri, values); 3361 } 3362 testQueryContactFilterByName()3363 public void testQueryContactFilterByName() { 3364 ContentValues values = new ContentValues(); 3365 long rawContactId = createRawContact(values, "18004664411", 3366 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 3367 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 3368 StatusUpdates.CAPABILITY_HAS_VOICE); 3369 3370 ContentValues nameValues = new ContentValues(); 3371 nameValues.put(StructuredName.GIVEN_NAME, "Stu"); 3372 nameValues.put(StructuredName.FAMILY_NAME, "Goulash"); 3373 nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "goo"); 3374 nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "LASH"); 3375 Uri nameUri = DataUtil.insertStructuredName(mResolver, rawContactId, nameValues); 3376 3377 long contactId = queryContactId(rawContactId); 3378 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 3379 3380 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goulash"); 3381 values.put(Contacts.TIMES_CONTACTED, 0); 3382 assertStoredValuesWithProjection(filterUri1, values); 3383 3384 assertContactFilter(contactId, "goolash"); 3385 assertContactFilter(contactId, "lash"); 3386 3387 assertContactFilterNoResult("goolish"); 3388 3389 // Phonetic name with given/family reversed should not match 3390 assertContactFilterNoResult("lashgoo"); 3391 3392 nameValues.clear(); 3393 nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "ga"); 3394 nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "losh"); 3395 3396 mResolver.update(nameUri, nameValues, null, null); 3397 3398 assertContactFilter(contactId, "galosh"); 3399 3400 assertContactFilterNoResult("goolish"); 3401 } 3402 testQueryContactFilterByEmailAddress()3403 public void testQueryContactFilterByEmailAddress() { 3404 ContentValues values = new ContentValues(); 3405 long rawContactId = createRawContact(values, "18004664411", 3406 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 3407 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 3408 StatusUpdates.CAPABILITY_HAS_VOICE); 3409 3410 DataUtil.insertStructuredName(mResolver, rawContactId, "James", "Bond"); 3411 3412 long contactId = queryContactId(rawContactId); 3413 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 3414 3415 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goog411@acme.com"); 3416 values.put(Contacts.TIMES_CONTACTED, 0); 3417 assertStoredValuesWithProjection(filterUri1, values); 3418 3419 assertContactFilter(contactId, "goog"); 3420 assertContactFilter(contactId, "goog411"); 3421 assertContactFilter(contactId, "goog411@"); 3422 assertContactFilter(contactId, "goog411@acme"); 3423 assertContactFilter(contactId, "goog411@acme.com"); 3424 3425 assertContactFilterNoResult("goog411@acme.combo"); 3426 assertContactFilterNoResult("goog411@le.com"); 3427 assertContactFilterNoResult("goolish"); 3428 } 3429 testQueryContactFilterByPhoneNumber()3430 public void testQueryContactFilterByPhoneNumber() { 3431 ContentValues values = new ContentValues(); 3432 long rawContactId = createRawContact(values, "18004664411", 3433 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 3434 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 3435 StatusUpdates.CAPABILITY_HAS_VOICE); 3436 3437 DataUtil.insertStructuredName(mResolver, rawContactId, "James", "Bond"); 3438 3439 long contactId = queryContactId(rawContactId); 3440 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 3441 3442 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "18004664411"); 3443 values.put(Contacts.TIMES_CONTACTED, 0); 3444 assertStoredValuesWithProjection(filterUri1, values); 3445 3446 assertContactFilter(contactId, "18004664411"); 3447 assertContactFilter(contactId, "1800466"); 3448 assertContactFilter(contactId, "+18004664411"); 3449 assertContactFilter(contactId, "8004664411"); 3450 3451 assertContactFilterNoResult("78004664411"); 3452 assertContactFilterNoResult("18004664412"); 3453 assertContactFilterNoResult("8884664411"); 3454 } 3455 3456 /** 3457 * Checks ContactsProvider2 works well with strequent Uris. The provider should return starred 3458 * contacts. 3459 */ testQueryContactStrequent()3460 public void testQueryContactStrequent() { 3461 ContentValues values1 = new ContentValues(); 3462 final String email1 = "a@acme.com"; 3463 final String phoneNumber1 = "18004664411"; 3464 final int timesContacted1 = 0; 3465 createContact(values1, "Noah", "Tever", phoneNumber1, 3466 email1, StatusUpdates.OFFLINE, timesContacted1, 0, 0, 3467 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO); 3468 final String phoneNumber2 = "18004664412"; 3469 ContentValues values2 = new ContentValues(); 3470 createContact(values2, "Sam", "Times", phoneNumber2, 3471 "b@acme.com", StatusUpdates.INVISIBLE, 3, 0, 0, 3472 StatusUpdates.CAPABILITY_HAS_CAMERA); 3473 ContentValues values3 = new ContentValues(); 3474 final String phoneNumber3 = "18004664413"; 3475 final int timesContacted3 = 9; 3476 createContact(values3, "Lotta", "Calling", phoneNumber3, 3477 "c@acme.com", StatusUpdates.AWAY, timesContacted3, 0, 0, 3478 StatusUpdates.CAPABILITY_HAS_VIDEO); 3479 ContentValues values4 = new ContentValues(); 3480 final long rawContactId4 = createRawContact(values4, "Fay", "Veritt", null, 3481 "d@acme.com", StatusUpdates.AVAILABLE, 0, 1, 0, 3482 StatusUpdates.CAPABILITY_HAS_VIDEO | StatusUpdates.CAPABILITY_HAS_VOICE); 3483 3484 // Starred contacts should be returned. TIMES_CONTACTED should be ignored and only data 3485 // usage feedback should be used for "frequently contacted" listing. 3486 assertStoredValues(Contacts.CONTENT_STREQUENT_URI, values4); 3487 3488 // Send feedback for the 3rd phone number, pretending we called that person via phone. 3489 sendFeedback(phoneNumber3, DataUsageFeedback.USAGE_TYPE_CALL, values3); 3490 3491 values3.put(Contacts.TIMES_CONTACTED, 0); 3492 3493 // After the feedback, 3rd contact should be shown after starred one. 3494 assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI, 3495 new ContentValues[] { values4 }); 3496 3497 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1); 3498 // Twice. 3499 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1); 3500 3501 // After the feedback, 1st and 3rd contacts should be shown after starred one. 3502 values1.put(Contacts.TIMES_CONTACTED, 0); 3503 assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI, 3504 new ContentValues[] { values4 }); 3505 3506 // With phone-only parameter, 1st and 4th contacts shouldn't be returned because: 3507 // 1st: feedbacks are only about email, not about phone call. 3508 // 4th: it has no phone number though starred. 3509 Uri phoneOnlyStrequentUri = Contacts.CONTENT_STREQUENT_URI.buildUpon() 3510 .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true") 3511 .build(); 3512 assertStoredValuesOrderly(phoneOnlyStrequentUri, new ContentValues[] { }); 3513 } 3514 testQueryContactStrequentFrequentOrder()3515 public void testQueryContactStrequentFrequentOrder() { 3516 // Prepare test data 3517 final long rid1 = RawContactUtil.createRawContact(mResolver); 3518 final long did1 = ContentUris.parseId(insertPhoneNumber(rid1, "1")); 3519 final long did1e = ContentUris.parseId(insertEmail(rid1, "1@email.com")); 3520 3521 final long rid2 = RawContactUtil.createRawContact(mResolver); 3522 final long did2 = ContentUris.parseId(insertPhoneNumber(rid2, "2")); 3523 3524 final long rid3 = RawContactUtil.createRawContact(mResolver); 3525 final long did3 = ContentUris.parseId(insertPhoneNumber(rid3, "3")); 3526 3527 final long rid4 = RawContactUtil.createRawContact(mResolver); 3528 final long did4 = ContentUris.parseId(insertPhoneNumber(rid4, "4")); 3529 3530 final long rid5 = RawContactUtil.createRawContact(mResolver); 3531 final long did5 = ContentUris.parseId(insertPhoneNumber(rid5, "5")); 3532 3533 final long rid6 = RawContactUtil.createRawContact(mResolver); 3534 final long did6 = ContentUris.parseId(insertPhoneNumber(rid6, "6")); 3535 3536 final long rid7 = RawContactUtil.createRawContact(mResolver); 3537 final long did7 = ContentUris.parseId(insertPhoneNumber(rid7, "7")); 3538 3539 final long rid8 = RawContactUtil.createRawContact(mResolver); 3540 final long did8 = ContentUris.parseId(insertPhoneNumber(rid8, "8")); 3541 3542 final long cid1 = queryContactId(rid1); 3543 final long cid2 = queryContactId(rid2); 3544 final long cid3 = queryContactId(rid3); 3545 final long cid4 = queryContactId(rid4); 3546 final long cid5 = queryContactId(rid5); 3547 final long cid6 = queryContactId(rid6); 3548 final long cid7 = queryContactId(rid7); 3549 final long cid8 = queryContactId(rid8); 3550 3551 // Make sure they aren't aggregated. 3552 EvenMoreAsserts.assertUnique(cid1, cid2, cid3, cid4, cid5, cid6, cid7, cid8); 3553 3554 // Prepare the clock 3555 sMockClock.install(); 3556 3557 // We check the timestamp in SQL, which doesn't know about the MockClock. So we need to 3558 // use the actual (roughly) time. 3559 3560 final long nowInMillis = System.currentTimeMillis(); 3561 final long oneDayAgoInMillis = (nowInMillis - 24L * 60 * 60 * 1000); 3562 final long fourDaysAgoInMillis = (nowInMillis - 4L * 24 * 60 * 60 * 1000); 3563 final long eightDaysAgoInMillis = (nowInMillis - 8L * 24 * 60 * 60 * 1000); 3564 final long fifteenDaysAgoInMillis = (nowInMillis - 15L * 24 * 60 * 60 * 1000); 3565 // All contacts older than 30 days will not be included in frequents 3566 final long thirtyOneDaysAgoInMillis = (nowInMillis - 31L * 24 * 60 * 60 * 1000); 3567 3568 // Contacts in this bucket are considered more than 30 days old 3569 sMockClock.setCurrentTimeMillis(thirtyOneDaysAgoInMillis); 3570 3571 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did1, did2); 3572 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did1); 3573 3574 // Contacts in this bucket are considered more than 14 days old 3575 sMockClock.setCurrentTimeMillis(fifteenDaysAgoInMillis); 3576 3577 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did3, did4); 3578 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did3); 3579 3580 // Contacts in this bucket are considered more than 7 days old 3581 sMockClock.setCurrentTimeMillis(eightDaysAgoInMillis); 3582 3583 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did5, did6); 3584 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did5); 3585 3586 // Contact cid1 again, but it's an email, not a phone call. 3587 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, did1e); 3588 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, did1e); 3589 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, did1e); 3590 3591 // Contacts in this bucket are considered more than 3 days old 3592 sMockClock.setCurrentTimeMillis(fourDaysAgoInMillis); 3593 3594 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did7); 3595 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did7); 3596 3597 3598 // Contacts in this bucket are considered less than 3 days old 3599 sMockClock.setCurrentTimeMillis(oneDayAgoInMillis); 3600 3601 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did8); 3602 3603 sMockClock.setCurrentTimeMillis(nowInMillis); 3604 3605 // Check the order -- The regular frequent, which is contact based. 3606 // Note because we contacted cid1 8 days ago, it's been contacted 3 times, so it comes 3607 // before cid5 and cid6, which were contacted at the same time. 3608 // cid2 will not show up because it was contacted more than 30 days ago 3609 3610 assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI); 3611 3612 // Check the order -- phone only frequent, which is data based. 3613 // Note this is based on data, and only looks at phone numbers, so the order is different 3614 // now. 3615 // did1, did2 will not show up because they were used to make calls more than 30 days ago. 3616 assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI.buildUpon() 3617 .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "1").build()); 3618 } 3619 3620 /** 3621 * Checks ContactsProvider2 works well with frequent Uri. The provider should return frequently 3622 * contacted person ordered by number of times contacted. 3623 */ testQueryContactFrequent()3624 public void testQueryContactFrequent() { 3625 ContentValues values1 = new ContentValues(); 3626 final String email1 = "a@acme.com"; 3627 createContact(values1, "Noah", "Tever", "18004664411", 3628 email1, StatusUpdates.OFFLINE, 0, 0, 0, 0); 3629 ContentValues values2 = new ContentValues(); 3630 final String email2 = "b@acme.com"; 3631 createContact(values2, "Sam", "Times", "18004664412", 3632 email2, StatusUpdates.INVISIBLE, 0, 0, 0, 0); 3633 ContentValues values3 = new ContentValues(); 3634 final String phoneNumber3 = "18004664413"; 3635 final long contactId3 = createContact(values3, "Lotta", "Calling", phoneNumber3, 3636 "c@acme.com", StatusUpdates.AWAY, 0, 1, 0, 0); 3637 ContentValues values4 = new ContentValues(); 3638 createContact(values4, "Fay", "Veritt", "18004664414", 3639 "d@acme.com", StatusUpdates.AVAILABLE, 0, 1, 0, 0); 3640 3641 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1); 3642 3643 assertStoredValues(Contacts.CONTENT_FREQUENT_URI); 3644 3645 // Pretend email was sent to the address twice. 3646 sendFeedback(email2, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values2); 3647 sendFeedback(email2, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values2); 3648 3649 values1.put(Contacts.TIMES_CONTACTED, 0); 3650 values2.put(Contacts.TIMES_CONTACTED, 0); 3651 assertStoredValues(Contacts.CONTENT_FREQUENT_URI); 3652 3653 for (int i = 0; i < 10; i++) { 3654 sendFeedback(phoneNumber3, DataUsageFeedback.USAGE_TYPE_CALL, values3); 3655 } 3656 3657 values3.put(Contacts.TIMES_CONTACTED, 0); 3658 3659 assertStoredValues(Contacts.CONTENT_FREQUENT_URI); 3660 3661 3662 // Test it works with selection/selectionArgs 3663 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, 3664 Contacts.STARRED + "=?", new String[] {"0"} 3665 ); 3666 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, 3667 Contacts.STARRED + "=?", new String[] {"1"} 3668 ); 3669 3670 values3.put(Contacts.STARRED, 0); 3671 assertEquals(1, 3672 mResolver.update(Uri.withAppendedPath(Contacts.CONTENT_URI, 3673 String.valueOf(contactId3)), 3674 values3, null, null)); 3675 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, 3676 Contacts.STARRED + "=?", new String[] {"0"} 3677 ); 3678 assertStoredValues(Contacts.CONTENT_FREQUENT_URI, 3679 Contacts.STARRED + "=?", new String[] {"1"} 3680 ); 3681 } 3682 testQueryContactFrequentExcludingInvisible()3683 public void testQueryContactFrequentExcludingInvisible() { 3684 ContentValues values1 = new ContentValues(); 3685 final String email1 = "a@acme.com"; 3686 final long cid1 = createContact(values1, "Noah", "Tever", "18004664411", 3687 email1, StatusUpdates.OFFLINE, 0, 0, 0, 0); 3688 ContentValues values2 = new ContentValues(); 3689 final String email2 = "b@acme.com"; 3690 final long cid2 = createContact(values2, "Sam", "Times", "18004664412", 3691 email2, StatusUpdates.INVISIBLE, 0, 0, 0, 0); 3692 3693 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1); 3694 sendFeedback(email2, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values2); 3695 3696 // First, we have two contacts in frequent. 3697 assertStoredValues(Contacts.CONTENT_FREQUENT_URI); 3698 3699 // Contact 2 goes invisible. 3700 markInvisible(cid2); 3701 3702 // Now we have only 1 frequent. 3703 assertStoredValues(Contacts.CONTENT_FREQUENT_URI); 3704 3705 } 3706 testQueryDataUsageStat()3707 public void testQueryDataUsageStat() { 3708 // Now all data usage stats are zero as of Q. 3709 3710 ContentValues values1 = new ContentValues(); 3711 final String email1 = "a@acme.com"; 3712 final long cid1 = createContact(values1, "Noah", "Tever", "18004664411", 3713 email1, StatusUpdates.OFFLINE, 0, 0, 0, 0); 3714 3715 sMockClock.install(); 3716 sMockClock.setCurrentTimeMillis(100); 3717 3718 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1); 3719 3720 assertDataUsageZero(Data.CONTENT_URI, "a@acme.com"); 3721 3722 sMockClock.setCurrentTimeMillis(86400 + 123); 3723 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1); 3724 3725 assertDataUsageZero(Data.CONTENT_URI, "a@acme.com"); 3726 3727 sMockClock.setCurrentTimeMillis(86400 * 3 + 123); 3728 for (int i = 0; i < 11; i++) { 3729 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, values1); 3730 } 3731 3732 assertDataUsageZero(Data.CONTENT_URI, "a@acme.com"); 3733 3734 final Uri dataUriWithUsageTypeLongText = Data.CONTENT_URI.buildUpon().appendQueryParameter( 3735 DataUsageFeedback.USAGE_TYPE, DataUsageFeedback.USAGE_TYPE_LONG_TEXT).build(); 3736 3737 assertDataUsageZero(dataUriWithUsageTypeLongText, "a@acme.com"); 3738 3739 sMockClock.setCurrentTimeMillis(86400 * 4 + 123); 3740 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_CALL, values1); 3741 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_CALL, values1); 3742 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_CALL, values1); 3743 3744 assertDataUsageZero(Data.CONTENT_URI, "a@acme.com"); 3745 3746 sMockClock.setCurrentTimeMillis(86400 * 5 + 123); 3747 for (int i = 0; i < 10; i++) { 3748 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_CALL, values1); 3749 } 3750 assertDataUsageZero(Data.CONTENT_URI, "a@acme.com"); 3751 3752 sMockClock.setCurrentTimeMillis(86400 * 6 + 123); 3753 for (int i = 0; i < 10; i++) { 3754 sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_CALL, values1); 3755 } 3756 assertDataUsageZero(Data.CONTENT_URI, "a@acme.com"); 3757 3758 final Uri dataUriWithUsageTypeCall = Data.CONTENT_URI.buildUpon().appendQueryParameter( 3759 DataUsageFeedback.USAGE_TYPE, DataUsageFeedback.USAGE_TYPE_CALL).build(); 3760 3761 assertDataUsageZero(dataUriWithUsageTypeCall, "a@acme.com"); 3762 } 3763 testQueryContactGroup()3764 public void testQueryContactGroup() { 3765 long groupId = createGroup(null, "testGroup", "Test Group"); 3766 3767 ContentValues values1 = new ContentValues(); 3768 createContact(values1, "Best", "West", "18004664411", 3769 "west@acme.com", StatusUpdates.OFFLINE, 0, 0, groupId, 3770 StatusUpdates.CAPABILITY_HAS_CAMERA); 3771 3772 ContentValues values2 = new ContentValues(); 3773 createContact(values2, "Rest", "East", "18004664422", 3774 "east@acme.com", StatusUpdates.AVAILABLE, 0, 0, 0, 3775 StatusUpdates.CAPABILITY_HAS_VOICE); 3776 3777 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group"); 3778 Cursor c = mResolver.query(filterUri1, null, null, null, Contacts._ID); 3779 assertEquals(1, c.getCount()); 3780 c.moveToFirst(); 3781 dumpCursor(c); 3782 assertCursorValues(c, values1); 3783 c.close(); 3784 3785 Uri filterUri2 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group"); 3786 c = mResolver.query(filterUri2, null, Contacts.DISPLAY_NAME + "=?", 3787 new String[] { "Best West" }, Contacts._ID); 3788 assertEquals(1, c.getCount()); 3789 c.close(); 3790 3791 Uri filterUri3 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Next Group"); 3792 c = mResolver.query(filterUri3, null, null, null, Contacts._ID); 3793 assertEquals(0, c.getCount()); 3794 c.close(); 3795 } 3796 expectNoSecurityException(String failureMessage, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)3797 private void expectNoSecurityException(String failureMessage, Uri uri, String[] projection, 3798 String selection, String[] selectionArgs, String sortOrder) { 3799 Cursor c = null; 3800 try { 3801 c = mResolver.query(uri, projection, selection, selectionArgs, sortOrder); 3802 } catch (SecurityException expected) { 3803 fail(failureMessage); 3804 } finally { 3805 if (c != null) { 3806 c.close(); 3807 } 3808 } 3809 } 3810 expectSecurityException(String failureMessage, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)3811 private void expectSecurityException(String failureMessage, Uri uri, String[] projection, 3812 String selection, String[] selectionArgs, String sortOrder) { 3813 Cursor c = null; 3814 try { 3815 c = mResolver.query(uri, projection, selection, selectionArgs, sortOrder); 3816 fail(failureMessage); 3817 } catch (SecurityException expected) { 3818 // The security exception is expected to occur because we're missing a permission. 3819 } finally { 3820 if (c != null) { 3821 c.close(); 3822 } 3823 } 3824 } 3825 testQueryProfileWithoutPermission()3826 public void testQueryProfileWithoutPermission() { 3827 createBasicProfileContact(new ContentValues()); 3828 3829 // Case 1: Retrieving profile contact. 3830 expectNoSecurityException( 3831 "Querying for the profile without READ_PROFILE access should succeed.", 3832 Profile.CONTENT_URI, null, null, null, Contacts._ID); 3833 3834 // Case 2: Retrieving profile data. 3835 expectNoSecurityException( 3836 "Querying for the profile data without READ_PROFILE access should succeed.", 3837 Profile.CONTENT_URI.buildUpon().appendPath("data").build(), 3838 null, null, null, Contacts._ID); 3839 3840 // Case 3: Retrieving profile entities. 3841 expectNoSecurityException( 3842 "Querying for the profile entities without READ_PROFILE access should succeed.", 3843 Profile.CONTENT_URI.buildUpon() 3844 .appendPath("entities").build(), null, null, null, Contacts._ID); 3845 } 3846 testQueryProfileByContactIdWithoutReadPermission()3847 public void testQueryProfileByContactIdWithoutReadPermission() { 3848 long profileRawContactId = createBasicProfileContact(new ContentValues()); 3849 long profileContactId = queryContactId(profileRawContactId); 3850 3851 // A query for the profile contact by ID should not require READ_PROFILE. 3852 expectNoSecurityException( 3853 "Querying for the profile by contact ID without READ_PROFILE access should succeed", 3854 ContentUris.withAppendedId(Contacts.CONTENT_URI, profileContactId), 3855 null, null, null, Contacts._ID); 3856 } 3857 testQueryProfileByRawContactIdWithoutReadPermission()3858 public void testQueryProfileByRawContactIdWithoutReadPermission() { 3859 long profileRawContactId = createBasicProfileContact(new ContentValues()); 3860 3861 expectNoSecurityException( 3862 "Querying for the raw contact profile without READ_PROFILE access should succeed.", 3863 ContentUris.withAppendedId(RawContacts.CONTENT_URI, 3864 profileRawContactId), null, null, null, RawContacts._ID); 3865 } 3866 testQueryProfileRawContactWithoutReadPermission()3867 public void testQueryProfileRawContactWithoutReadPermission() { 3868 long profileRawContactId = createBasicProfileContact(new ContentValues()); 3869 3870 // Case 1: Retrieve the overall raw contact set for the profile. 3871 expectNoSecurityException( 3872 "Querying for the raw contact profile without READ_PROFILE access should succeed.", 3873 Profile.CONTENT_RAW_CONTACTS_URI, null, null, null, null); 3874 3875 // Case 2: Retrieve the raw contact profile data for the inserted raw contact ID. 3876 expectNoSecurityException( 3877 "Querying for the raw profile data without READ_PROFILE access should succeed.", 3878 ContentUris.withAppendedId( 3879 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId).buildUpon() 3880 .appendPath("data").build(), null, null, null, null); 3881 3882 // Case 3: Retrieve the raw contact profile entity for the inserted raw contact ID. 3883 expectNoSecurityException( 3884 "Querying for the raw profile entities without READ_PROFILE access should succeed.", 3885 ContentUris.withAppendedId( 3886 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId).buildUpon() 3887 .appendPath("entity").build(), null, null, null, null); 3888 } 3889 testQueryProfileDataByDataIdWithoutReadPermission()3890 public void testQueryProfileDataByDataIdWithoutReadPermission() { 3891 createBasicProfileContact(new ContentValues()); 3892 Cursor c = mResolver.query(Profile.CONTENT_URI.buildUpon().appendPath("data").build(), 3893 new String[]{Data._ID, Data.MIMETYPE}, null, null, null); 3894 assertEquals(4, c.getCount()); // Photo, phone, email, name. 3895 c.moveToFirst(); 3896 long profileDataId = c.getLong(0); 3897 c.close(); 3898 3899 expectNoSecurityException( 3900 "Querying for the data in the profile without READ_PROFILE access should succeed.", 3901 ContentUris.withAppendedId(Data.CONTENT_URI, profileDataId), 3902 null, null, null, null); 3903 } 3904 testQueryProfileDataWithoutReadPermission()3905 public void testQueryProfileDataWithoutReadPermission() { 3906 createBasicProfileContact(new ContentValues()); 3907 3908 expectNoSecurityException( 3909 "Querying for the data in the profile without READ_PROFILE access should succeed.", 3910 Profile.CONTENT_URI.buildUpon().appendPath("data").build(), 3911 null, null, null, null); 3912 } 3913 testInsertProfileWithoutWritePermission()3914 public void testInsertProfileWithoutWritePermission() { 3915 // Creating a non-profile contact should be fine. 3916 createBasicNonProfileContact(new ContentValues()); 3917 3918 try { 3919 createBasicProfileContact(new ContentValues()); 3920 } catch (SecurityException expected) { 3921 fail("Creating a profile contact should not require WRITE_PROFILE access."); 3922 } 3923 } 3924 testInsertProfileDataWithoutWritePermission()3925 public void testInsertProfileDataWithoutWritePermission() { 3926 long profileRawContactId = createBasicProfileContact(new ContentValues()); 3927 3928 try { 3929 insertEmail(profileRawContactId, "foo@bar.net", false); 3930 } catch (SecurityException expected) { 3931 fail("Inserting data into a profile contact should not require WRITE_PROFILE access."); 3932 } 3933 } 3934 testUpdateDataDoesNotRequireProfilePermission()3935 public void testUpdateDataDoesNotRequireProfilePermission() { 3936 // Create a non-profile contact. 3937 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "Domo", "Arigato"); 3938 long dataId = getStoredLongValue(Data.CONTENT_URI, 3939 Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?", 3940 new String[]{String.valueOf(rawContactId), StructuredName.CONTENT_ITEM_TYPE}, 3941 Data._ID); 3942 3943 // Updates its name using a selection. 3944 ContentValues values = new ContentValues(); 3945 values.put(StructuredName.GIVEN_NAME, "Bob"); 3946 values.put(StructuredName.FAMILY_NAME, "Blob"); 3947 mResolver.update(Data.CONTENT_URI, values, Data._ID + "=?", 3948 new String[]{String.valueOf(dataId)}); 3949 3950 // Check that the update went through. 3951 assertStoredValues(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), values); 3952 } 3953 testQueryContactThenProfile()3954 public void testQueryContactThenProfile() { 3955 ContentValues profileValues = new ContentValues(); 3956 long profileRawContactId = createBasicProfileContact(profileValues); 3957 long profileContactId = queryContactId(profileRawContactId); 3958 3959 ContentValues nonProfileValues = new ContentValues(); 3960 long nonProfileRawContactId = createBasicNonProfileContact(nonProfileValues); 3961 long nonProfileContactId = queryContactId(nonProfileRawContactId); 3962 3963 nonProfileValues.put(Contacts.TIMES_CONTACTED, 0); 3964 profileValues.put(Contacts.TIMES_CONTACTED, 0); 3965 3966 assertStoredValues(Contacts.CONTENT_URI, nonProfileValues); 3967 3968 assertStoredValues(Profile.CONTENT_URI, profileValues); 3969 } 3970 testQueryContactExcludeProfile()3971 public void testQueryContactExcludeProfile() { 3972 // Create a profile contact (it should not be returned by the general contact URI). 3973 createBasicProfileContact(new ContentValues()); 3974 3975 // Create a non-profile contact - this should be returned. 3976 ContentValues nonProfileValues = new ContentValues(); 3977 createBasicNonProfileContact(nonProfileValues); 3978 nonProfileValues.put(Contacts.TIMES_CONTACTED, 0); 3979 assertStoredValues(Contacts.CONTENT_URI, new ContentValues[] {nonProfileValues}); 3980 } 3981 testQueryProfile()3982 public void testQueryProfile() { 3983 ContentValues profileValues = new ContentValues(); 3984 createBasicProfileContact(profileValues); 3985 3986 profileValues.put(Contacts.TIMES_CONTACTED, 0); 3987 assertStoredValues(Profile.CONTENT_URI, profileValues); 3988 } 3989 getExpectedProfileDataValues()3990 private ContentValues[] getExpectedProfileDataValues() { 3991 // Expected photo data values (only field is the photo BLOB, which we can't check). 3992 ContentValues photoRow = new ContentValues(); 3993 photoRow.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 3994 3995 // Expected phone data values. 3996 ContentValues phoneRow = new ContentValues(); 3997 phoneRow.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 3998 phoneRow.put(Phone.NUMBER, "18005554411"); 3999 4000 // Expected email data values. 4001 ContentValues emailRow = new ContentValues(); 4002 emailRow.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 4003 emailRow.put(Email.ADDRESS, "mia.prophyl@acme.com"); 4004 4005 // Expected name data values. 4006 ContentValues nameRow = new ContentValues(); 4007 nameRow.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 4008 nameRow.put(StructuredName.DISPLAY_NAME, "Mia Prophyl"); 4009 nameRow.put(StructuredName.GIVEN_NAME, "Mia"); 4010 nameRow.put(StructuredName.FAMILY_NAME, "Prophyl"); 4011 4012 return new ContentValues[]{photoRow, phoneRow, emailRow, nameRow}; 4013 } 4014 testQueryProfileData()4015 public void testQueryProfileData() { 4016 createBasicProfileContact(new ContentValues()); 4017 4018 assertStoredValues(Profile.CONTENT_URI.buildUpon().appendPath("data").build(), 4019 getExpectedProfileDataValues()); 4020 } 4021 testQueryProfileEntities()4022 public void testQueryProfileEntities() { 4023 createBasicProfileContact(new ContentValues()); 4024 4025 assertStoredValues(Profile.CONTENT_URI.buildUpon().appendPath("entities").build(), 4026 getExpectedProfileDataValues()); 4027 } 4028 testQueryRawProfile()4029 public void testQueryRawProfile() { 4030 ContentValues profileValues = new ContentValues(); 4031 createBasicProfileContact(profileValues); 4032 4033 // The raw contact view doesn't include the photo ID. 4034 profileValues.remove(Contacts.PHOTO_ID); 4035 profileValues.put(Contacts.TIMES_CONTACTED, 0); 4036 assertStoredValues(Profile.CONTENT_RAW_CONTACTS_URI, profileValues); 4037 } 4038 testQueryRawProfileById()4039 public void testQueryRawProfileById() { 4040 ContentValues profileValues = new ContentValues(); 4041 long profileRawContactId = createBasicProfileContact(profileValues); 4042 4043 // The raw contact view doesn't include the photo ID. 4044 profileValues.remove(Contacts.PHOTO_ID); 4045 profileValues.put(Contacts.TIMES_CONTACTED, 0); 4046 assertStoredValues(ContentUris.withAppendedId( 4047 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId), profileValues); 4048 } 4049 testQueryRawProfileData()4050 public void testQueryRawProfileData() { 4051 long profileRawContactId = createBasicProfileContact(new ContentValues()); 4052 4053 assertStoredValues(ContentUris.withAppendedId( 4054 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId).buildUpon() 4055 .appendPath("data").build(), getExpectedProfileDataValues()); 4056 } 4057 testQueryRawProfileEntity()4058 public void testQueryRawProfileEntity() { 4059 long profileRawContactId = createBasicProfileContact(new ContentValues()); 4060 4061 assertStoredValues(ContentUris.withAppendedId( 4062 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId).buildUpon() 4063 .appendPath("entity").build(), getExpectedProfileDataValues()); 4064 } 4065 testQueryDataForProfile()4066 public void testQueryDataForProfile() { 4067 createBasicProfileContact(new ContentValues()); 4068 4069 assertStoredValues(Profile.CONTENT_URI.buildUpon().appendPath("data").build(), 4070 getExpectedProfileDataValues()); 4071 } 4072 testUpdateProfileRawContact()4073 public void testUpdateProfileRawContact() { 4074 createBasicProfileContact(new ContentValues()); 4075 ContentValues updatedValues = new ContentValues(); 4076 updatedValues.put(RawContacts.SEND_TO_VOICEMAIL, 0); 4077 updatedValues.put(RawContacts.CUSTOM_RINGTONE, "rachmaninoff3"); 4078 updatedValues.put(RawContacts.STARRED, 1); 4079 mResolver.update(Profile.CONTENT_RAW_CONTACTS_URI, updatedValues, null, null); 4080 4081 assertStoredValues(Profile.CONTENT_RAW_CONTACTS_URI, updatedValues); 4082 } 4083 testInsertProfileWithDataSetTriggersAccountCreation()4084 public void testInsertProfileWithDataSetTriggersAccountCreation() { 4085 // Check that we have no profile raw contacts. 4086 assertStoredValues(Profile.CONTENT_RAW_CONTACTS_URI, new ContentValues[]{}); 4087 4088 // Insert a profile record with a new data set. 4089 Account account = new Account("a", "b"); 4090 String dataSet = "c"; 4091 Uri profileUri = TestUtil.maybeAddAccountQueryParameters(Profile.CONTENT_RAW_CONTACTS_URI, 4092 account) 4093 .buildUpon().appendQueryParameter(RawContacts.DATA_SET, dataSet).build(); 4094 ContentValues values = new ContentValues(); 4095 long rawContactId = ContentUris.parseId(mResolver.insert(profileUri, values)); 4096 values.put(RawContacts._ID, rawContactId); 4097 4098 // Check that querying for the profile gets the created raw contact. 4099 assertStoredValues(Profile.CONTENT_RAW_CONTACTS_URI, values); 4100 } 4101 testLoadProfilePhoto()4102 public void testLoadProfilePhoto() throws IOException { 4103 long rawContactId = createBasicProfileContact(new ContentValues()); 4104 insertPhoto(rawContactId, R.drawable.earth_normal); 4105 EvenMoreAsserts.assertImageRawData(getContext(), 4106 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.THUMBNAIL), 4107 Contacts.openContactPhotoInputStream(mResolver, Profile.CONTENT_URI, false)); 4108 } 4109 testLoadProfileDisplayPhoto()4110 public void testLoadProfileDisplayPhoto() throws IOException { 4111 long rawContactId = createBasicProfileContact(new ContentValues()); 4112 insertPhoto(rawContactId, R.drawable.earth_normal); 4113 EvenMoreAsserts.assertImageRawData(getContext(), 4114 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 4115 Contacts.openContactPhotoInputStream(mResolver, Profile.CONTENT_URI, true)); 4116 } 4117 testPhonesWithStatusUpdate()4118 public void testPhonesWithStatusUpdate() { 4119 4120 ContentValues values = new ContentValues(); 4121 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 4122 long rawContactId = ContentUris.parseId(rawContactUri); 4123 DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe"); 4124 Uri photoUri = insertPhoto(rawContactId); 4125 long photoId = ContentUris.parseId(photoUri); 4126 insertPhoneNumber(rawContactId, "18004664411"); 4127 insertPhoneNumber(rawContactId, "18004664412"); 4128 insertEmail(rawContactId, "goog411@acme.com"); 4129 insertEmail(rawContactId, "goog412@acme.com"); 4130 4131 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog411@acme.com", 4132 StatusUpdates.INVISIBLE, "Bad", 4133 StatusUpdates.CAPABILITY_HAS_CAMERA); 4134 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog412@acme.com", 4135 StatusUpdates.AVAILABLE, "Good", 4136 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VOICE); 4137 long contactId = queryContactId(rawContactId); 4138 4139 Uri uri = Data.CONTENT_URI; 4140 4141 Cursor c = mResolver.query(uri, null, RawContacts.CONTACT_ID + "=" + contactId + " AND " 4142 + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'", null, Phone.NUMBER); 4143 assertEquals(2, c.getCount()); 4144 4145 c.moveToFirst(); 4146 4147 values.clear(); 4148 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 4149 values.put(Contacts.CONTACT_STATUS, "Bad"); 4150 values.put(Contacts.DISPLAY_NAME, "John Doe"); 4151 values.put(Phone.NUMBER, "18004664411"); 4152 values.putNull(Phone.LABEL); 4153 values.put(RawContacts.CONTACT_ID, contactId); 4154 assertCursorValues(c, values); 4155 4156 c.moveToNext(); 4157 4158 values.clear(); 4159 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 4160 values.put(Contacts.CONTACT_STATUS, "Bad"); 4161 values.put(Contacts.DISPLAY_NAME, "John Doe"); 4162 values.put(Phone.NUMBER, "18004664412"); 4163 values.putNull(Phone.LABEL); 4164 values.put(RawContacts.CONTACT_ID, contactId); 4165 assertCursorValues(c, values); 4166 4167 c.close(); 4168 } 4169 testGroupQuery()4170 public void testGroupQuery() { 4171 Account account1 = new Account("a", "b"); 4172 Account account2 = new Account("c", "d"); 4173 long groupId1 = createGroup(account1, "e", "f"); 4174 long groupId2 = createGroup(account2, "g", "h"); 4175 Uri uri1 = TestUtil.maybeAddAccountQueryParameters(Groups.CONTENT_URI, account1); 4176 Uri uri2 = TestUtil.maybeAddAccountQueryParameters(Groups.CONTENT_URI, account2); 4177 assertEquals(1, getCount(uri1, null, null)); 4178 assertEquals(1, getCount(uri2, null, null)); 4179 assertStoredValue(uri1, Groups._ID + "=" + groupId1, null, Groups._ID, groupId1) ; 4180 assertStoredValue(uri2, Groups._ID + "=" + groupId2, null, Groups._ID, groupId2) ; 4181 } 4182 testGroupInsert()4183 public void testGroupInsert() { 4184 ContentValues values = new ContentValues(); 4185 4186 values.put(Groups.ACCOUNT_NAME, "a"); 4187 values.put(Groups.ACCOUNT_TYPE, "b"); 4188 values.put(Groups.DATA_SET, "ds"); 4189 values.put(Groups.SOURCE_ID, "c"); 4190 values.put(Groups.VERSION, 42); 4191 values.put(Groups.GROUP_VISIBLE, 1); 4192 values.put(Groups.TITLE, "d"); 4193 values.put(Groups.TITLE_RES, 1234); 4194 values.put(Groups.NOTES, "e"); 4195 values.put(Groups.RES_PACKAGE, "f"); 4196 values.put(Groups.SYSTEM_ID, "g"); 4197 values.put(Groups.DELETED, 1); 4198 values.put(Groups.SYNC1, "h"); 4199 values.put(Groups.SYNC2, "i"); 4200 values.put(Groups.SYNC3, "j"); 4201 values.put(Groups.SYNC4, "k"); 4202 4203 Uri rowUri = mResolver.insert(Groups.CONTENT_URI, values); 4204 4205 values.put(Groups.DIRTY, 1); 4206 assertStoredValues(rowUri, values); 4207 } 4208 testGroupCreationAfterMembershipInsert()4209 public void testGroupCreationAfterMembershipInsert() { 4210 long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount); 4211 Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1"); 4212 4213 long groupId = assertSingleGroup(NO_LONG, mAccount, "gsid1", null); 4214 assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri), 4215 rawContactId1, groupId, "gsid1"); 4216 } 4217 testGroupReuseAfterMembershipInsert()4218 public void testGroupReuseAfterMembershipInsert() { 4219 long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount); 4220 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 4221 Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1"); 4222 4223 assertSingleGroup(groupId1, mAccount, "gsid1", "title1"); 4224 assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri), 4225 rawContactId1, groupId1, "gsid1"); 4226 } 4227 testGroupInsertFailureOnGroupIdConflict()4228 public void testGroupInsertFailureOnGroupIdConflict() { 4229 long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount); 4230 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 4231 4232 ContentValues values = new ContentValues(); 4233 values.put(GroupMembership.RAW_CONTACT_ID, rawContactId1); 4234 values.put(GroupMembership.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE); 4235 values.put(GroupMembership.GROUP_SOURCE_ID, "gsid1"); 4236 values.put(GroupMembership.GROUP_ROW_ID, groupId1); 4237 try { 4238 mResolver.insert(Data.CONTENT_URI, values); 4239 fail("the insert was expected to fail, but it succeeded"); 4240 } catch (IllegalArgumentException e) { 4241 // this was expected 4242 } 4243 } 4244 testGroupDelete_byAccountSelection()4245 public void testGroupDelete_byAccountSelection() { 4246 final Account account1 = new Account("accountName1", "accountType1"); 4247 final Account account2 = new Account("accountName2", "accountType2"); 4248 4249 final long groupId1 = createGroup(account1, "sourceId1", "title1"); 4250 final long groupId2 = createGroup(account2, "sourceId2", "title2"); 4251 final long groupId3 = createGroup(account2, "sourceId3", "title3"); 4252 4253 final int numDeleted = mResolver.delete(Groups.CONTENT_URI, 4254 Groups.ACCOUNT_NAME + "=? AND " + Groups.ACCOUNT_TYPE + "=?", 4255 new String[]{account2.name, account2.type}); 4256 assertEquals(2, numDeleted); 4257 4258 ContentValues v1 = new ContentValues(); 4259 v1.put(Groups._ID, groupId1); 4260 v1.put(Groups.DELETED, 0); 4261 4262 ContentValues v2 = new ContentValues(); 4263 v2.put(Groups._ID, groupId2); 4264 v2.put(Groups.DELETED, 1); 4265 4266 ContentValues v3 = new ContentValues(); 4267 v3.put(Groups._ID, groupId3); 4268 v3.put(Groups.DELETED, 1); 4269 4270 assertStoredValues(Groups.CONTENT_URI, new ContentValues[] { v1, v2, v3 }); 4271 } 4272 testGroupDelete_byAccountParam()4273 public void testGroupDelete_byAccountParam() { 4274 final Account account1 = new Account("accountName1", "accountType1"); 4275 final Account account2 = new Account("accountName2", "accountType2"); 4276 4277 final long groupId1 = createGroup(account1, "sourceId1", "title1"); 4278 final long groupId2 = createGroup(account2, "sourceId2", "title2"); 4279 final long groupId3 = createGroup(account2, "sourceId3", "title3"); 4280 4281 final int numDeleted = mResolver.delete( 4282 Groups.CONTENT_URI.buildUpon() 4283 .appendQueryParameter(Groups.ACCOUNT_NAME, account2.name) 4284 .appendQueryParameter(Groups.ACCOUNT_TYPE, account2.type) 4285 .build(), 4286 null, null); 4287 assertEquals(2, numDeleted); 4288 4289 ContentValues v1 = new ContentValues(); 4290 v1.put(Groups._ID, groupId1); 4291 v1.put(Groups.DELETED, 0); 4292 4293 ContentValues v2 = new ContentValues(); 4294 v2.put(Groups._ID, groupId2); 4295 v2.put(Groups.DELETED, 1); 4296 4297 ContentValues v3 = new ContentValues(); 4298 v3.put(Groups._ID, groupId3); 4299 v3.put(Groups.DELETED, 1); 4300 4301 assertStoredValues(Groups.CONTENT_URI, new ContentValues[] { v1, v2, v3 }); 4302 } 4303 testGroupSummaryQuery()4304 public void testGroupSummaryQuery() { 4305 final Account account1 = new Account("accountName1", "accountType1"); 4306 final Account account2 = new Account("accountName2", "accountType2"); 4307 final long groupId1 = createGroup(account1, "sourceId1", "title1"); 4308 final long groupId2 = createGroup(account2, "sourceId2", "title2"); 4309 final long groupId3 = createGroup(account2, "sourceId3", "title3"); 4310 4311 // Prepare raw contact id not used at all, to test group summary uri won't be confused 4312 // with it. 4313 final long rawContactId0 = RawContactUtil.createRawContactWithName(mResolver, "firstName0", 4314 "lastName0"); 4315 4316 final long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "firstName1", 4317 "lastName1"); 4318 insertEmail(rawContactId1, "address1@email.com"); 4319 insertGroupMembership(rawContactId1, groupId1); 4320 4321 final long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "firstName2", 4322 "lastName2"); 4323 insertEmail(rawContactId2, "address2@email.com"); 4324 insertPhoneNumber(rawContactId2, "222-222-2222"); 4325 insertGroupMembership(rawContactId2, groupId1); 4326 4327 ContentValues v1 = new ContentValues(); 4328 v1.put(Groups._ID, groupId1); 4329 v1.put(Groups.TITLE, "title1"); 4330 v1.put(Groups.SOURCE_ID, "sourceId1"); 4331 v1.put(Groups.ACCOUNT_NAME, account1.name); 4332 v1.put(Groups.ACCOUNT_TYPE, account1.type); 4333 v1.put(Groups.SUMMARY_COUNT, 2); 4334 v1.put(Groups.SUMMARY_WITH_PHONES, 1); 4335 4336 ContentValues v2 = new ContentValues(); 4337 v2.put(Groups._ID, groupId2); 4338 v2.put(Groups.TITLE, "title2"); 4339 v2.put(Groups.SOURCE_ID, "sourceId2"); 4340 v2.put(Groups.ACCOUNT_NAME, account2.name); 4341 v2.put(Groups.ACCOUNT_TYPE, account2.type); 4342 v2.put(Groups.SUMMARY_COUNT, 0); 4343 v2.put(Groups.SUMMARY_WITH_PHONES, 0); 4344 4345 ContentValues v3 = new ContentValues(); 4346 v3.put(Groups._ID, groupId3); 4347 v3.put(Groups.TITLE, "title3"); 4348 v3.put(Groups.SOURCE_ID, "sourceId3"); 4349 v3.put(Groups.ACCOUNT_NAME, account2.name); 4350 v3.put(Groups.ACCOUNT_TYPE, account2.type); 4351 v3.put(Groups.SUMMARY_COUNT, 0); 4352 v3.put(Groups.SUMMARY_WITH_PHONES, 0); 4353 4354 assertStoredValues(Groups.CONTENT_SUMMARY_URI, new ContentValues[] { v1, v2, v3 }); 4355 4356 // Now rawContactId1 has two phone numbers. 4357 insertPhoneNumber(rawContactId1, "111-111-1111"); 4358 insertPhoneNumber(rawContactId1, "111-111-1112"); 4359 // Result should reflect it correctly (don't count phone numbers but raw contacts) 4360 v1.put(Groups.SUMMARY_WITH_PHONES, v1.getAsInteger(Groups.SUMMARY_WITH_PHONES) + 1); 4361 assertStoredValues(Groups.CONTENT_SUMMARY_URI, new ContentValues[] { v1, v2, v3 }); 4362 4363 // Introduce new raw contact, pretending the user added another info. 4364 final long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "firstName3", 4365 "lastName3"); 4366 insertEmail(rawContactId3, "address3@email.com"); 4367 insertPhoneNumber(rawContactId3, "333-333-3333"); 4368 insertGroupMembership(rawContactId3, groupId2); 4369 v2.put(Groups.SUMMARY_COUNT, v2.getAsInteger(Groups.SUMMARY_COUNT) + 1); 4370 v2.put(Groups.SUMMARY_WITH_PHONES, v2.getAsInteger(Groups.SUMMARY_WITH_PHONES) + 1); 4371 4372 assertStoredValues(Groups.CONTENT_SUMMARY_URI, new ContentValues[] { v1, v2, v3 }); 4373 4374 final Uri uri = Groups.CONTENT_SUMMARY_URI; 4375 4376 // TODO Once SUMMARY_GROUP_COUNT_PER_ACCOUNT is supported remove all the if(false). 4377 if (false) { 4378 v1.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 1); 4379 v2.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 2); 4380 v3.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 2); 4381 } else { 4382 v1.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 0); 4383 v2.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 0); 4384 v3.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 0); 4385 } 4386 assertStoredValues(uri, new ContentValues[] { v1, v2, v3 }); 4387 4388 // Introduce another group in account1, testing SUMMARY_GROUP_COUNT_PER_ACCOUNT correctly 4389 // reflects the change. 4390 final long groupId4 = createGroup(account1, "sourceId4", "title4"); 4391 if (false) { 4392 v1.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 4393 v1.getAsInteger(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT) + 1); 4394 } else { 4395 v1.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 0); 4396 } 4397 ContentValues v4 = new ContentValues(); 4398 v4.put(Groups._ID, groupId4); 4399 v4.put(Groups.TITLE, "title4"); 4400 v4.put(Groups.SOURCE_ID, "sourceId4"); 4401 v4.put(Groups.ACCOUNT_NAME, account1.name); 4402 v4.put(Groups.ACCOUNT_TYPE, account1.type); 4403 v4.put(Groups.SUMMARY_COUNT, 0); 4404 v4.put(Groups.SUMMARY_WITH_PHONES, 0); 4405 if (false) { 4406 v4.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 4407 v1.getAsInteger(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT)); 4408 } else { 4409 v4.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, 0); 4410 } 4411 assertStoredValues(uri, new ContentValues[] { v1, v2, v3, v4 }); 4412 4413 // We change the tables dynamically according to the requested projection. 4414 // Make sure the SUMMARY_COUNT column exists 4415 v1.clear(); 4416 v1.put(Groups.SUMMARY_COUNT, 2); 4417 v2.clear(); 4418 v2.put(Groups.SUMMARY_COUNT, 1); 4419 v3.clear(); 4420 v3.put(Groups.SUMMARY_COUNT, 0); 4421 v4.clear(); 4422 v4.put(Groups.SUMMARY_COUNT, 0); 4423 assertStoredValuesWithProjection(uri, new ContentValues[] { v1, v2, v3, v4 }); 4424 } 4425 testSettingsQuery()4426 public void testSettingsQuery() { 4427 Account account1 = new Account("a", "b"); 4428 Account account2 = new Account("c", "d"); 4429 AccountWithDataSet account3 = new AccountWithDataSet("e", "f", "plus"); 4430 createSettings(account1, "0", "0"); 4431 createSettings(account2, "1", "1"); 4432 createSettings(account3, "1", "0"); 4433 Uri uri1 = TestUtil.maybeAddAccountQueryParameters(Settings.CONTENT_URI, account1); 4434 Uri uri2 = TestUtil.maybeAddAccountQueryParameters(Settings.CONTENT_URI, account2); 4435 Uri uri3 = Settings.CONTENT_URI.buildUpon() 4436 .appendQueryParameter(RawContacts.ACCOUNT_NAME, account3.getAccountName()) 4437 .appendQueryParameter(RawContacts.ACCOUNT_TYPE, account3.getAccountType()) 4438 .appendQueryParameter(RawContacts.DATA_SET, account3.getDataSet()) 4439 .build(); 4440 assertEquals(1, getCount(uri1, null, null)); 4441 assertEquals(1, getCount(uri2, null, null)); 4442 assertEquals(1, getCount(uri3, null, null)); 4443 assertStoredValue(uri1, Settings.SHOULD_SYNC, "0") ; 4444 assertStoredValue(uri1, Settings.UNGROUPED_VISIBLE, "0"); 4445 assertStoredValue(uri2, Settings.SHOULD_SYNC, "1") ; 4446 assertStoredValue(uri2, Settings.UNGROUPED_VISIBLE, "1"); 4447 assertStoredValue(uri3, Settings.SHOULD_SYNC, "1"); 4448 assertStoredValue(uri3, Settings.UNGROUPED_VISIBLE, "0"); 4449 } 4450 testSettingsInsertionPreventsDuplicates()4451 public void testSettingsInsertionPreventsDuplicates() { 4452 Account account1 = new Account("a", "b"); 4453 AccountWithDataSet account2 = new AccountWithDataSet("c", "d", "plus"); 4454 createSettings(account1, "0", "0"); 4455 createSettings(account2, "1", "1"); 4456 4457 // Now try creating the settings rows again. It should update the existing settings rows. 4458 createSettings(account1, "1", "0"); 4459 assertStoredValue(Settings.CONTENT_URI, 4460 Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE + "=?", 4461 new String[] {"a", "b"}, Settings.SHOULD_SYNC, "1"); 4462 4463 createSettings(account2, "0", "1"); 4464 assertStoredValue(Settings.CONTENT_URI, 4465 Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE + "=? AND " + 4466 Settings.DATA_SET + "=?", 4467 new String[] {"c", "d", "plus"}, Settings.SHOULD_SYNC, "0"); 4468 } 4469 testSettingsDeletion()4470 public void testSettingsDeletion() { 4471 Account account = new Account("a", "b"); 4472 Uri settingUri = createSettings(account, "0", "1"); 4473 long rawContactId = RawContactUtil.createRawContact(mResolver, account); 4474 4475 int count = mResolver.delete(settingUri, null, null); 4476 4477 // Settings cannot be deleted when there are still raw contacts for the account. 4478 assertEquals(0, count); 4479 4480 assertStoredValue(Settings.CONTENT_URI, 4481 Settings.ACCOUNT_NAME + "= ? AND " + Settings.ACCOUNT_TYPE + "= ?", 4482 new String[] {"a", "b"}, Settings.UNGROUPED_VISIBLE, "1"); 4483 4484 RawContactUtil.delete(mResolver, rawContactId, true); 4485 4486 count = mResolver.delete(settingUri, null, null); 4487 4488 assertEquals(1, count); 4489 assertRowCount(0, Settings.CONTENT_URI, null, null); 4490 } 4491 testSettingsUpdate()4492 public void testSettingsUpdate() { 4493 Account account1 = new Account("a", "b"); 4494 Account account2 = new Account("c", "d"); 4495 Account account3 = new Account("e", "f"); 4496 createSettings(account1, "0", "0"); 4497 createSettings(account2, "0", "0"); 4498 createSettings(account3, "0", "0"); 4499 4500 ContentValues values = new ContentValues(); 4501 values.put(Settings.UNGROUPED_VISIBLE, 1); 4502 int count = mResolver.update(Settings.CONTENT_URI, values, null, null); 4503 4504 assertEquals(3, count); 4505 assertStoredValues(Settings.CONTENT_URI, 4506 cv(Settings.UNGROUPED_VISIBLE, 1), 4507 cv(Settings.UNGROUPED_VISIBLE, 1), 4508 cv(Settings.UNGROUPED_VISIBLE, 1)); 4509 4510 values.put(Settings.SHOULD_SYNC, 1); 4511 count = mResolver.update(Settings.CONTENT_URI, values, 4512 Settings.ACCOUNT_NAME + "=?", new String[] {"a"}); 4513 4514 assertEquals(1, count); 4515 assertStoredValues(Settings.CONTENT_URI, 4516 cv(Settings.ACCOUNT_NAME, "a", 4517 Settings.SHOULD_SYNC, 1), 4518 cv(Settings.ACCOUNT_NAME, "c", 4519 Settings.SHOULD_SYNC, 0), 4520 cv(Settings.ACCOUNT_NAME, "e", 4521 Settings.SHOULD_SYNC, 0)); 4522 4523 values.clear(); 4524 // Settings are stored in the accounts table but updates shouldn't be allowed to modify 4525 // the other non-Settings columns. 4526 values.put(Settings.ACCOUNT_NAME, "x"); 4527 values.put(Settings.ACCOUNT_TYPE, "y"); 4528 values.put(Settings.DATA_SET, "z"); 4529 mResolver.update(Settings.CONTENT_URI, values, null, null); 4530 4531 values.put(AccountsColumns.SIM_EF_TYPE, 1); 4532 values.put(AccountsColumns.SIM_SLOT_INDEX, 1); 4533 try { 4534 mResolver.update(Settings.CONTENT_URI, values, null, null); 4535 } catch (Exception e) { 4536 // ignored. We just care that the update didn't change the data 4537 } 4538 4539 assertStoredValuesDb("SELECT * FROM " + Tables.ACCOUNTS, null, 4540 cv( 4541 Settings.ACCOUNT_NAME, "a", 4542 Settings.ACCOUNT_TYPE, "b", 4543 Settings.DATA_SET, null, 4544 AccountsColumns.SIM_SLOT_INDEX, null, 4545 AccountsColumns.SIM_EF_TYPE, null 4546 ), 4547 cv( 4548 Settings.ACCOUNT_NAME, "c", 4549 Settings.ACCOUNT_TYPE, "d", 4550 Settings.DATA_SET, null, 4551 AccountsColumns.SIM_SLOT_INDEX, null, 4552 AccountsColumns.SIM_EF_TYPE, null 4553 ), 4554 cv( 4555 Settings.ACCOUNT_NAME, "e", 4556 Settings.ACCOUNT_TYPE, "f", 4557 Settings.DATA_SET, null, 4558 AccountsColumns.SIM_SLOT_INDEX, null, 4559 AccountsColumns.SIM_EF_TYPE, null 4560 )); 4561 } 4562 testSettingsLocalAccount()4563 public void testSettingsLocalAccount() { 4564 AccountWithDataSet localAccount = AccountWithDataSet.LOCAL; 4565 4566 // It's not possible to insert the local account directly into settings but it will be 4567 // created automatically when a raw contact is created for it. 4568 RawContactUtil.createRawContactWithAccountDataSet( 4569 mResolver, localAccount.getAccountName(), 4570 localAccount.getAccountType(), localAccount.getDataSet()); 4571 4572 ContentValues values = new ContentValues(); 4573 values.put(Settings.ACCOUNT_NAME, localAccount.getAccountName()); 4574 values.put(Settings.ACCOUNT_TYPE, localAccount.getAccountType()); 4575 values.put(Settings.DATA_SET, localAccount.getDataSet()); 4576 ContentValues expectedValues = new ContentValues(values); 4577 // The defaults for the local account are opposite of other accounts. 4578 expectedValues.put(Settings.UNGROUPED_VISIBLE, "1"); 4579 expectedValues.put(Settings.SHOULD_SYNC, "0"); 4580 4581 assertStoredValues(Settings.CONTENT_URI, expectedValues); 4582 4583 values.put(Settings.SHOULD_SYNC, 1); 4584 values.put(Settings.UNGROUPED_VISIBLE, 0); 4585 mResolver.update(Settings.CONTENT_URI, values, null, null); 4586 4587 expectedValues.put(Settings.UNGROUPED_VISIBLE, "0"); 4588 expectedValues.put(Settings.SHOULD_SYNC, "1"); 4589 assertStoredValues(Settings.CONTENT_URI, expectedValues); 4590 4591 // Empty strings should also be the local account. 4592 values.put(Settings.ACCOUNT_NAME, ""); 4593 values.put(Settings.ACCOUNT_TYPE, ""); 4594 values.put(Settings.DATA_SET, ""); 4595 mResolver.insert(Settings.CONTENT_URI, values); 4596 4597 assertRowCount(1, Settings.CONTENT_URI, null, null); 4598 } 4599 testDisplayNameParsingWhenPartsUnspecified()4600 public void testDisplayNameParsingWhenPartsUnspecified() { 4601 long rawContactId = RawContactUtil.createRawContact(mResolver); 4602 ContentValues values = new ContentValues(); 4603 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 4604 DataUtil.insertStructuredName(mResolver, rawContactId, values); 4605 4606 assertStructuredName(rawContactId, "Mr.", "John", "Kevin", "von Smith", "Jr."); 4607 } 4608 testDisplayNameParsingWhenPartsAreNull()4609 public void testDisplayNameParsingWhenPartsAreNull() { 4610 long rawContactId = RawContactUtil.createRawContact(mResolver); 4611 ContentValues values = new ContentValues(); 4612 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 4613 values.putNull(StructuredName.GIVEN_NAME); 4614 values.putNull(StructuredName.FAMILY_NAME); 4615 DataUtil.insertStructuredName(mResolver, rawContactId, values); 4616 assertStructuredName(rawContactId, "Mr.", "John", "Kevin", "von Smith", "Jr."); 4617 } 4618 testDisplayNameParsingWhenPartsSpecified()4619 public void testDisplayNameParsingWhenPartsSpecified() { 4620 long rawContactId = RawContactUtil.createRawContact(mResolver); 4621 ContentValues values = new ContentValues(); 4622 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 4623 values.put(StructuredName.FAMILY_NAME, "Johnson"); 4624 DataUtil.insertStructuredName(mResolver, rawContactId, values); 4625 4626 assertStructuredName(rawContactId, null, null, null, "Johnson", null); 4627 } 4628 testContactWithoutPhoneticName()4629 public void testContactWithoutPhoneticName() { 4630 ContactLocaleUtils.setLocaleForTest(Locale.ENGLISH); 4631 final long rawContactId = RawContactUtil.createRawContact(mResolver, null); 4632 4633 ContentValues values = new ContentValues(); 4634 values.put(StructuredName.PREFIX, "Mr"); 4635 values.put(StructuredName.GIVEN_NAME, "John"); 4636 values.put(StructuredName.MIDDLE_NAME, "K."); 4637 values.put(StructuredName.FAMILY_NAME, "Doe"); 4638 values.put(StructuredName.SUFFIX, "Jr."); 4639 Uri dataUri = DataUtil.insertStructuredName(mResolver, rawContactId, values); 4640 4641 values.clear(); 4642 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 4643 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "Mr John K. Doe, Jr."); 4644 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "Mr Doe, John K., Jr."); 4645 values.putNull(RawContacts.PHONETIC_NAME); 4646 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 4647 values.put(RawContacts.SORT_KEY_PRIMARY, "John K. Doe, Jr."); 4648 values.put(RawContactsColumns.PHONEBOOK_LABEL_PRIMARY, "J"); 4649 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "Doe, John K., Jr."); 4650 values.put(RawContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, "D"); 4651 4652 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 4653 assertStoredValues(rawContactUri, values); 4654 4655 values.clear(); 4656 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 4657 values.put(Contacts.DISPLAY_NAME_PRIMARY, "Mr John K. Doe, Jr."); 4658 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "Mr Doe, John K., Jr."); 4659 values.putNull(Contacts.PHONETIC_NAME); 4660 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 4661 values.put(Contacts.SORT_KEY_PRIMARY, "John K. Doe, Jr."); 4662 values.put(ContactsColumns.PHONEBOOK_LABEL_PRIMARY, "J"); 4663 values.put(Contacts.SORT_KEY_ALTERNATIVE, "Doe, John K., Jr."); 4664 values.put(ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, "D"); 4665 4666 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 4667 queryContactId(rawContactId)); 4668 assertStoredValues(contactUri, values); 4669 4670 // The same values should be available through a join with Data 4671 assertStoredValues(dataUri, values); 4672 } 4673 testContactWithChineseName()4674 public void testContactWithChineseName() { 4675 if (!hasChineseCollator()) { 4676 return; 4677 } 4678 ContactLocaleUtils.setLocaleForTest(Locale.SIMPLIFIED_CHINESE); 4679 4680 long rawContactId = RawContactUtil.createRawContact(mResolver, null); 4681 4682 ContentValues values = new ContentValues(); 4683 // "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B" 4684 values.put(StructuredName.DISPLAY_NAME, "\u6BB5\u5C0F\u6D9B"); 4685 Uri dataUri = DataUtil.insertStructuredName(mResolver, rawContactId, values); 4686 4687 values.clear(); 4688 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 4689 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "\u6BB5\u5C0F\u6D9B"); 4690 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B"); 4691 values.putNull(RawContacts.PHONETIC_NAME); 4692 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 4693 values.put(RawContacts.SORT_KEY_PRIMARY, "\u6BB5\u5C0F\u6D9B"); 4694 values.put(RawContactsColumns.PHONEBOOK_LABEL_PRIMARY, "D"); 4695 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B"); 4696 values.put(RawContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, "D"); 4697 4698 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 4699 assertStoredValues(rawContactUri, values); 4700 4701 values.clear(); 4702 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 4703 values.put(Contacts.DISPLAY_NAME_PRIMARY, "\u6BB5\u5C0F\u6D9B"); 4704 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B"); 4705 values.putNull(Contacts.PHONETIC_NAME); 4706 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 4707 values.put(Contacts.SORT_KEY_PRIMARY, "\u6BB5\u5C0F\u6D9B"); 4708 values.put(ContactsColumns.PHONEBOOK_LABEL_PRIMARY, "D"); 4709 values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B"); 4710 values.put(ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, "D"); 4711 4712 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 4713 queryContactId(rawContactId)); 4714 assertStoredValues(contactUri, values); 4715 4716 // The same values should be available through a join with Data 4717 assertStoredValues(dataUri, values); 4718 } 4719 testJapaneseNameContactInEnglishLocale()4720 public void testJapaneseNameContactInEnglishLocale() { 4721 // Need Japanese locale data for transliteration 4722 if (!hasJapaneseCollator()) { 4723 return; 4724 } 4725 ContactLocaleUtils.setLocaleForTest(Locale.US); 4726 long rawContactId = RawContactUtil.createRawContact(mResolver, null); 4727 4728 ContentValues values = new ContentValues(); 4729 values.put(StructuredName.GIVEN_NAME, "\u7A7A\u6D77"); 4730 values.put(StructuredName.PHONETIC_GIVEN_NAME, "\u304B\u3044\u304F\u3046"); 4731 DataUtil.insertStructuredName(mResolver, rawContactId, values); 4732 4733 long contactId = queryContactId(rawContactId); 4734 // en_US should behave same as ja_JP (match on Hiragana and Romaji 4735 // but not Pinyin) 4736 assertContactFilter(contactId, "\u304B\u3044\u304F\u3046"); 4737 assertContactFilter(contactId, "kaiku"); 4738 assertContactFilterNoResult("kong"); 4739 } 4740 testContactWithJapaneseName()4741 public void testContactWithJapaneseName() { 4742 if (!hasJapaneseCollator()) { 4743 return; 4744 } 4745 ContactLocaleUtils.setLocaleForTest(Locale.JAPAN); 4746 long rawContactId = RawContactUtil.createRawContact(mResolver, null); 4747 4748 ContentValues values = new ContentValues(); 4749 values.put(StructuredName.GIVEN_NAME, "\u7A7A\u6D77"); 4750 values.put(StructuredName.PHONETIC_GIVEN_NAME, "\u304B\u3044\u304F\u3046"); 4751 Uri dataUri = DataUtil.insertStructuredName(mResolver, rawContactId, values); 4752 4753 values.clear(); 4754 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 4755 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "\u7A7A\u6D77"); 4756 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "\u7A7A\u6D77"); 4757 values.put(RawContacts.PHONETIC_NAME, "\u304B\u3044\u304F\u3046"); 4758 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 4759 values.put(RawContacts.SORT_KEY_PRIMARY, "\u304B\u3044\u304F\u3046"); 4760 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "\u304B\u3044\u304F\u3046"); 4761 values.put(RawContactsColumns.PHONEBOOK_LABEL_PRIMARY, "\u304B"); 4762 values.put(RawContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, "\u304B"); 4763 4764 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 4765 assertStoredValues(rawContactUri, values); 4766 4767 values.clear(); 4768 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 4769 values.put(Contacts.DISPLAY_NAME_PRIMARY, "\u7A7A\u6D77"); 4770 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "\u7A7A\u6D77"); 4771 values.put(Contacts.PHONETIC_NAME, "\u304B\u3044\u304F\u3046"); 4772 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 4773 values.put(Contacts.SORT_KEY_PRIMARY, "\u304B\u3044\u304F\u3046"); 4774 values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u304B\u3044\u304F\u3046"); 4775 values.put(ContactsColumns.PHONEBOOK_LABEL_PRIMARY, "\u304B"); 4776 values.put(ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, "\u304B"); 4777 4778 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 4779 queryContactId(rawContactId)); 4780 assertStoredValues(contactUri, values); 4781 4782 // The same values should be available through a join with Data 4783 assertStoredValues(dataUri, values); 4784 4785 long contactId = queryContactId(rawContactId); 4786 // ja_JP should match on Hiragana and Romaji but not Pinyin 4787 assertContactFilter(contactId, "\u304B\u3044\u304F\u3046"); 4788 assertContactFilter(contactId, "kaiku"); 4789 assertContactFilterNoResult("kong"); 4790 } 4791 testDisplayNameUpdate()4792 public void testDisplayNameUpdate() { 4793 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 4794 insertEmail(rawContactId1, "potato@acme.com", true); 4795 4796 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 4797 insertPhoneNumber(rawContactId2, "123456789", true); 4798 4799 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 4800 rawContactId1, rawContactId2); 4801 4802 assertAggregated(rawContactId1, rawContactId2, "123456789"); 4803 4804 DataUtil.insertStructuredName(mResolver, rawContactId2, "Potato", "Head"); 4805 4806 assertAggregated(rawContactId1, rawContactId2, "Potato Head"); 4807 assertNetworkNotified(true); 4808 } 4809 testDisplayNameFromData()4810 public void testDisplayNameFromData() { 4811 long rawContactId = RawContactUtil.createRawContact(mResolver); 4812 long contactId = queryContactId(rawContactId); 4813 ContentValues values = new ContentValues(); 4814 4815 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4816 4817 assertStoredValue(uri, Contacts.DISPLAY_NAME, null); 4818 insertEmail(rawContactId, "mike@monstersinc.com"); 4819 assertStoredValue(uri, Contacts.DISPLAY_NAME, "mike@monstersinc.com"); 4820 4821 insertEmail(rawContactId, "james@monstersinc.com", true); 4822 assertStoredValue(uri, Contacts.DISPLAY_NAME, "james@monstersinc.com"); 4823 4824 insertPhoneNumber(rawContactId, "1-800-466-4411"); 4825 assertStoredValue(uri, Contacts.DISPLAY_NAME, "1-800-466-4411"); 4826 4827 // If there are title and company, the company is display name. 4828 values.clear(); 4829 values.put(Organization.COMPANY, "Monsters Inc"); 4830 Uri organizationUri = insertOrganization(rawContactId, values); 4831 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Monsters Inc"); 4832 4833 // If there is nickname, that is display name. 4834 insertNickname(rawContactId, "Sully"); 4835 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Sully"); 4836 4837 // If there is structured name, that is display name. 4838 values.clear(); 4839 values.put(StructuredName.GIVEN_NAME, "James"); 4840 values.put(StructuredName.MIDDLE_NAME, "P."); 4841 values.put(StructuredName.FAMILY_NAME, "Sullivan"); 4842 DataUtil.insertStructuredName(mResolver, rawContactId, values); 4843 assertStoredValue(uri, Contacts.DISPLAY_NAME, "James P. Sullivan"); 4844 } 4845 testDisplayNameFromOrganizationWithoutPhoneticName()4846 public void testDisplayNameFromOrganizationWithoutPhoneticName() { 4847 long rawContactId = RawContactUtil.createRawContact(mResolver); 4848 long contactId = queryContactId(rawContactId); 4849 ContentValues values = new ContentValues(); 4850 4851 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4852 4853 // If there is title without company, the title is display name. 4854 values.clear(); 4855 values.put(Organization.TITLE, "Protagonist"); 4856 Uri organizationUri = insertOrganization(rawContactId, values); 4857 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Protagonist"); 4858 4859 // If there are title and company, the company is display name. 4860 values.clear(); 4861 values.put(Organization.COMPANY, "Monsters Inc"); 4862 mResolver.update(organizationUri, values, null, null); 4863 4864 values.clear(); 4865 values.put(Contacts.DISPLAY_NAME, "Monsters Inc"); 4866 values.putNull(Contacts.PHONETIC_NAME); 4867 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 4868 values.put(Contacts.SORT_KEY_PRIMARY, "Monsters Inc"); 4869 values.put(Contacts.SORT_KEY_ALTERNATIVE, "Monsters Inc"); 4870 values.put(ContactsColumns.PHONEBOOK_LABEL_PRIMARY, "M"); 4871 values.put(ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, "M"); 4872 assertStoredValues(uri, values); 4873 } 4874 testDisplayNameFromOrganizationWithJapanesePhoneticName()4875 public void testDisplayNameFromOrganizationWithJapanesePhoneticName() { 4876 if (!hasJapaneseCollator()) { 4877 return; 4878 } 4879 ContactLocaleUtils.setLocaleForTest(Locale.JAPAN); 4880 long rawContactId = RawContactUtil.createRawContact(mResolver); 4881 long contactId = queryContactId(rawContactId); 4882 ContentValues values = new ContentValues(); 4883 4884 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4885 4886 // If there is title without company, the title is display name. 4887 values.clear(); 4888 values.put(Organization.COMPANY, "DoCoMo"); 4889 values.put(Organization.PHONETIC_NAME, "\u30C9\u30B3\u30E2"); 4890 Uri organizationUri = insertOrganization(rawContactId, values); 4891 4892 values.clear(); 4893 values.put(Contacts.DISPLAY_NAME, "DoCoMo"); 4894 values.put(Contacts.PHONETIC_NAME, "\u30C9\u30B3\u30E2"); 4895 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 4896 values.put(Contacts.SORT_KEY_PRIMARY, "\u30C9\u30B3\u30E2"); 4897 values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u30C9\u30B3\u30E2"); 4898 values.put(ContactsColumns.PHONEBOOK_LABEL_PRIMARY, "\u305F"); 4899 values.put(ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, "\u305F"); 4900 assertStoredValues(uri, values); 4901 } 4902 testDisplayNameFromOrganizationWithChineseName()4903 public void testDisplayNameFromOrganizationWithChineseName() { 4904 if (!hasChineseCollator()) { 4905 return; 4906 } 4907 ContactLocaleUtils.setLocaleForTest(Locale.SIMPLIFIED_CHINESE); 4908 4909 long rawContactId = RawContactUtil.createRawContact(mResolver); 4910 long contactId = queryContactId(rawContactId); 4911 ContentValues values = new ContentValues(); 4912 4913 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 4914 4915 // If there is title without company, the title is display name. 4916 values.clear(); 4917 values.put(Organization.COMPANY, "\u4E2D\u56FD\u7535\u4FE1"); 4918 Uri organizationUri = insertOrganization(rawContactId, values); 4919 4920 values.clear(); 4921 values.put(Contacts.DISPLAY_NAME, "\u4E2D\u56FD\u7535\u4FE1"); 4922 values.putNull(Contacts.PHONETIC_NAME); 4923 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 4924 values.put(Contacts.SORT_KEY_PRIMARY, "\u4E2D\u56FD\u7535\u4FE1"); 4925 values.put(ContactsColumns.PHONEBOOK_LABEL_PRIMARY, "Z"); 4926 values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u4E2D\u56FD\u7535\u4FE1"); 4927 values.put(ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE, "Z"); 4928 assertStoredValues(uri, values); 4929 } 4930 testLookupByOrganization()4931 public void testLookupByOrganization() { 4932 long rawContactId = RawContactUtil.createRawContact(mResolver); 4933 long contactId = queryContactId(rawContactId); 4934 ContentValues values = new ContentValues(); 4935 4936 values.clear(); 4937 values.put(Organization.COMPANY, "acmecorp"); 4938 values.put(Organization.TITLE, "president"); 4939 Uri organizationUri = insertOrganization(rawContactId, values); 4940 4941 assertContactFilter(contactId, "acmecorp"); 4942 assertContactFilter(contactId, "president"); 4943 4944 values.clear(); 4945 values.put(Organization.DEPARTMENT, "software"); 4946 mResolver.update(organizationUri, values, null, null); 4947 4948 assertContactFilter(contactId, "acmecorp"); 4949 assertContactFilter(contactId, "president"); 4950 4951 values.clear(); 4952 values.put(Organization.COMPANY, "incredibles"); 4953 mResolver.update(organizationUri, values, null, null); 4954 4955 assertContactFilter(contactId, "incredibles"); 4956 assertContactFilter(contactId, "president"); 4957 4958 values.clear(); 4959 values.put(Organization.TITLE, "director"); 4960 mResolver.update(organizationUri, values, null, null); 4961 4962 assertContactFilter(contactId, "incredibles"); 4963 assertContactFilter(contactId, "director"); 4964 4965 values.clear(); 4966 values.put(Organization.COMPANY, "monsters"); 4967 values.put(Organization.TITLE, "scarer"); 4968 mResolver.update(organizationUri, values, null, null); 4969 4970 assertContactFilter(contactId, "monsters"); 4971 assertContactFilter(contactId, "scarer"); 4972 } 4973 assertContactFilter(long contactId, String filter)4974 private void assertContactFilter(long contactId, String filter) { 4975 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(filter)); 4976 assertStoredValue(filterUri, Contacts._ID, contactId); 4977 } 4978 assertContactFilterNoResult(String filter)4979 private void assertContactFilterNoResult(String filter) { 4980 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(filter)); 4981 assertEquals(0, getCount(filterUri, null, null)); 4982 } 4983 testSearchSnippetOrganization()4984 public void testSearchSnippetOrganization() throws Exception { 4985 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 4986 long contactId = queryContactId(rawContactId); 4987 4988 // Some random data element 4989 insertEmail(rawContactId, "inc@corp.com"); 4990 4991 ContentValues values = new ContentValues(); 4992 values.clear(); 4993 values.put(Organization.COMPANY, "acmecorp"); 4994 values.put(Organization.TITLE, "engineer"); 4995 Uri organizationUri = insertOrganization(rawContactId, values); 4996 4997 // Add another matching organization 4998 values.put(Organization.COMPANY, "acmeinc"); 4999 insertOrganization(rawContactId, values); 5000 5001 // Add another non-matching organization 5002 values.put(Organization.COMPANY, "corpacme"); 5003 insertOrganization(rawContactId, values); 5004 5005 // And another data element 5006 insertEmail(rawContactId, "emca@corp.com", true, Email.TYPE_CUSTOM, "Custom"); 5007 5008 Uri filterUri = buildFilterUri("acme", true); 5009 5010 values.clear(); 5011 values.put(Contacts._ID, contactId); 5012 values.put(SearchSnippets.SNIPPET, "acmecorp"); 5013 assertContainsValues(filterUri, values); 5014 } 5015 testSearchSnippetEmail()5016 public void testSearchSnippetEmail() throws Exception { 5017 long rawContactId = RawContactUtil.createRawContact(mResolver); 5018 long contactId = queryContactId(rawContactId); 5019 ContentValues values = new ContentValues(); 5020 5021 DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe"); 5022 Uri dataUri = insertEmail(rawContactId, "acme@corp.com", true, Email.TYPE_CUSTOM, "Custom"); 5023 5024 Uri filterUri = buildFilterUri("acme", true); 5025 5026 values.clear(); 5027 values.put(Contacts._ID, contactId); 5028 values.put(SearchSnippets.SNIPPET, "acme@corp.com"); 5029 assertStoredValues(filterUri, values); 5030 } 5031 testCountPhoneNumberDigits()5032 public void testCountPhoneNumberDigits() { 5033 assertEquals(10, ContactsProvider2.countPhoneNumberDigits("86 (0) 5-55-12-34")); 5034 assertEquals(10, ContactsProvider2.countPhoneNumberDigits("860 555-1234")); 5035 assertEquals(3, ContactsProvider2.countPhoneNumberDigits("860")); 5036 assertEquals(10, ContactsProvider2.countPhoneNumberDigits("8605551234")); 5037 assertEquals(6, ContactsProvider2.countPhoneNumberDigits("860555")); 5038 assertEquals(6, ContactsProvider2.countPhoneNumberDigits("860 555")); 5039 assertEquals(6, ContactsProvider2.countPhoneNumberDigits("860-555")); 5040 assertEquals(12, ContactsProvider2.countPhoneNumberDigits("+441234098765")); 5041 assertEquals(0, ContactsProvider2.countPhoneNumberDigits("44+1234098765")); 5042 assertEquals(0, ContactsProvider2.countPhoneNumberDigits("+441234098foo")); 5043 } 5044 testSearchSnippetPhone()5045 public void testSearchSnippetPhone() throws Exception { 5046 long rawContactId = RawContactUtil.createRawContact(mResolver); 5047 long contactId = queryContactId(rawContactId); 5048 ContentValues values = new ContentValues(); 5049 5050 DataUtil.insertStructuredName(mResolver, rawContactId, "Cave", "Johnson"); 5051 insertPhoneNumber(rawContactId, "(860) 555-1234"); 5052 5053 values.clear(); 5054 values.put(Contacts._ID, contactId); 5055 values.put(SearchSnippets.SNIPPET, "[(860) 555-1234]"); 5056 5057 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 5058 Uri.encode("86 (0) 5-55-12-34")), values); 5059 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 5060 Uri.encode("860 555-1234")), values); 5061 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 5062 Uri.encode("860")), values); 5063 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 5064 Uri.encode("8605551234")), values); 5065 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 5066 Uri.encode("860555")), values); 5067 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 5068 Uri.encode("860 555")), values); 5069 assertStoredValues(Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 5070 Uri.encode("860-555")), values); 5071 } 5072 buildFilterUri(String query, boolean deferredSnippeting)5073 private Uri buildFilterUri(String query, boolean deferredSnippeting) { 5074 Uri.Builder builder = Contacts.CONTENT_FILTER_URI.buildUpon() 5075 .appendPath(Uri.encode(query)); 5076 if (deferredSnippeting) { 5077 builder.appendQueryParameter(ContactsContract.DEFERRED_SNIPPETING, "1"); 5078 } 5079 return builder.build(); 5080 } 5081 createSnippetContentValues(long contactId, String snippet)5082 public ContentValues createSnippetContentValues(long contactId, String snippet) { 5083 final ContentValues values = new ContentValues(); 5084 values.clear(); 5085 values.put(Contacts._ID, contactId); 5086 values.put(SearchSnippets.SNIPPET, snippet); 5087 return values; 5088 } 5089 testSearchSnippetNickname()5090 public void testSearchSnippetNickname() throws Exception { 5091 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 5092 long contactId = queryContactId(rawContactId); 5093 ContentValues values = new ContentValues(); 5094 5095 Uri dataUri = insertNickname(rawContactId, "Incredible"); 5096 5097 Uri filterUri = buildFilterUri("inc", true); 5098 5099 values.clear(); 5100 values.put(Contacts._ID, contactId); 5101 values.put(SearchSnippets.SNIPPET, "Incredible"); 5102 assertStoredValues(filterUri, values); 5103 } 5104 testSearchSnippetEmptyForNameInDisplayName()5105 public void testSearchSnippetEmptyForNameInDisplayName() throws Exception { 5106 long rawContactId = RawContactUtil.createRawContact(mResolver); 5107 long contactId = queryContactId(rawContactId); 5108 DataUtil.insertStructuredName(mResolver, rawContactId, "Cave", "Johnson"); 5109 insertEmail(rawContactId, "cave@aperturescience.com", true); 5110 5111 ContentValues snippet = createSnippetContentValues(contactId, "cave@aperturescience.com"); 5112 5113 assertContainsValues(buildFilterUri("cave", true), snippet); 5114 assertContainsValues(buildFilterUri("john", true), snippet); 5115 } 5116 testSearchSnippetEmptyForNicknameInDisplayName()5117 public void testSearchSnippetEmptyForNicknameInDisplayName() throws Exception { 5118 long rawContactId = RawContactUtil.createRawContact(mResolver); 5119 long contactId = queryContactId(rawContactId); 5120 insertNickname(rawContactId, "Caveman"); 5121 insertEmail(rawContactId, "cave@aperturescience.com", true); 5122 5123 ContentValues snippet = createSnippetContentValues(contactId, "cave@aperturescience.com"); 5124 5125 assertContainsValues(buildFilterUri("cave", true), snippet); 5126 } 5127 testSearchSnippetEmptyForCompanyInDisplayName()5128 public void testSearchSnippetEmptyForCompanyInDisplayName() throws Exception { 5129 long rawContactId = RawContactUtil.createRawContact(mResolver); 5130 long contactId = queryContactId(rawContactId); 5131 ContentValues company = new ContentValues(); 5132 company.clear(); 5133 company.put(Organization.COMPANY, "Aperture Science"); 5134 company.put(Organization.TITLE, "President"); 5135 insertOrganization(rawContactId, company); 5136 insertEmail(rawContactId, "aperturepresident@aperturescience.com", true); 5137 5138 ContentValues snippet = createSnippetContentValues(contactId, "aperturepresident"); 5139 5140 assertContainsValues(buildFilterUri("aperture", true), snippet); 5141 } 5142 testSearchSnippetEmptyForPhoneInDisplayName()5143 public void testSearchSnippetEmptyForPhoneInDisplayName() throws Exception { 5144 long rawContactId = RawContactUtil.createRawContact(mResolver); 5145 long contactId = queryContactId(rawContactId); 5146 insertPhoneNumber(rawContactId, "860-555-1234"); 5147 insertEmail(rawContactId, "860@aperturescience.com", true); 5148 5149 ContentValues snippet = createSnippetContentValues(contactId, "860-555-1234"); 5150 5151 assertContainsValues(buildFilterUri("860", true), snippet); 5152 } 5153 testSearchSnippetEmptyForEmailInDisplayName()5154 public void testSearchSnippetEmptyForEmailInDisplayName() throws Exception { 5155 long rawContactId = RawContactUtil.createRawContact(mResolver); 5156 long contactId = queryContactId(rawContactId); 5157 insertEmail(rawContactId, "cave@aperturescience.com", true); 5158 insertNote(rawContactId, "Cave Johnson is president of Aperture Science"); 5159 5160 ContentValues snippet = createSnippetContentValues(contactId, 5161 "Cave Johnson is president of Aperture Science"); 5162 5163 assertContainsValues(buildFilterUri("cave", true), snippet); 5164 } 5165 testDisplayNameUpdateFromStructuredNameUpdate()5166 public void testDisplayNameUpdateFromStructuredNameUpdate() { 5167 long rawContactId = RawContactUtil.createRawContact(mResolver); 5168 Uri nameUri = DataUtil.insertStructuredName(mResolver, rawContactId, "Slinky", "Dog"); 5169 5170 long contactId = queryContactId(rawContactId); 5171 5172 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 5173 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky Dog"); 5174 5175 ContentValues values = new ContentValues(); 5176 values.putNull(StructuredName.FAMILY_NAME); 5177 5178 mResolver.update(nameUri, values, null, null); 5179 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky"); 5180 5181 values.putNull(StructuredName.GIVEN_NAME); 5182 5183 mResolver.update(nameUri, values, null, null); 5184 assertStoredValue(uri, Contacts.DISPLAY_NAME, null); 5185 5186 values.put(StructuredName.FAMILY_NAME, "Dog"); 5187 mResolver.update(nameUri, values, null, null); 5188 5189 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Dog"); 5190 } 5191 testInsertDataWithContentProviderOperations()5192 public void testInsertDataWithContentProviderOperations() throws Exception { 5193 ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 5194 .withValues(new ContentValues()) 5195 .build(); 5196 ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 5197 .withValueBackReference(Data.RAW_CONTACT_ID, 0) 5198 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 5199 .withValue(StructuredName.GIVEN_NAME, "John") 5200 .withValue(StructuredName.FAMILY_NAME, "Doe") 5201 .build(); 5202 ContentProviderResult[] results = 5203 mResolver.applyBatch(ContactsContract.AUTHORITY, Lists.newArrayList(cpo1, cpo2)); 5204 long contactId = queryContactId(ContentUris.parseId(results[0].uri)); 5205 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 5206 assertStoredValue(uri, Contacts.DISPLAY_NAME, "John Doe"); 5207 } 5208 testSendToVoicemailDefault()5209 public void testSendToVoicemailDefault() { 5210 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 5211 long contactId = queryContactId(rawContactId); 5212 5213 Cursor c = queryContact(contactId); 5214 assertTrue(c.moveToNext()); 5215 int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL)); 5216 assertEquals(0, sendToVoicemail); 5217 c.close(); 5218 } 5219 testSetSendToVoicemailAndRingtone()5220 public void testSetSendToVoicemailAndRingtone() { 5221 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 5222 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 5223 assertDirty(rawContactUri, true); 5224 clearDirty(rawContactUri); 5225 long contactId = queryContactId(rawContactId); 5226 5227 updateSendToVoicemailAndRingtone(contactId, true, "foo"); 5228 assertSendToVoicemailAndRingtone(contactId, true, "foo"); 5229 assertNetworkNotified(false); 5230 assertDirty(rawContactUri, false); 5231 assertMetadataDirty(rawContactUri, false); 5232 5233 updateSendToVoicemailAndRingtoneWithSelection(contactId, false, "bar"); 5234 assertSendToVoicemailAndRingtone(contactId, false, "bar"); 5235 assertNetworkNotified(false); 5236 assertDirty(rawContactUri, false); 5237 assertMetadataDirty(rawContactUri, false); 5238 } 5239 testSendToVoicemailAndRingtoneAfterAggregation()5240 public void testSendToVoicemailAndRingtoneAfterAggregation() { 5241 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "a", "b"); 5242 long contactId1 = queryContactId(rawContactId1); 5243 updateSendToVoicemailAndRingtone(contactId1, true, "foo"); 5244 5245 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "c", "d"); 5246 long contactId2 = queryContactId(rawContactId2); 5247 updateSendToVoicemailAndRingtone(contactId2, true, "bar"); 5248 5249 // Aggregate them 5250 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 5251 rawContactId1, rawContactId2); 5252 5253 // Both contacts had "send to VM", the contact now has the same value 5254 assertSendToVoicemailAndRingtone(contactId1, true, "foo,bar"); // Either foo or bar 5255 } 5256 testDoNotSendToVoicemailAfterAggregation()5257 public void testDoNotSendToVoicemailAfterAggregation() { 5258 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "e", "f"); 5259 long contactId1 = queryContactId(rawContactId1); 5260 updateSendToVoicemailAndRingtone(contactId1, true, null); 5261 5262 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "g", "h"); 5263 long contactId2 = queryContactId(rawContactId2); 5264 updateSendToVoicemailAndRingtone(contactId2, false, null); 5265 5266 // Aggregate them 5267 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 5268 rawContactId1, rawContactId2); 5269 5270 // Since one of the contacts had "don't send to VM" that setting wins for the aggregate 5271 assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), false, null); 5272 } 5273 testSetSendToVoicemailAndRingtonePreservedAfterJoinAndSplit()5274 public void testSetSendToVoicemailAndRingtonePreservedAfterJoinAndSplit() { 5275 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "i", "j"); 5276 long contactId1 = queryContactId(rawContactId1); 5277 updateSendToVoicemailAndRingtone(contactId1, true, "foo"); 5278 5279 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "k", "l"); 5280 long contactId2 = queryContactId(rawContactId2); 5281 updateSendToVoicemailAndRingtone(contactId2, false, "bar"); 5282 5283 // Aggregate them 5284 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 5285 rawContactId1, rawContactId2); 5286 5287 // Split them 5288 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 5289 rawContactId1, rawContactId2); 5290 5291 assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), true, "foo"); 5292 assertSendToVoicemailAndRingtone(queryContactId(rawContactId2), false, "bar"); 5293 } 5294 testMarkMetadataDirtyAfterAggregation()5295 public void testMarkMetadataDirtyAfterAggregation() { 5296 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "i", "j"); 5297 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "k", "l"); 5298 Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 5299 Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2); 5300 assertDirty(rawContactUri1, true); 5301 assertDirty(rawContactUri2, true); 5302 clearDirty(rawContactUri1); 5303 clearDirty(rawContactUri2); 5304 5305 // Aggregate them 5306 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 5307 rawContactId1, rawContactId2); 5308 5309 assertDirty(rawContactUri1, false); 5310 assertDirty(rawContactUri2, false); 5311 assertMetadataDirty(rawContactUri1, false); 5312 assertMetadataDirty(rawContactUri2, false); 5313 assertNetworkNotified(false); 5314 } 5315 testStatusUpdateInsert()5316 public void testStatusUpdateInsert() { 5317 long rawContactId = RawContactUtil.createRawContact(mResolver); 5318 Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 5319 long dataId = ContentUris.parseId(imUri); 5320 5321 ContentValues values = new ContentValues(); 5322 values.put(StatusUpdates.DATA_ID, dataId); 5323 values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM); 5324 values.putNull(StatusUpdates.CUSTOM_PROTOCOL); 5325 values.put(StatusUpdates.IM_HANDLE, "aim"); 5326 values.put(StatusUpdates.PRESENCE, StatusUpdates.INVISIBLE); 5327 values.put(StatusUpdates.STATUS, "Hiding"); 5328 values.put(StatusUpdates.STATUS_TIMESTAMP, 100); 5329 values.put(StatusUpdates.STATUS_RES_PACKAGE, "a.b.c"); 5330 values.put(StatusUpdates.STATUS_ICON, 1234); 5331 values.put(StatusUpdates.STATUS_LABEL, 2345); 5332 5333 Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values); 5334 5335 assertStoredValues(resultUri, values); 5336 5337 long contactId = queryContactId(rawContactId); 5338 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 5339 5340 values.clear(); 5341 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 5342 values.put(Contacts.CONTACT_STATUS, "Hiding"); 5343 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100); 5344 values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "a.b.c"); 5345 values.put(Contacts.CONTACT_STATUS_ICON, 1234); 5346 values.put(Contacts.CONTACT_STATUS_LABEL, 2345); 5347 5348 assertStoredValues(contactUri, values); 5349 5350 values.clear(); 5351 values.put(StatusUpdates.DATA_ID, dataId); 5352 values.put(StatusUpdates.STATUS, "Cloaked"); 5353 values.put(StatusUpdates.STATUS_TIMESTAMP, 200); 5354 values.put(StatusUpdates.STATUS_RES_PACKAGE, "d.e.f"); 5355 values.put(StatusUpdates.STATUS_ICON, 4321); 5356 values.put(StatusUpdates.STATUS_LABEL, 5432); 5357 mResolver.insert(StatusUpdates.CONTENT_URI, values); 5358 5359 values.clear(); 5360 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 5361 values.put(Contacts.CONTACT_STATUS, "Cloaked"); 5362 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 200); 5363 values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "d.e.f"); 5364 values.put(Contacts.CONTACT_STATUS_ICON, 4321); 5365 values.put(Contacts.CONTACT_STATUS_LABEL, 5432); 5366 assertStoredValues(contactUri, values); 5367 } 5368 testStatusUpdateInferAttribution()5369 public void testStatusUpdateInferAttribution() { 5370 long rawContactId = RawContactUtil.createRawContact(mResolver); 5371 Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 5372 long dataId = ContentUris.parseId(imUri); 5373 5374 ContentValues values = new ContentValues(); 5375 values.put(StatusUpdates.DATA_ID, dataId); 5376 values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM); 5377 values.put(StatusUpdates.IM_HANDLE, "aim"); 5378 values.put(StatusUpdates.STATUS, "Hiding"); 5379 5380 Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values); 5381 5382 values.clear(); 5383 values.put(StatusUpdates.DATA_ID, dataId); 5384 values.put(StatusUpdates.STATUS_LABEL, com.android.internal.R.string.imProtocolAim); 5385 values.put(StatusUpdates.STATUS, "Hiding"); 5386 5387 assertStoredValues(resultUri, values); 5388 } 5389 testStatusUpdateMatchingImOrEmail()5390 public void testStatusUpdateMatchingImOrEmail() { 5391 long rawContactId = RawContactUtil.createRawContact(mResolver); 5392 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 5393 insertImHandle(rawContactId, Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im"); 5394 insertEmail(rawContactId, "m@acme.com"); 5395 5396 // Match on IM (standard) 5397 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available", 5398 StatusUpdates.CAPABILITY_HAS_CAMERA); 5399 5400 // Match on IM (custom) 5401 insertStatusUpdate(Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im", StatusUpdates.IDLE, "Idle", 5402 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO); 5403 5404 // Match on Email 5405 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "m@acme.com", StatusUpdates.AWAY, "Away", 5406 StatusUpdates.CAPABILITY_HAS_VOICE); 5407 5408 // No match 5409 insertStatusUpdate(Im.PROTOCOL_ICQ, null, "12345", StatusUpdates.DO_NOT_DISTURB, "Go away", 5410 StatusUpdates.CAPABILITY_HAS_CAMERA); 5411 5412 Cursor c = mResolver.query(StatusUpdates.CONTENT_URI, new String[] { 5413 StatusUpdates.DATA_ID, StatusUpdates.PROTOCOL, StatusUpdates.CUSTOM_PROTOCOL, 5414 StatusUpdates.PRESENCE, StatusUpdates.STATUS}, 5415 PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null, StatusUpdates.DATA_ID); 5416 assertTrue(c.moveToNext()); 5417 assertStatusUpdate(c, Im.PROTOCOL_AIM, null, StatusUpdates.AVAILABLE, "Available"); 5418 assertTrue(c.moveToNext()); 5419 assertStatusUpdate(c, Im.PROTOCOL_CUSTOM, "my_im_proto", StatusUpdates.IDLE, "Idle"); 5420 assertTrue(c.moveToNext()); 5421 assertStatusUpdate(c, Im.PROTOCOL_GOOGLE_TALK, null, StatusUpdates.AWAY, "Away"); 5422 assertFalse(c.moveToNext()); 5423 c.close(); 5424 5425 long contactId = queryContactId(rawContactId); 5426 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 5427 5428 ContentValues values = new ContentValues(); 5429 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 5430 values.put(Contacts.CONTACT_STATUS, "Available"); 5431 assertStoredValuesWithProjection(contactUri, values); 5432 } 5433 testStatusUpdateUpdateAndDelete()5434 public void testStatusUpdateUpdateAndDelete() { 5435 long rawContactId = RawContactUtil.createRawContact(mResolver); 5436 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 5437 5438 long contactId = queryContactId(rawContactId); 5439 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 5440 5441 ContentValues values = new ContentValues(); 5442 values.putNull(Contacts.CONTACT_PRESENCE); 5443 values.putNull(Contacts.CONTACT_STATUS); 5444 assertStoredValuesWithProjection(contactUri, values); 5445 5446 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AWAY, "BUSY", 5447 StatusUpdates.CAPABILITY_HAS_CAMERA); 5448 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.DO_NOT_DISTURB, "GO AWAY", 5449 StatusUpdates.CAPABILITY_HAS_CAMERA); 5450 Uri statusUri = 5451 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available", 5452 StatusUpdates.CAPABILITY_HAS_CAMERA); 5453 long statusId = ContentUris.parseId(statusUri); 5454 5455 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 5456 values.put(Contacts.CONTACT_STATUS, "Available"); 5457 assertStoredValuesWithProjection(contactUri, values); 5458 5459 // update status_updates table to set new values for 5460 // status_updates.status 5461 // status_updates.status_ts 5462 // presence 5463 long updatedTs = 200; 5464 String testUpdate = "test_update"; 5465 String selection = StatusUpdates.DATA_ID + "=" + statusId; 5466 values.clear(); 5467 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 5468 values.put(StatusUpdates.STATUS, testUpdate); 5469 values.put(StatusUpdates.PRESENCE, "presence_test"); 5470 mResolver.update(StatusUpdates.CONTENT_URI, values, 5471 StatusUpdates.DATA_ID + "=" + statusId, null); 5472 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 5473 5474 // update status_updates table to set new values for columns in status_updates table ONLY 5475 // i.e., no rows in presence table are to be updated. 5476 updatedTs = 300; 5477 testUpdate = "test_update_new"; 5478 selection = StatusUpdates.DATA_ID + "=" + statusId; 5479 values.clear(); 5480 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 5481 values.put(StatusUpdates.STATUS, testUpdate); 5482 mResolver.update(StatusUpdates.CONTENT_URI, values, 5483 StatusUpdates.DATA_ID + "=" + statusId, null); 5484 // make sure the presence column value is still the old value 5485 values.put(StatusUpdates.PRESENCE, "presence_test"); 5486 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 5487 5488 // update status_updates table to set new values for columns in presence table ONLY 5489 // i.e., no rows in status_updates table are to be updated. 5490 selection = StatusUpdates.DATA_ID + "=" + statusId; 5491 values.clear(); 5492 values.put(StatusUpdates.PRESENCE, "presence_test_new"); 5493 mResolver.update(StatusUpdates.CONTENT_URI, values, 5494 StatusUpdates.DATA_ID + "=" + statusId, null); 5495 // make sure the status_updates table is not updated 5496 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 5497 values.put(StatusUpdates.STATUS, testUpdate); 5498 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 5499 5500 // effect "delete status_updates" operation and expect the following 5501 // data deleted from status_updates table 5502 // presence set to null 5503 mResolver.delete(StatusUpdates.CONTENT_URI, StatusUpdates.DATA_ID + "=" + statusId, null); 5504 values.clear(); 5505 values.putNull(Contacts.CONTACT_PRESENCE); 5506 assertStoredValuesWithProjection(contactUri, values); 5507 } 5508 testStatusUpdateUpdateToNull()5509 public void testStatusUpdateUpdateToNull() { 5510 long rawContactId = RawContactUtil.createRawContact(mResolver); 5511 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 5512 5513 long contactId = queryContactId(rawContactId); 5514 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 5515 5516 ContentValues values = new ContentValues(); 5517 Uri statusUri = 5518 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available", 5519 StatusUpdates.CAPABILITY_HAS_CAMERA); 5520 long statusId = ContentUris.parseId(statusUri); 5521 5522 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 5523 values.put(Contacts.CONTACT_STATUS, "Available"); 5524 assertStoredValuesWithProjection(contactUri, values); 5525 5526 values.clear(); 5527 values.putNull(StatusUpdates.PRESENCE); 5528 mResolver.update(StatusUpdates.CONTENT_URI, values, 5529 StatusUpdates.DATA_ID + "=" + statusId, null); 5530 5531 values.clear(); 5532 values.putNull(Contacts.CONTACT_PRESENCE); 5533 values.put(Contacts.CONTACT_STATUS, "Available"); 5534 assertStoredValuesWithProjection(contactUri, values); 5535 } 5536 testStatusUpdateWithTimestamp()5537 public void testStatusUpdateWithTimestamp() { 5538 long rawContactId = RawContactUtil.createRawContact(mResolver); 5539 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 5540 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk"); 5541 5542 long contactId = queryContactId(rawContactId); 5543 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 5544 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Offline", 80, 5545 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 5546 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Available", 100, 5547 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 5548 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", 0, "Busy", 90, 5549 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 5550 5551 // Should return the latest status 5552 ContentValues values = new ContentValues(); 5553 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100); 5554 values.put(Contacts.CONTACT_STATUS, "Available"); 5555 assertStoredValuesWithProjection(contactUri, values); 5556 } 5557 assertStatusUpdate(Cursor c, int protocol, String customProtocol, int presence, String status)5558 private void assertStatusUpdate(Cursor c, int protocol, String customProtocol, int presence, 5559 String status) { 5560 ContentValues values = new ContentValues(); 5561 values.put(StatusUpdates.PROTOCOL, protocol); 5562 values.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 5563 values.put(StatusUpdates.PRESENCE, presence); 5564 values.put(StatusUpdates.STATUS, status); 5565 assertCursorValues(c, values); 5566 } 5567 5568 // Stream item query test cases. 5569 testQueryStreamItemsByRawContactId()5570 public void testQueryStreamItemsByRawContactId() { 5571 long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 5572 ContentValues values = buildGenericStreamItemValues(); 5573 insertStreamItem(rawContactId, values, mAccount); 5574 assertStoredValues( 5575 Uri.withAppendedPath( 5576 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 5577 RawContacts.StreamItems.CONTENT_DIRECTORY), 5578 values); 5579 } 5580 testQueryStreamItemsByContactId()5581 public void testQueryStreamItemsByContactId() { 5582 long rawContactId = RawContactUtil.createRawContact(mResolver); 5583 long contactId = queryContactId(rawContactId); 5584 ContentValues values = buildGenericStreamItemValues(); 5585 insertStreamItem(rawContactId, values, null); 5586 assertStoredValues( 5587 Uri.withAppendedPath( 5588 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 5589 Contacts.StreamItems.CONTENT_DIRECTORY), 5590 values); 5591 } 5592 testQueryStreamItemsByLookupKey()5593 public void testQueryStreamItemsByLookupKey() { 5594 long rawContactId = RawContactUtil.createRawContact(mResolver); 5595 long contactId = queryContactId(rawContactId); 5596 String lookupKey = queryLookupKey(contactId); 5597 ContentValues values = buildGenericStreamItemValues(); 5598 insertStreamItem(rawContactId, values, null); 5599 assertStoredValues( 5600 Uri.withAppendedPath( 5601 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), 5602 Contacts.StreamItems.CONTENT_DIRECTORY), 5603 values); 5604 } 5605 testQueryStreamItemsByLookupKeyAndContactId()5606 public void testQueryStreamItemsByLookupKeyAndContactId() { 5607 long rawContactId = RawContactUtil.createRawContact(mResolver); 5608 long contactId = queryContactId(rawContactId); 5609 String lookupKey = queryLookupKey(contactId); 5610 ContentValues values = buildGenericStreamItemValues(); 5611 insertStreamItem(rawContactId, values, null); 5612 assertStoredValues( 5613 Uri.withAppendedPath( 5614 ContentUris.withAppendedId( 5615 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), 5616 contactId), 5617 Contacts.StreamItems.CONTENT_DIRECTORY), 5618 values); 5619 } 5620 testQueryStreamItems()5621 public void testQueryStreamItems() { 5622 long rawContactId = RawContactUtil.createRawContact(mResolver); 5623 ContentValues values = buildGenericStreamItemValues(); 5624 insertStreamItem(rawContactId, values, null); 5625 assertStoredValues(StreamItems.CONTENT_URI, values); 5626 } 5627 testQueryStreamItemsWithSelection()5628 public void testQueryStreamItemsWithSelection() { 5629 long rawContactId = RawContactUtil.createRawContact(mResolver); 5630 ContentValues firstValues = buildGenericStreamItemValues(); 5631 insertStreamItem(rawContactId, firstValues, null); 5632 5633 ContentValues secondValues = buildGenericStreamItemValues(); 5634 secondValues.put(StreamItems.TEXT, "Goodbye world"); 5635 insertStreamItem(rawContactId, secondValues, null); 5636 5637 // Select only the first stream item. 5638 assertStoredValues(StreamItems.CONTENT_URI, StreamItems.TEXT + "=?", 5639 new String[]{"Hello world"}, firstValues); 5640 5641 // Select only the second stream item. 5642 assertStoredValues(StreamItems.CONTENT_URI, StreamItems.TEXT + "=?", 5643 new String[]{"Goodbye world"}, secondValues); 5644 } 5645 testQueryStreamItemById()5646 public void testQueryStreamItemById() { 5647 long rawContactId = RawContactUtil.createRawContact(mResolver); 5648 ContentValues firstValues = buildGenericStreamItemValues(); 5649 Uri resultUri = insertStreamItem(rawContactId, firstValues, null); 5650 long firstStreamItemId = ContentUris.parseId(resultUri); 5651 5652 ContentValues secondValues = buildGenericStreamItemValues(); 5653 secondValues.put(StreamItems.TEXT, "Goodbye world"); 5654 resultUri = insertStreamItem(rawContactId, secondValues, null); 5655 long secondStreamItemId = ContentUris.parseId(resultUri); 5656 5657 // Select only the first stream item. 5658 assertStoredValues(ContentUris.withAppendedId(StreamItems.CONTENT_URI, firstStreamItemId), 5659 firstValues); 5660 5661 // Select only the second stream item. 5662 assertStoredValues(ContentUris.withAppendedId(StreamItems.CONTENT_URI, secondStreamItemId), 5663 secondValues); 5664 } 5665 5666 // Stream item photo insertion + query test cases. 5667 testQueryStreamItemPhotoWithSelection()5668 public void testQueryStreamItemPhotoWithSelection() { 5669 long rawContactId = RawContactUtil.createRawContact(mResolver); 5670 ContentValues values = buildGenericStreamItemValues(); 5671 Uri resultUri = insertStreamItem(rawContactId, values, null); 5672 long streamItemId = ContentUris.parseId(resultUri); 5673 5674 ContentValues photo1Values = buildGenericStreamItemPhotoValues(1); 5675 insertStreamItemPhoto(streamItemId, photo1Values, null); 5676 photo1Values.remove(StreamItemPhotos.PHOTO); // Removed during processing. 5677 ContentValues photo2Values = buildGenericStreamItemPhotoValues(2); 5678 insertStreamItemPhoto(streamItemId, photo2Values, null); 5679 5680 // Select only the first photo. 5681 assertStoredValues(StreamItems.CONTENT_PHOTO_URI, StreamItemPhotos.SORT_INDEX + "=?", 5682 new String[]{"1"}, photo1Values); 5683 } 5684 testQueryStreamItemPhotoByStreamItemId()5685 public void testQueryStreamItemPhotoByStreamItemId() { 5686 long rawContactId = RawContactUtil.createRawContact(mResolver); 5687 5688 // Insert a first stream item. 5689 ContentValues firstValues = buildGenericStreamItemValues(); 5690 Uri resultUri = insertStreamItem(rawContactId, firstValues, null); 5691 long firstStreamItemId = ContentUris.parseId(resultUri); 5692 5693 // Insert a second stream item. 5694 ContentValues secondValues = buildGenericStreamItemValues(); 5695 resultUri = insertStreamItem(rawContactId, secondValues, null); 5696 long secondStreamItemId = ContentUris.parseId(resultUri); 5697 5698 // Add a photo to the first stream item. 5699 ContentValues photo1Values = buildGenericStreamItemPhotoValues(1); 5700 insertStreamItemPhoto(firstStreamItemId, photo1Values, null); 5701 photo1Values.remove(StreamItemPhotos.PHOTO); // Removed during processing. 5702 5703 // Add a photo to the second stream item. 5704 ContentValues photo2Values = buildGenericStreamItemPhotoValues(1); 5705 photo2Values.put(StreamItemPhotos.PHOTO, loadPhotoFromResource( 5706 R.drawable.nebula, PhotoSize.ORIGINAL)); 5707 insertStreamItemPhoto(secondStreamItemId, photo2Values, null); 5708 photo2Values.remove(StreamItemPhotos.PHOTO); // Removed during processing. 5709 5710 // Select only the photos from the second stream item. 5711 assertStoredValues(Uri.withAppendedPath( 5712 ContentUris.withAppendedId(StreamItems.CONTENT_URI, secondStreamItemId), 5713 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), photo2Values); 5714 } 5715 testQueryStreamItemPhotoByStreamItemPhotoId()5716 public void testQueryStreamItemPhotoByStreamItemPhotoId() { 5717 long rawContactId = RawContactUtil.createRawContact(mResolver); 5718 5719 // Insert a first stream item. 5720 ContentValues firstValues = buildGenericStreamItemValues(); 5721 Uri resultUri = insertStreamItem(rawContactId, firstValues, null); 5722 long firstStreamItemId = ContentUris.parseId(resultUri); 5723 5724 // Insert a second stream item. 5725 ContentValues secondValues = buildGenericStreamItemValues(); 5726 resultUri = insertStreamItem(rawContactId, secondValues, null); 5727 long secondStreamItemId = ContentUris.parseId(resultUri); 5728 5729 // Add a photo to the first stream item. 5730 ContentValues photo1Values = buildGenericStreamItemPhotoValues(1); 5731 resultUri = insertStreamItemPhoto(firstStreamItemId, photo1Values, null); 5732 long firstPhotoId = ContentUris.parseId(resultUri); 5733 photo1Values.remove(StreamItemPhotos.PHOTO); // Removed during processing. 5734 5735 // Add a photo to the second stream item. 5736 ContentValues photo2Values = buildGenericStreamItemPhotoValues(1); 5737 photo2Values.put(StreamItemPhotos.PHOTO, loadPhotoFromResource( 5738 R.drawable.galaxy, PhotoSize.ORIGINAL)); 5739 resultUri = insertStreamItemPhoto(secondStreamItemId, photo2Values, null); 5740 long secondPhotoId = ContentUris.parseId(resultUri); 5741 photo2Values.remove(StreamItemPhotos.PHOTO); // Removed during processing. 5742 5743 // Select the first photo. 5744 assertStoredValues(ContentUris.withAppendedId( 5745 Uri.withAppendedPath( 5746 ContentUris.withAppendedId(StreamItems.CONTENT_URI, firstStreamItemId), 5747 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 5748 firstPhotoId), 5749 photo1Values); 5750 5751 // Select the second photo. 5752 assertStoredValues(ContentUris.withAppendedId( 5753 Uri.withAppendedPath( 5754 ContentUris.withAppendedId(StreamItems.CONTENT_URI, secondStreamItemId), 5755 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 5756 secondPhotoId), 5757 photo2Values); 5758 } 5759 5760 // Stream item insertion test cases. 5761 testInsertStreamItemInProfileRequiresWriteProfileAccess()5762 public void testInsertStreamItemInProfileRequiresWriteProfileAccess() { 5763 long profileRawContactId = createBasicProfileContact(new ContentValues()); 5764 5765 // Try inserting a stream item. It should still succeed even without the profile permission. 5766 ContentValues values = buildGenericStreamItemValues(); 5767 insertStreamItem(profileRawContactId, values, null); 5768 } 5769 testInsertStreamItemWithContentValues()5770 public void testInsertStreamItemWithContentValues() { 5771 long rawContactId = RawContactUtil.createRawContact(mResolver); 5772 ContentValues values = buildGenericStreamItemValues(); 5773 values.put(StreamItems.RAW_CONTACT_ID, rawContactId); 5774 mResolver.insert(StreamItems.CONTENT_URI, values); 5775 assertStoredValues(Uri.withAppendedPath( 5776 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 5777 RawContacts.StreamItems.CONTENT_DIRECTORY), values); 5778 } 5779 testInsertStreamItemOverLimit()5780 public void testInsertStreamItemOverLimit() { 5781 long rawContactId = RawContactUtil.createRawContact(mResolver); 5782 ContentValues values = buildGenericStreamItemValues(); 5783 values.put(StreamItems.RAW_CONTACT_ID, rawContactId); 5784 5785 List<Long> streamItemIds = Lists.newArrayList(); 5786 5787 // Insert MAX + 1 stream items. 5788 long baseTime = System.currentTimeMillis(); 5789 for (int i = 0; i < 6; i++) { 5790 values.put(StreamItems.TIMESTAMP, baseTime + i); 5791 Uri resultUri = mResolver.insert(StreamItems.CONTENT_URI, values); 5792 streamItemIds.add(ContentUris.parseId(resultUri)); 5793 } 5794 Long doomedStreamItemId = streamItemIds.get(0); 5795 5796 // There should only be MAX items. The oldest one should have been cleaned up. 5797 Cursor c = mResolver.query( 5798 Uri.withAppendedPath( 5799 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 5800 RawContacts.StreamItems.CONTENT_DIRECTORY), 5801 new String[]{StreamItems._ID}, null, null, null); 5802 try { 5803 while(c.moveToNext()) { 5804 long streamItemId = c.getLong(0); 5805 streamItemIds.remove(streamItemId); 5806 } 5807 } finally { 5808 c.close(); 5809 } 5810 5811 assertEquals(1, streamItemIds.size()); 5812 } 5813 testInsertStreamItemOlderThanOldestInLimit()5814 public void testInsertStreamItemOlderThanOldestInLimit() { 5815 long rawContactId = RawContactUtil.createRawContact(mResolver); 5816 ContentValues values = buildGenericStreamItemValues(); 5817 values.put(StreamItems.RAW_CONTACT_ID, rawContactId); 5818 5819 // Insert MAX stream items. 5820 long baseTime = System.currentTimeMillis(); 5821 for (int i = 0; i < 5; i++) { 5822 values.put(StreamItems.TIMESTAMP, baseTime + i); 5823 Uri resultUri = mResolver.insert(StreamItems.CONTENT_URI, values); 5824 assertNotSame("Expected non-0 stream item ID to be inserted", 5825 0L, ContentUris.parseId(resultUri)); 5826 } 5827 5828 // Now try to insert a stream item that's older. It should be deleted immediately 5829 // and return an ID of 0. 5830 values.put(StreamItems.TIMESTAMP, baseTime - 1); 5831 Uri resultUri = mResolver.insert(StreamItems.CONTENT_URI, values); 5832 assertEquals(0L, ContentUris.parseId(resultUri)); 5833 } 5834 5835 // Stream item photo insertion test cases. 5836 testInsertStreamItemsAndPhotosInBatch()5837 public void testInsertStreamItemsAndPhotosInBatch() throws Exception { 5838 long rawContactId = RawContactUtil.createRawContact(mResolver); 5839 ContentValues streamItemValues = buildGenericStreamItemValues(); 5840 ContentValues streamItemPhotoValues = buildGenericStreamItemPhotoValues(0); 5841 5842 ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 5843 ops.add(ContentProviderOperation.newInsert( 5844 Uri.withAppendedPath( 5845 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 5846 RawContacts.StreamItems.CONTENT_DIRECTORY)) 5847 .withValues(streamItemValues).build()); 5848 for (int i = 0; i < 5; i++) { 5849 streamItemPhotoValues.put(StreamItemPhotos.SORT_INDEX, i); 5850 ops.add(ContentProviderOperation.newInsert(StreamItems.CONTENT_PHOTO_URI) 5851 .withValues(streamItemPhotoValues) 5852 .withValueBackReference(StreamItemPhotos.STREAM_ITEM_ID, 0) 5853 .build()); 5854 } 5855 mResolver.applyBatch(ContactsContract.AUTHORITY, ops); 5856 5857 // Check that all five photos were inserted under the raw contact. 5858 Cursor c = mResolver.query(StreamItems.CONTENT_URI, new String[]{StreamItems._ID}, 5859 StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 5860 null); 5861 long streamItemId = 0; 5862 try { 5863 assertEquals(1, c.getCount()); 5864 c.moveToFirst(); 5865 streamItemId = c.getLong(0); 5866 } finally { 5867 c.close(); 5868 } 5869 5870 c = mResolver.query(Uri.withAppendedPath( 5871 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 5872 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 5873 new String[]{StreamItemPhotos._ID, StreamItemPhotos.PHOTO_URI}, 5874 null, null, null); 5875 try { 5876 assertEquals(5, c.getCount()); 5877 byte[] expectedPhotoBytes = loadPhotoFromResource( 5878 R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO); 5879 while (c.moveToNext()) { 5880 String photoUri = c.getString(1); 5881 EvenMoreAsserts.assertImageRawData(getContext(), 5882 expectedPhotoBytes, mResolver.openInputStream(Uri.parse(photoUri))); 5883 } 5884 } finally { 5885 c.close(); 5886 } 5887 } 5888 5889 // Stream item update test cases. 5890 testUpdateStreamItemById()5891 public void testUpdateStreamItemById() { 5892 long rawContactId = RawContactUtil.createRawContact(mResolver); 5893 ContentValues values = buildGenericStreamItemValues(); 5894 Uri resultUri = insertStreamItem(rawContactId, values, null); 5895 long streamItemId = ContentUris.parseId(resultUri); 5896 values.put(StreamItems.TEXT, "Goodbye world"); 5897 mResolver.update(ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), values, 5898 null, null); 5899 assertStoredValues(Uri.withAppendedPath( 5900 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 5901 RawContacts.StreamItems.CONTENT_DIRECTORY), values); 5902 } 5903 testUpdateStreamItemWithContentValues()5904 public void testUpdateStreamItemWithContentValues() { 5905 long rawContactId = RawContactUtil.createRawContact(mResolver); 5906 ContentValues values = buildGenericStreamItemValues(); 5907 Uri resultUri = insertStreamItem(rawContactId, values, null); 5908 long streamItemId = ContentUris.parseId(resultUri); 5909 values.put(StreamItems._ID, streamItemId); 5910 values.put(StreamItems.TEXT, "Goodbye world"); 5911 mResolver.update(StreamItems.CONTENT_URI, values, null, null); 5912 assertStoredValues(Uri.withAppendedPath( 5913 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 5914 RawContacts.StreamItems.CONTENT_DIRECTORY), values); 5915 } 5916 5917 // Stream item photo update test cases. 5918 testUpdateStreamItemPhotoById()5919 public void testUpdateStreamItemPhotoById() throws IOException { 5920 long rawContactId = RawContactUtil.createRawContact(mResolver); 5921 ContentValues values = buildGenericStreamItemValues(); 5922 Uri resultUri = insertStreamItem(rawContactId, values, null); 5923 long streamItemId = ContentUris.parseId(resultUri); 5924 ContentValues photoValues = buildGenericStreamItemPhotoValues(1); 5925 resultUri = insertStreamItemPhoto(streamItemId, photoValues, null); 5926 long streamItemPhotoId = ContentUris.parseId(resultUri); 5927 5928 photoValues.put(StreamItemPhotos.PHOTO, loadPhotoFromResource( 5929 R.drawable.nebula, PhotoSize.ORIGINAL)); 5930 Uri photoUri = 5931 ContentUris.withAppendedId( 5932 Uri.withAppendedPath( 5933 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 5934 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 5935 streamItemPhotoId); 5936 mResolver.update(photoUri, photoValues, null, null); 5937 photoValues.remove(StreamItemPhotos.PHOTO); // Removed during processing. 5938 assertStoredValues(photoUri, photoValues); 5939 5940 // Check that the photo stored is the expected one. 5941 String displayPhotoUri = getStoredValue(photoUri, StreamItemPhotos.PHOTO_URI); 5942 EvenMoreAsserts.assertImageRawData(getContext(), 5943 loadPhotoFromResource(R.drawable.nebula, PhotoSize.DISPLAY_PHOTO), 5944 mResolver.openInputStream(Uri.parse(displayPhotoUri))); 5945 } 5946 testUpdateStreamItemPhotoWithContentValues()5947 public void testUpdateStreamItemPhotoWithContentValues() throws IOException { 5948 long rawContactId = RawContactUtil.createRawContact(mResolver); 5949 ContentValues values = buildGenericStreamItemValues(); 5950 Uri resultUri = insertStreamItem(rawContactId, values, null); 5951 long streamItemId = ContentUris.parseId(resultUri); 5952 ContentValues photoValues = buildGenericStreamItemPhotoValues(1); 5953 resultUri = insertStreamItemPhoto(streamItemId, photoValues, null); 5954 long streamItemPhotoId = ContentUris.parseId(resultUri); 5955 5956 photoValues.put(StreamItemPhotos._ID, streamItemPhotoId); 5957 photoValues.put(StreamItemPhotos.PHOTO, loadPhotoFromResource( 5958 R.drawable.nebula, PhotoSize.ORIGINAL)); 5959 Uri photoUri = 5960 Uri.withAppendedPath( 5961 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 5962 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY); 5963 mResolver.update(photoUri, photoValues, null, null); 5964 photoValues.remove(StreamItemPhotos.PHOTO); // Removed during processing. 5965 assertStoredValues(photoUri, photoValues); 5966 5967 // Check that the photo stored is the expected one. 5968 String displayPhotoUri = getStoredValue(photoUri, StreamItemPhotos.PHOTO_URI); 5969 EvenMoreAsserts.assertImageRawData(getContext(), 5970 loadPhotoFromResource(R.drawable.nebula, PhotoSize.DISPLAY_PHOTO), 5971 mResolver.openInputStream(Uri.parse(displayPhotoUri))); 5972 } 5973 5974 // Stream item deletion test cases. 5975 testDeleteStreamItemById()5976 public void testDeleteStreamItemById() { 5977 long rawContactId = RawContactUtil.createRawContact(mResolver); 5978 ContentValues firstValues = buildGenericStreamItemValues(); 5979 Uri resultUri = insertStreamItem(rawContactId, firstValues, null); 5980 long firstStreamItemId = ContentUris.parseId(resultUri); 5981 5982 ContentValues secondValues = buildGenericStreamItemValues(); 5983 secondValues.put(StreamItems.TEXT, "Goodbye world"); 5984 insertStreamItem(rawContactId, secondValues, null); 5985 5986 // Delete the first stream item. 5987 mResolver.delete(ContentUris.withAppendedId(StreamItems.CONTENT_URI, firstStreamItemId), 5988 null, null); 5989 5990 // Check that only the second item remains. 5991 assertStoredValues(Uri.withAppendedPath( 5992 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 5993 RawContacts.StreamItems.CONTENT_DIRECTORY), secondValues); 5994 } 5995 testDeleteStreamItemWithSelection()5996 public void testDeleteStreamItemWithSelection() { 5997 long rawContactId = RawContactUtil.createRawContact(mResolver); 5998 ContentValues firstValues = buildGenericStreamItemValues(); 5999 insertStreamItem(rawContactId, firstValues, null); 6000 6001 ContentValues secondValues = buildGenericStreamItemValues(); 6002 secondValues.put(StreamItems.TEXT, "Goodbye world"); 6003 insertStreamItem(rawContactId, secondValues, null); 6004 6005 // Delete the first stream item with a custom selection. 6006 mResolver.delete(StreamItems.CONTENT_URI, StreamItems.TEXT + "=?", 6007 new String[]{"Hello world"}); 6008 6009 // Check that only the second item remains. 6010 assertStoredValues(Uri.withAppendedPath( 6011 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 6012 RawContacts.StreamItems.CONTENT_DIRECTORY), secondValues); 6013 } 6014 6015 // Stream item photo deletion test cases. 6016 testDeleteStreamItemPhotoById()6017 public void testDeleteStreamItemPhotoById() { 6018 long rawContactId = RawContactUtil.createRawContact(mResolver); 6019 long streamItemId = ContentUris.parseId( 6020 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null)); 6021 long streamItemPhotoId = ContentUris.parseId( 6022 insertStreamItemPhoto(streamItemId, buildGenericStreamItemPhotoValues(0), null)); 6023 mResolver.delete( 6024 ContentUris.withAppendedId( 6025 Uri.withAppendedPath( 6026 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 6027 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 6028 streamItemPhotoId), null, null); 6029 6030 Cursor c = mResolver.query(StreamItems.CONTENT_PHOTO_URI, 6031 new String[]{StreamItemPhotos._ID}, 6032 StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{String.valueOf(streamItemId)}, 6033 null); 6034 try { 6035 assertEquals("Expected photo to be deleted.", 0, c.getCount()); 6036 } finally { 6037 c.close(); 6038 } 6039 } 6040 testDeleteStreamItemPhotoWithSelection()6041 public void testDeleteStreamItemPhotoWithSelection() { 6042 long rawContactId = RawContactUtil.createRawContact(mResolver); 6043 long streamItemId = ContentUris.parseId( 6044 insertStreamItem(rawContactId, buildGenericStreamItemValues(), null)); 6045 ContentValues firstPhotoValues = buildGenericStreamItemPhotoValues(0); 6046 ContentValues secondPhotoValues = buildGenericStreamItemPhotoValues(1); 6047 insertStreamItemPhoto(streamItemId, firstPhotoValues, null); 6048 firstPhotoValues.remove(StreamItemPhotos.PHOTO); // Removed while processing. 6049 insertStreamItemPhoto(streamItemId, secondPhotoValues, null); 6050 Uri photoUri = Uri.withAppendedPath( 6051 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 6052 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY); 6053 mResolver.delete(photoUri, StreamItemPhotos.SORT_INDEX + "=1", null); 6054 6055 assertStoredValues(photoUri, firstPhotoValues); 6056 } 6057 testDeleteStreamItemsWhenRawContactDeleted()6058 public void testDeleteStreamItemsWhenRawContactDeleted() { 6059 long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6060 Uri streamItemUri = insertStreamItem(rawContactId, 6061 buildGenericStreamItemValues(), mAccount); 6062 Uri streamItemPhotoUri = insertStreamItemPhoto(ContentUris.parseId(streamItemUri), 6063 buildGenericStreamItemPhotoValues(0), mAccount); 6064 mResolver.delete(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 6065 null, null); 6066 6067 ContentValues[] emptyValues = new ContentValues[0]; 6068 6069 // The stream item and its photo should be gone. 6070 assertStoredValues(streamItemUri, emptyValues); 6071 assertStoredValues(streamItemPhotoUri, emptyValues); 6072 } 6073 testQueryStreamItemLimit()6074 public void testQueryStreamItemLimit() { 6075 ContentValues values = new ContentValues(); 6076 values.put(StreamItems.MAX_ITEMS, 5); 6077 assertStoredValues(StreamItems.CONTENT_LIMIT_URI, values); 6078 } 6079 6080 // Tests for inserting or updating stream items as a side-effect of making status updates 6081 // (forward-compatibility of status updates into the new social stream API). 6082 testStreamItemInsertedOnStatusUpdate()6083 public void testStreamItemInsertedOnStatusUpdate() { 6084 6085 // This method of creating a raw contact automatically inserts a status update with 6086 // the status message "hacking". 6087 ContentValues values = new ContentValues(); 6088 long rawContactId = createRawContact(values, "18004664411", 6089 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 6090 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 6091 StatusUpdates.CAPABILITY_HAS_VOICE); 6092 6093 ContentValues expectedValues = new ContentValues(); 6094 expectedValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 6095 expectedValues.put(StreamItems.TEXT, "hacking"); 6096 assertStoredValues(RawContacts.CONTENT_URI.buildUpon() 6097 .appendPath(String.valueOf(rawContactId)) 6098 .appendPath(RawContacts.StreamItems.CONTENT_DIRECTORY).build(), 6099 expectedValues); 6100 } 6101 testStreamItemInsertedOnStatusUpdate_HtmlQuoting()6102 public void testStreamItemInsertedOnStatusUpdate_HtmlQuoting() { 6103 6104 // This method of creating a raw contact automatically inserts a status update with 6105 // the status message "hacking". 6106 ContentValues values = new ContentValues(); 6107 long rawContactId = createRawContact(values, "18004664411", 6108 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 6109 StatusUpdates.CAPABILITY_HAS_VOICE); 6110 6111 // Insert a new status update for the raw contact. 6112 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog411@acme.com", 6113 StatusUpdates.INVISIBLE, "& <b> test '", StatusUpdates.CAPABILITY_HAS_VOICE); 6114 6115 ContentValues expectedValues = new ContentValues(); 6116 expectedValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 6117 expectedValues.put(StreamItems.TEXT, "& <b> test &#39;"); 6118 assertStoredValues(RawContacts.CONTENT_URI.buildUpon() 6119 .appendPath(String.valueOf(rawContactId)) 6120 .appendPath(RawContacts.StreamItems.CONTENT_DIRECTORY).build(), 6121 expectedValues); 6122 } 6123 testStreamItemUpdatedOnSecondStatusUpdate()6124 public void testStreamItemUpdatedOnSecondStatusUpdate() { 6125 6126 // This method of creating a raw contact automatically inserts a status update with 6127 // the status message "hacking". 6128 ContentValues values = new ContentValues(); 6129 int chatMode = StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 6130 StatusUpdates.CAPABILITY_HAS_VOICE; 6131 long rawContactId = createRawContact(values, "18004664411", 6132 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, chatMode); 6133 6134 // Insert a new status update for the raw contact. 6135 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog411@acme.com", 6136 StatusUpdates.INVISIBLE, "finished hacking", chatMode); 6137 6138 ContentValues expectedValues = new ContentValues(); 6139 expectedValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 6140 expectedValues.put(StreamItems.TEXT, "finished hacking"); 6141 assertStoredValues(RawContacts.CONTENT_URI.buildUpon() 6142 .appendPath(String.valueOf(rawContactId)) 6143 .appendPath(RawContacts.StreamItems.CONTENT_DIRECTORY).build(), 6144 expectedValues); 6145 } 6146 buildGenericStreamItemValues()6147 private ContentValues buildGenericStreamItemValues() { 6148 ContentValues values = new ContentValues(); 6149 values.put(StreamItems.TEXT, "Hello world"); 6150 values.put(StreamItems.TIMESTAMP, System.currentTimeMillis()); 6151 values.put(StreamItems.COMMENTS, "Reshared by 123 others"); 6152 return values; 6153 } 6154 buildGenericStreamItemPhotoValues(int sortIndex)6155 private ContentValues buildGenericStreamItemPhotoValues(int sortIndex) { 6156 ContentValues values = new ContentValues(); 6157 values.put(StreamItemPhotos.SORT_INDEX, sortIndex); 6158 values.put(StreamItemPhotos.PHOTO, 6159 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.ORIGINAL)); 6160 return values; 6161 } 6162 testSingleStatusUpdateRowPerContact()6163 public void testSingleStatusUpdateRowPerContact() { 6164 int protocol1 = Im.PROTOCOL_GOOGLE_TALK; 6165 String handle1 = "test@gmail.com"; 6166 6167 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 6168 insertImHandle(rawContactId1, protocol1, null, handle1); 6169 6170 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AVAILABLE, "Green", 6171 StatusUpdates.CAPABILITY_HAS_CAMERA); 6172 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AWAY, "Yellow", 6173 StatusUpdates.CAPABILITY_HAS_CAMERA); 6174 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.INVISIBLE, "Red", 6175 StatusUpdates.CAPABILITY_HAS_CAMERA); 6176 6177 Cursor c = queryContact(queryContactId(rawContactId1), 6178 new String[] {Contacts.CONTACT_PRESENCE, Contacts.CONTACT_STATUS}); 6179 assertEquals(1, c.getCount()); 6180 6181 c.moveToFirst(); 6182 assertEquals(StatusUpdates.INVISIBLE, c.getInt(0)); 6183 assertEquals("Red", c.getString(1)); 6184 c.close(); 6185 } 6186 updateSendToVoicemailAndRingtone(long contactId, boolean sendToVoicemail, String ringtone)6187 private void updateSendToVoicemailAndRingtone(long contactId, boolean sendToVoicemail, 6188 String ringtone) { 6189 ContentValues values = new ContentValues(); 6190 values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail); 6191 if (ringtone != null) { 6192 values.put(Contacts.CUSTOM_RINGTONE, ringtone); 6193 } 6194 6195 final Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 6196 int count = mResolver.update(uri, values, null, null); 6197 assertEquals(1, count); 6198 } 6199 updateSendToVoicemailAndRingtoneWithSelection(long contactId, boolean sendToVoicemail, String ringtone)6200 private void updateSendToVoicemailAndRingtoneWithSelection(long contactId, 6201 boolean sendToVoicemail, String ringtone) { 6202 ContentValues values = new ContentValues(); 6203 values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail); 6204 if (ringtone != null) { 6205 values.put(Contacts.CUSTOM_RINGTONE, ringtone); 6206 } 6207 6208 int count = mResolver.update(Contacts.CONTENT_URI, values, Contacts._ID + "=" + contactId, 6209 null); 6210 assertEquals(1, count); 6211 } 6212 assertSendToVoicemailAndRingtone(long contactId, boolean expectedSendToVoicemail, String expectedRingtone)6213 private void assertSendToVoicemailAndRingtone(long contactId, boolean expectedSendToVoicemail, 6214 String expectedRingtone) { 6215 Cursor c = queryContact(contactId); 6216 assertTrue(c.moveToNext()); 6217 int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL)); 6218 assertEquals(expectedSendToVoicemail ? 1 : 0, sendToVoicemail); 6219 String ringtone = c.getString(c.getColumnIndex(Contacts.CUSTOM_RINGTONE)); 6220 if (expectedRingtone == null) { 6221 assertNull(ringtone); 6222 } else { 6223 assertTrue(ArrayUtils.contains(expectedRingtone.split(","), ringtone)); 6224 } 6225 c.close(); 6226 } 6227 testContactVisibilityUpdateOnMembershipChange()6228 public void testContactVisibilityUpdateOnMembershipChange() { 6229 long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6230 assertVisibility(rawContactId, "0"); 6231 6232 long visibleGroupId = createGroup(mAccount, "123", "Visible", 1); 6233 long invisibleGroupId = createGroup(mAccount, "567", "Invisible", 0); 6234 6235 Uri membership1 = insertGroupMembership(rawContactId, visibleGroupId); 6236 assertVisibility(rawContactId, "1"); 6237 6238 Uri membership2 = insertGroupMembership(rawContactId, invisibleGroupId); 6239 assertVisibility(rawContactId, "1"); 6240 6241 mResolver.delete(membership1, null, null); 6242 assertVisibility(rawContactId, "0"); 6243 6244 ContentValues values = new ContentValues(); 6245 values.put(GroupMembership.GROUP_ROW_ID, visibleGroupId); 6246 6247 mResolver.update(membership2, values, null, null); 6248 assertVisibility(rawContactId, "1"); 6249 } 6250 assertVisibility(long rawContactId, String expectedValue)6251 private void assertVisibility(long rawContactId, String expectedValue) { 6252 assertStoredValue(Contacts.CONTENT_URI, Contacts._ID + "=" + queryContactId(rawContactId), 6253 null, Contacts.IN_VISIBLE_GROUP, expectedValue); 6254 } 6255 testSupplyingBothValuesAndParameters()6256 public void testSupplyingBothValuesAndParameters() throws Exception { 6257 Account account = new Account("account 1", "type%/:1"); 6258 Uri uri = ContactsContract.Groups.CONTENT_URI.buildUpon() 6259 .appendQueryParameter(ContactsContract.Groups.ACCOUNT_NAME, account.name) 6260 .appendQueryParameter(ContactsContract.Groups.ACCOUNT_TYPE, account.type) 6261 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true") 6262 .build(); 6263 6264 ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(uri); 6265 builder.withValue(ContactsContract.Groups.ACCOUNT_TYPE, account.type); 6266 builder.withValue(ContactsContract.Groups.ACCOUNT_NAME, account.name); 6267 builder.withValue(ContactsContract.Groups.SYSTEM_ID, "some id"); 6268 builder.withValue(ContactsContract.Groups.TITLE, "some name"); 6269 builder.withValue(ContactsContract.Groups.GROUP_VISIBLE, 1); 6270 6271 mResolver.applyBatch(ContactsContract.AUTHORITY, Lists.newArrayList(builder.build())); 6272 6273 builder = ContentProviderOperation.newInsert(uri); 6274 builder.withValue(ContactsContract.Groups.ACCOUNT_TYPE, account.type + "diff"); 6275 builder.withValue(ContactsContract.Groups.ACCOUNT_NAME, account.name); 6276 builder.withValue(ContactsContract.Groups.SYSTEM_ID, "some other id"); 6277 builder.withValue(ContactsContract.Groups.TITLE, "some other name"); 6278 builder.withValue(ContactsContract.Groups.GROUP_VISIBLE, 1); 6279 6280 try { 6281 mResolver.applyBatch(ContactsContract.AUTHORITY, Lists.newArrayList(builder.build())); 6282 fail("Expected IllegalArgumentException"); 6283 } catch (IllegalArgumentException ex) { 6284 // Expected 6285 } 6286 } 6287 testContentEntityIterator()6288 public void testContentEntityIterator() { 6289 // create multiple contacts and check that the selected ones are returned 6290 long id; 6291 6292 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 6293 long groupId2 = createGroup(mAccount, "gsid2", "title2"); 6294 6295 id = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.SOURCE_ID, "c0"); 6296 insertGroupMembership(id, "gsid1"); 6297 insertEmail(id, "c0@email.com"); 6298 insertPhoneNumber(id, "5551212c0"); 6299 6300 long c1 = id = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.SOURCE_ID, 6301 "c1"); 6302 Uri id_1_0 = insertGroupMembership(id, "gsid1"); 6303 Uri id_1_1 = insertGroupMembership(id, "gsid2"); 6304 Uri id_1_2 = insertEmail(id, "c1@email.com"); 6305 Uri id_1_3 = insertPhoneNumber(id, "5551212c1"); 6306 6307 long c2 = id = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.SOURCE_ID, 6308 "c2"); 6309 Uri id_2_0 = insertGroupMembership(id, "gsid1"); 6310 Uri id_2_1 = insertEmail(id, "c2@email.com"); 6311 Uri id_2_2 = insertPhoneNumber(id, "5551212c2"); 6312 6313 long c3 = id = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.SOURCE_ID, 6314 "c3"); 6315 Uri id_3_0 = insertGroupMembership(id, groupId2); 6316 Uri id_3_1 = insertEmail(id, "c3@email.com"); 6317 Uri id_3_2 = insertPhoneNumber(id, "5551212c3"); 6318 6319 EntityIterator iterator = RawContacts.newEntityIterator(mResolver.query( 6320 TestUtil.maybeAddAccountQueryParameters(RawContactsEntity.CONTENT_URI, mAccount), 6321 null, RawContacts.SOURCE_ID + " in ('c1', 'c2', 'c3')", null, null)); 6322 Entity entity; 6323 ContentValues[] subValues; 6324 entity = iterator.next(); 6325 assertEquals(c1, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 6326 subValues = asSortedContentValuesArray(entity.getSubValues()); 6327 assertEquals(4, subValues.length); 6328 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 6329 Data._ID, id_1_0, 6330 GroupMembership.GROUP_ROW_ID, groupId1, 6331 GroupMembership.GROUP_SOURCE_ID, "gsid1"); 6332 assertDataRow(subValues[1], GroupMembership.CONTENT_ITEM_TYPE, 6333 Data._ID, id_1_1, 6334 GroupMembership.GROUP_ROW_ID, groupId2, 6335 GroupMembership.GROUP_SOURCE_ID, "gsid2"); 6336 assertDataRow(subValues[2], Email.CONTENT_ITEM_TYPE, 6337 Data._ID, id_1_2, 6338 Email.DATA, "c1@email.com"); 6339 assertDataRow(subValues[3], Phone.CONTENT_ITEM_TYPE, 6340 Data._ID, id_1_3, 6341 Email.DATA, "5551212c1"); 6342 6343 entity = iterator.next(); 6344 assertEquals(c2, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 6345 subValues = asSortedContentValuesArray(entity.getSubValues()); 6346 assertEquals(3, subValues.length); 6347 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 6348 Data._ID, id_2_0, 6349 GroupMembership.GROUP_ROW_ID, groupId1, 6350 GroupMembership.GROUP_SOURCE_ID, "gsid1"); 6351 assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE, 6352 Data._ID, id_2_1, 6353 Email.DATA, "c2@email.com"); 6354 assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE, 6355 Data._ID, id_2_2, 6356 Email.DATA, "5551212c2"); 6357 6358 entity = iterator.next(); 6359 assertEquals(c3, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 6360 subValues = asSortedContentValuesArray(entity.getSubValues()); 6361 assertEquals(3, subValues.length); 6362 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 6363 Data._ID, id_3_0, 6364 GroupMembership.GROUP_ROW_ID, groupId2, 6365 GroupMembership.GROUP_SOURCE_ID, "gsid2"); 6366 assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE, 6367 Data._ID, id_3_1, 6368 Email.DATA, "c3@email.com"); 6369 assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE, 6370 Data._ID, id_3_2, 6371 Email.DATA, "5551212c3"); 6372 6373 assertFalse(iterator.hasNext()); 6374 iterator.close(); 6375 } 6376 testDataCreateUpdateDeleteByMimeType()6377 public void testDataCreateUpdateDeleteByMimeType() throws Exception { 6378 long rawContactId = RawContactUtil.createRawContact(mResolver); 6379 6380 ContentValues values = new ContentValues(); 6381 values.put(Data.RAW_CONTACT_ID, rawContactId); 6382 values.put(Data.MIMETYPE, "testmimetype"); 6383 values.put(Data.RES_PACKAGE, "oldpackage"); 6384 values.put(Data.IS_PRIMARY, 1); 6385 values.put(Data.IS_SUPER_PRIMARY, 1); 6386 values.put(Data.DATA1, "old1"); 6387 values.put(Data.DATA2, "old2"); 6388 values.put(Data.DATA3, "old3"); 6389 values.put(Data.DATA4, "old4"); 6390 values.put(Data.DATA5, "old5"); 6391 values.put(Data.DATA6, "old6"); 6392 values.put(Data.DATA7, "old7"); 6393 values.put(Data.DATA8, "old8"); 6394 values.put(Data.DATA9, "old9"); 6395 values.put(Data.DATA10, "old10"); 6396 values.put(Data.DATA11, "old11"); 6397 values.put(Data.DATA12, "old12"); 6398 values.put(Data.DATA13, "old13"); 6399 values.put(Data.DATA14, "old14"); 6400 values.put(Data.DATA15, "old15"); 6401 values.put(Data.CARRIER_PRESENCE, 0); 6402 values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, "oldcomponentname"); 6403 values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, "oldid"); 6404 Uri uri = mResolver.insert(Data.CONTENT_URI, values); 6405 assertStoredValues(uri, values); 6406 assertNetworkNotified(true); 6407 6408 values.clear(); 6409 values.put(Data.RES_PACKAGE, "newpackage"); 6410 values.put(Data.IS_PRIMARY, 0); 6411 values.put(Data.IS_SUPER_PRIMARY, 0); 6412 values.put(Data.DATA1, "new1"); 6413 values.put(Data.DATA2, "new2"); 6414 values.put(Data.DATA3, "new3"); 6415 values.put(Data.DATA4, "new4"); 6416 values.put(Data.DATA5, "new5"); 6417 values.put(Data.DATA6, "new6"); 6418 values.put(Data.DATA7, "new7"); 6419 values.put(Data.DATA8, "new8"); 6420 values.put(Data.DATA9, "new9"); 6421 values.put(Data.DATA10, "new10"); 6422 values.put(Data.DATA11, "new11"); 6423 values.put(Data.DATA12, "new12"); 6424 values.put(Data.DATA13, "new13"); 6425 values.put(Data.DATA14, "new14"); 6426 values.put(Data.DATA15, "new15"); 6427 values.put(Data.CARRIER_PRESENCE, Data.CARRIER_PRESENCE_VT_CAPABLE); 6428 values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, "newcomponentname"); 6429 values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, "newid"); 6430 mResolver.update(Data.CONTENT_URI, values, Data.RAW_CONTACT_ID + "=" + rawContactId + 6431 " AND " + Data.MIMETYPE + "='testmimetype'", null); 6432 assertNetworkNotified(true); 6433 6434 assertStoredValues(uri, values); 6435 6436 int count = mResolver.delete(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId 6437 + " AND " + Data.MIMETYPE + "='testmimetype'", null); 6438 assertEquals(1, count); 6439 assertEquals(0, getCount(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId 6440 + " AND " + Data.MIMETYPE + "='testmimetype'", null)); 6441 assertNetworkNotified(true); 6442 } 6443 testRawContactQuery()6444 public void testRawContactQuery() { 6445 Account account1 = new Account("a", "b"); 6446 Account account2 = new Account("c", "d"); 6447 long rawContactId1 = RawContactUtil.createRawContact(mResolver, account1); 6448 long rawContactId2 = RawContactUtil.createRawContact(mResolver, account2); 6449 6450 Uri uri1 = TestUtil.maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account1); 6451 Uri uri2 = TestUtil.maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account2); 6452 assertEquals(1, getCount(uri1, null, null)); 6453 assertEquals(1, getCount(uri2, null, null)); 6454 assertStoredValue(uri1, RawContacts._ID, rawContactId1) ; 6455 assertStoredValue(uri2, RawContacts._ID, rawContactId2) ; 6456 6457 Uri rowUri1 = ContentUris.withAppendedId(uri1, rawContactId1); 6458 Uri rowUri2 = ContentUris.withAppendedId(uri2, rawContactId2); 6459 assertStoredValue(rowUri1, RawContacts._ID, rawContactId1) ; 6460 assertStoredValue(rowUri2, RawContacts._ID, rawContactId2) ; 6461 } 6462 testRawContactDeletion()6463 public void testRawContactDeletion() { 6464 long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6465 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 6466 6467 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 6468 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 6469 StatusUpdates.AVAILABLE, null, 6470 StatusUpdates.CAPABILITY_HAS_CAMERA); 6471 long contactId = queryContactId(rawContactId); 6472 6473 assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 6474 null, null)); 6475 assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 6476 + rawContactId, null)); 6477 6478 mResolver.delete(uri, null, null); 6479 6480 assertStoredValue(uri, RawContacts.DELETED, "1"); 6481 assertNetworkNotified(true); 6482 6483 Uri permanentDeletionUri = setCallerIsSyncAdapter(uri, mAccount); 6484 mResolver.delete(permanentDeletionUri, null, null); 6485 assertEquals(0, getCount(uri, null, null)); 6486 assertEquals(0, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 6487 null, null)); 6488 assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 6489 + rawContactId, null)); 6490 assertEquals(0, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null)); 6491 assertNetworkNotified(false); 6492 } 6493 testRawContactDeletionKeepingAggregateContact()6494 public void testRawContactDeletionKeepingAggregateContact() { 6495 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, mAccount); 6496 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, mAccount); 6497 setAggregationException( 6498 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 6499 6500 long contactId = queryContactId(rawContactId1); 6501 6502 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 6503 Uri permanentDeletionUri = setCallerIsSyncAdapter(uri, mAccount); 6504 mResolver.delete(permanentDeletionUri, null, null); 6505 assertEquals(0, getCount(uri, null, null)); 6506 assertEquals(1, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null)); 6507 } 6508 testRawContactDeletion_byAccountParam()6509 public void testRawContactDeletion_byAccountParam() { 6510 long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6511 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 6512 6513 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 6514 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 6515 StatusUpdates.AVAILABLE, null, 6516 StatusUpdates.CAPABILITY_HAS_CAMERA); 6517 assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 6518 null, null)); 6519 assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 6520 + rawContactId, null)); 6521 6522 // Do not delete if we are deleting with wrong account. 6523 Uri deleteWithWrongAccountUri = 6524 RawContacts.CONTENT_URI.buildUpon() 6525 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccountTwo.name) 6526 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccountTwo.type) 6527 .build(); 6528 int numDeleted = mResolver.delete(deleteWithWrongAccountUri, null, null); 6529 assertEquals(0, numDeleted); 6530 6531 assertStoredValue(uri, RawContacts.DELETED, "0"); 6532 6533 // Delete if we are deleting with correct account. 6534 Uri deleteWithCorrectAccountUri = 6535 RawContacts.CONTENT_URI.buildUpon() 6536 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccount.name) 6537 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccount.type) 6538 .build(); 6539 numDeleted = mResolver.delete(deleteWithCorrectAccountUri, null, null); 6540 assertEquals(1, numDeleted); 6541 6542 assertStoredValue(uri, RawContacts.DELETED, "1"); 6543 } 6544 testRawContactDeletion_byAccountSelection()6545 public void testRawContactDeletion_byAccountSelection() { 6546 long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6547 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 6548 6549 // Do not delete if we are deleting with wrong account. 6550 int numDeleted = mResolver.delete(RawContacts.CONTENT_URI, 6551 RawContacts.ACCOUNT_NAME + "=? AND " + RawContacts.ACCOUNT_TYPE + "=?", 6552 new String[] {mAccountTwo.name, mAccountTwo.type}); 6553 assertEquals(0, numDeleted); 6554 6555 assertStoredValue(uri, RawContacts.DELETED, "0"); 6556 6557 // Delete if we are deleting with correct account. 6558 numDeleted = mResolver.delete(RawContacts.CONTENT_URI, 6559 RawContacts.ACCOUNT_NAME + "=? AND " + RawContacts.ACCOUNT_TYPE + "=?", 6560 new String[] {mAccount.name, mAccount.type}); 6561 assertEquals(1, numDeleted); 6562 6563 assertStoredValue(uri, RawContacts.DELETED, "1"); 6564 } 6565 6566 /** 6567 * Test for {@link ContactsProvider2#stringToAccounts} and 6568 * {@link ContactsProvider2#accountsToString}. 6569 */ testAccountsToString()6570 public void testAccountsToString() { 6571 final Set<Account> EXPECTED_0 = Sets.newHashSet(); 6572 final Set<Account> EXPECTED_1 = Sets.newHashSet(TestUtil.ACCOUNT_1); 6573 final Set<Account> EXPECTED_2 = Sets.newHashSet(TestUtil.ACCOUNT_2); 6574 final Set<Account> EXPECTED_1_2 = Sets.newHashSet(TestUtil.ACCOUNT_1, TestUtil.ACCOUNT_2); 6575 6576 final Set<Account> ACTUAL_0 = Sets.newHashSet(); 6577 final Set<Account> ACTUAL_1 = Sets.newHashSet(TestUtil.ACCOUNT_1); 6578 final Set<Account> ACTUAL_2 = Sets.newHashSet(TestUtil.ACCOUNT_2); 6579 final Set<Account> ACTUAL_1_2 = Sets.newHashSet(TestUtil.ACCOUNT_2, TestUtil.ACCOUNT_1); 6580 6581 assertTrue(EXPECTED_0.equals(accountsToStringToAccounts(ACTUAL_0))); 6582 assertFalse(EXPECTED_0.equals(accountsToStringToAccounts(ACTUAL_1))); 6583 assertFalse(EXPECTED_0.equals(accountsToStringToAccounts(ACTUAL_2))); 6584 assertFalse(EXPECTED_0.equals(accountsToStringToAccounts(ACTUAL_1_2))); 6585 6586 assertFalse(EXPECTED_1.equals(accountsToStringToAccounts(ACTUAL_0))); 6587 assertTrue(EXPECTED_1.equals(accountsToStringToAccounts(ACTUAL_1))); 6588 assertFalse(EXPECTED_1.equals(accountsToStringToAccounts(ACTUAL_2))); 6589 assertFalse(EXPECTED_1.equals(accountsToStringToAccounts(ACTUAL_1_2))); 6590 6591 assertFalse(EXPECTED_2.equals(accountsToStringToAccounts(ACTUAL_0))); 6592 assertFalse(EXPECTED_2.equals(accountsToStringToAccounts(ACTUAL_1))); 6593 assertTrue(EXPECTED_2.equals(accountsToStringToAccounts(ACTUAL_2))); 6594 assertFalse(EXPECTED_2.equals(accountsToStringToAccounts(ACTUAL_1_2))); 6595 6596 assertFalse(EXPECTED_1_2.equals(accountsToStringToAccounts(ACTUAL_0))); 6597 assertFalse(EXPECTED_1_2.equals(accountsToStringToAccounts(ACTUAL_1))); 6598 assertFalse(EXPECTED_1_2.equals(accountsToStringToAccounts(ACTUAL_2))); 6599 assertTrue(EXPECTED_1_2.equals(accountsToStringToAccounts(ACTUAL_1_2))); 6600 6601 try { 6602 ContactsProvider2.stringToAccounts("x"); 6603 fail("Didn't throw for malformed input"); 6604 } catch (IllegalArgumentException expected) { 6605 } 6606 } 6607 accountsToStringToAccounts(Set<Account> accounts)6608 private static final Set<Account> accountsToStringToAccounts(Set<Account> accounts) { 6609 return ContactsProvider2.stringToAccounts(ContactsProvider2.accountsToString(accounts)); 6610 } 6611 6612 /** 6613 * Test for {@link ContactsProvider2#haveAccountsChanged} and 6614 * {@link ContactsProvider2#saveAccounts}. 6615 */ testHaveAccountsChanged()6616 public void testHaveAccountsChanged() { 6617 final ContactsProvider2 cp = (ContactsProvider2) getProvider(); 6618 6619 final Account[] ACCOUNTS_0 = new Account[] {}; 6620 final Account[] ACCOUNTS_1 = new Account[] {TestUtil.ACCOUNT_1}; 6621 final Account[] ACCOUNTS_2 = new Account[] {TestUtil.ACCOUNT_2}; 6622 final Account[] ACCOUNTS_1_2 = new Account[] {TestUtil.ACCOUNT_1, TestUtil.ACCOUNT_2}; 6623 final Account[] ACCOUNTS_2_1 = new Account[] {TestUtil.ACCOUNT_2, TestUtil.ACCOUNT_1}; 6624 6625 // Add ACCOUNT_1 6626 6627 assertTrue(cp.haveAccountsChanged(ACCOUNTS_1)); 6628 cp.saveAccounts(ACCOUNTS_1); 6629 assertFalse(cp.haveAccountsChanged(ACCOUNTS_1)); 6630 6631 // Add ACCOUNT_2 6632 6633 assertTrue(cp.haveAccountsChanged(ACCOUNTS_1_2)); 6634 // (try with reverse order) 6635 assertTrue(cp.haveAccountsChanged(ACCOUNTS_2_1)); 6636 cp.saveAccounts(ACCOUNTS_1_2); 6637 assertFalse(cp.haveAccountsChanged(ACCOUNTS_1_2)); 6638 // (try with reverse order) 6639 assertFalse(cp.haveAccountsChanged(ACCOUNTS_2_1)); 6640 6641 // Remove ACCOUNT_1 6642 6643 assertTrue(cp.haveAccountsChanged(ACCOUNTS_2)); 6644 cp.saveAccounts(ACCOUNTS_2); 6645 assertFalse(cp.haveAccountsChanged(ACCOUNTS_2)); 6646 6647 // Remove ACCOUNT_2 6648 6649 assertTrue(cp.haveAccountsChanged(ACCOUNTS_0)); 6650 cp.saveAccounts(ACCOUNTS_0); 6651 assertFalse(cp.haveAccountsChanged(ACCOUNTS_0)); 6652 6653 // Test with malformed DB property. 6654 6655 final ContactsDatabaseHelper dbHelper = cp.getThreadActiveDatabaseHelperForTest(); 6656 dbHelper.setProperty(DbProperties.KNOWN_ACCOUNTS, "x"); 6657 6658 // With malformed property the method always return true. 6659 assertTrue(cp.haveAccountsChanged(ACCOUNTS_0)); 6660 assertTrue(cp.haveAccountsChanged(ACCOUNTS_1)); 6661 } 6662 testAccountsUpdated()6663 public void testAccountsUpdated() { 6664 // This is to ensure we do not delete contacts with null, null (account name, type) 6665 // accidentally. 6666 long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "James", "Sullivan"); 6667 insertPhoneNumber(rawContactId3, "5234567890"); 6668 Uri rawContact3 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId3); 6669 assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null)); 6670 6671 ContactsProvider2 cp = (ContactsProvider2) getProvider(); 6672 mActor.setAccounts(new Account[]{mAccount, mAccountTwo}); 6673 cp.onAccountsUpdated(new Account[]{mAccount, mAccountTwo}); 6674 assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null)); 6675 assertStoredValue( 6676 rawContact3, RawContacts.ACCOUNT_NAME, 6677 AccountWithDataSet.LOCAL.getAccountName()); 6678 assertStoredValue(rawContact3, RawContacts.ACCOUNT_TYPE, 6679 AccountWithDataSet.LOCAL.getAccountType()); 6680 6681 long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount); 6682 insertEmail(rawContactId1, "account1@email.com"); 6683 long rawContactId2 = RawContactUtil.createRawContact(mResolver, mAccountTwo); 6684 insertEmail(rawContactId2, "account2@email.com"); 6685 insertImHandle(rawContactId2, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 6686 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 6687 StatusUpdates.AVAILABLE, null, 6688 StatusUpdates.CAPABILITY_HAS_CAMERA); 6689 6690 mActor.setAccounts(new Account[]{mAccount}); 6691 cp.onAccountsUpdated(new Account[]{mAccount}); 6692 assertEquals(2, getCount(RawContacts.CONTENT_URI, null, null)); 6693 assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 6694 + rawContactId2, null)); 6695 } 6696 testAccountDeletion()6697 public void testAccountDeletion() { 6698 Account readOnlyAccount = new Account("act", READ_ONLY_ACCOUNT_TYPE); 6699 ContactsProvider2 cp = (ContactsProvider2) getProvider(); 6700 mActor.setAccounts(new Account[]{readOnlyAccount, mAccount}); 6701 cp.onAccountsUpdated(new Account[]{readOnlyAccount, mAccount}); 6702 6703 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 6704 readOnlyAccount); 6705 Uri photoUri1 = insertPhoto(rawContactId1); 6706 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "john", "doe", 6707 mAccount); 6708 Uri photoUri2 = insertPhoto(rawContactId2); 6709 storeValue(photoUri2, Photo.IS_SUPER_PRIMARY, "1"); 6710 6711 assertAggregated(rawContactId1, rawContactId2); 6712 6713 long contactId = queryContactId(rawContactId1); 6714 6715 // The display name should come from the writable account 6716 assertStoredValue(Uri.withAppendedPath( 6717 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 6718 Contacts.Data.CONTENT_DIRECTORY), 6719 Contacts.DISPLAY_NAME, "john doe"); 6720 6721 // The photo should be the one we marked as super-primary 6722 assertStoredValue(Contacts.CONTENT_URI, contactId, 6723 Contacts.PHOTO_ID, ContentUris.parseId(photoUri2)); 6724 6725 mActor.setAccounts(new Account[]{readOnlyAccount}); 6726 // Remove the writable account 6727 cp.onAccountsUpdated(new Account[]{readOnlyAccount}); 6728 6729 // The display name should come from the remaining account 6730 assertStoredValue(Uri.withAppendedPath( 6731 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 6732 Contacts.Data.CONTENT_DIRECTORY), 6733 Contacts.DISPLAY_NAME, "John Doe"); 6734 6735 // The photo should be the remaining one 6736 assertStoredValue(Contacts.CONTENT_URI, contactId, 6737 Contacts.PHOTO_ID, ContentUris.parseId(photoUri1)); 6738 } 6739 testStreamItemsCleanedUpOnAccountRemoval()6740 public void testStreamItemsCleanedUpOnAccountRemoval() { 6741 Account doomedAccount = new Account("doom", "doom"); 6742 Account safeAccount = mAccount; 6743 ContactsProvider2 cp = (ContactsProvider2) getProvider(); 6744 mActor.setAccounts(new Account[]{doomedAccount, safeAccount}); 6745 cp.onAccountsUpdated(new Account[]{doomedAccount, safeAccount}); 6746 6747 // Create a doomed raw contact, stream item, and photo. 6748 long doomedRawContactId = RawContactUtil.createRawContactWithName(mResolver, doomedAccount); 6749 Uri doomedStreamItemUri = 6750 insertStreamItem(doomedRawContactId, buildGenericStreamItemValues(), doomedAccount); 6751 long doomedStreamItemId = ContentUris.parseId(doomedStreamItemUri); 6752 Uri doomedStreamItemPhotoUri = insertStreamItemPhoto( 6753 doomedStreamItemId, buildGenericStreamItemPhotoValues(0), doomedAccount); 6754 6755 // Create a safe raw contact, stream item, and photo. 6756 long safeRawContactId = RawContactUtil.createRawContactWithName(mResolver, safeAccount); 6757 Uri safeStreamItemUri = 6758 insertStreamItem(safeRawContactId, buildGenericStreamItemValues(), safeAccount); 6759 long safeStreamItemId = ContentUris.parseId(safeStreamItemUri); 6760 Uri safeStreamItemPhotoUri = insertStreamItemPhoto( 6761 safeStreamItemId, buildGenericStreamItemPhotoValues(0), safeAccount); 6762 long safeStreamItemPhotoId = ContentUris.parseId(safeStreamItemPhotoUri); 6763 6764 // Remove the doomed account. 6765 mActor.setAccounts(new Account[]{safeAccount}); 6766 cp.onAccountsUpdated(new Account[]{safeAccount}); 6767 6768 // Check that the doomed stuff has all been nuked. 6769 ContentValues[] noValues = new ContentValues[0]; 6770 assertStoredValues(ContentUris.withAppendedId(RawContacts.CONTENT_URI, doomedRawContactId), 6771 noValues); 6772 assertStoredValues(doomedStreamItemUri, noValues); 6773 assertStoredValues(doomedStreamItemPhotoUri, noValues); 6774 6775 // Check that the safe stuff lives on. 6776 assertStoredValue(RawContacts.CONTENT_URI, safeRawContactId, RawContacts._ID, 6777 safeRawContactId); 6778 assertStoredValue(safeStreamItemUri, StreamItems._ID, safeStreamItemId); 6779 assertStoredValue(safeStreamItemPhotoUri, StreamItemPhotos._ID, safeStreamItemPhotoId); 6780 } 6781 testContactDeletion()6782 public void testContactDeletion() { 6783 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 6784 TestUtil.ACCOUNT_1); 6785 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 6786 TestUtil.ACCOUNT_2); 6787 6788 long contactId = queryContactId(rawContactId1); 6789 6790 mResolver.delete(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), null, null); 6791 6792 assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1), 6793 RawContacts.DELETED, "1"); 6794 assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2), 6795 RawContacts.DELETED, "1"); 6796 } 6797 testMarkAsDirtyParameter()6798 public void testMarkAsDirtyParameter() { 6799 long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6800 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 6801 6802 Uri uri = DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe"); 6803 clearDirty(rawContactUri); 6804 Uri updateUri = setCallerIsSyncAdapter(uri, mAccount); 6805 6806 ContentValues values = new ContentValues(); 6807 values.put(StructuredName.FAMILY_NAME, "Dough"); 6808 mResolver.update(updateUri, values, null, null); 6809 assertStoredValue(uri, StructuredName.FAMILY_NAME, "Dough"); 6810 assertDirty(rawContactUri, false); 6811 assertNetworkNotified(false); 6812 } 6813 testDirtyWhenRawContactInsert()6814 public void testDirtyWhenRawContactInsert() { 6815 // When inserting a rawcontact. 6816 long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6817 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 6818 assertDirty(rawContactUri, false); 6819 assertMetadataDirty(rawContactUri, false); 6820 assertNetworkNotified(true); 6821 } 6822 testRawContactDirtyAndVersion()6823 public void testRawContactDirtyAndVersion() { 6824 final long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6825 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId); 6826 assertDirty(uri, false); 6827 long version = getVersion(uri); 6828 6829 ContentValues values = new ContentValues(); 6830 values.put(ContactsContract.RawContacts.SEND_TO_VOICEMAIL, 1); 6831 values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 6832 RawContacts.AGGREGATION_MODE_IMMEDIATE); 6833 assertEquals(1, mResolver.update(uri, values, null, null)); 6834 assertEquals(version, getVersion(uri)); 6835 6836 assertDirty(uri, false); 6837 assertMetadataDirty(uri, false); 6838 assertNetworkNotified(false); 6839 6840 Uri emailUri = insertEmail(rawContactId, "goo@woo.com"); 6841 assertDirty(uri, true); 6842 assertNetworkNotified(true); 6843 ++version; 6844 assertEquals(version, getVersion(uri)); 6845 clearDirty(uri); 6846 6847 values = new ContentValues(); 6848 values.put(Email.DATA, "goo@hoo.com"); 6849 mResolver.update(emailUri, values, null, null); 6850 assertDirty(uri, true); 6851 assertNetworkNotified(true); 6852 ++version; 6853 assertEquals(version, getVersion(uri)); 6854 clearDirty(uri); 6855 6856 mResolver.delete(emailUri, null, null); 6857 assertDirty(uri, true); 6858 assertNetworkNotified(true); 6859 ++version; 6860 assertEquals(version, getVersion(uri)); 6861 } 6862 testRawContactClearDirty()6863 public void testRawContactClearDirty() { 6864 final long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6865 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, 6866 rawContactId); 6867 long version = getVersion(uri); 6868 insertEmail(rawContactId, "goo@woo.com"); 6869 assertDirty(uri, true); 6870 version++; 6871 assertEquals(version, getVersion(uri)); 6872 6873 clearDirty(uri); 6874 assertDirty(uri, false); 6875 assertEquals(version, getVersion(uri)); 6876 } 6877 testRawContactDeletionSetsDirty()6878 public void testRawContactDeletionSetsDirty() { 6879 final long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6880 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, 6881 rawContactId); 6882 long version = getVersion(uri); 6883 clearDirty(uri); 6884 assertDirty(uri, false); 6885 6886 mResolver.delete(uri, null, null); 6887 assertStoredValue(uri, RawContacts.DELETED, "1"); 6888 assertDirty(uri, true); 6889 assertNetworkNotified(true); 6890 version++; 6891 assertEquals(version, getVersion(uri)); 6892 } 6893 testNotifyMetadataChangeForRawContactInsertBySyncAdapter()6894 public void testNotifyMetadataChangeForRawContactInsertBySyncAdapter() { 6895 Uri uri = RawContacts.CONTENT_URI.buildUpon() 6896 .appendQueryParameter(RawContacts.ACCOUNT_NAME, mAccount.name) 6897 .appendQueryParameter(RawContacts.ACCOUNT_TYPE, mAccount.type) 6898 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, true + "") 6899 .build(); 6900 6901 long rawContactId = ContentUris.parseId(mResolver.insert(uri, new ContentValues())); 6902 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 6903 assertMetadataDirty(rawContactUri, false); 6904 } 6905 testMarkAsMetadataDirtyForRawContactMetadataChange()6906 public void testMarkAsMetadataDirtyForRawContactMetadataChange() { 6907 long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6908 long contactId = queryContactId(rawContactId); 6909 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 6910 6911 ContentValues values = new ContentValues(); 6912 values.put(Contacts.STARRED, 1); 6913 mResolver.update(contactUri, values, null, null); 6914 assertStoredValue(contactUri, Contacts.STARRED, 1); 6915 6916 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 6917 assertMetadataDirty(rawContactUri, false); 6918 6919 clearMetadataDirty(rawContactUri); 6920 values = new ContentValues(); 6921 values.put(Contacts.PINNED, 1); 6922 mResolver.update(contactUri, values, null, null); 6923 assertStoredValue(contactUri, Contacts.PINNED, 1); 6924 6925 assertMetadataDirty(rawContactUri, false); 6926 6927 clearMetadataDirty(rawContactUri); 6928 values = new ContentValues(); 6929 values.put(Contacts.SEND_TO_VOICEMAIL, 1); 6930 mResolver.update(contactUri, values, null, null); 6931 assertStoredValue(contactUri, Contacts.SEND_TO_VOICEMAIL, 1); 6932 6933 assertMetadataDirty(rawContactUri, false); 6934 } 6935 testMarkAsMetadataDirtyForRawContactBackupIdChange()6936 public void testMarkAsMetadataDirtyForRawContactBackupIdChange() { 6937 long rawContactId = RawContactUtil.createRawContact(mResolver, mAccount); 6938 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 6939 6940 // Make a metadata change to set metadata_dirty. 6941 ContentValues values = new ContentValues(); 6942 values.put(RawContacts.SEND_TO_VOICEMAIL, "1"); 6943 mResolver.update(rawContactUri, values, null, null); 6944 assertMetadataDirty(rawContactUri, false); 6945 6946 // Update the backup_id and check metadata network should be notified. 6947 values = new ContentValues(); 6948 values.put(RawContacts.BACKUP_ID, "newBackupId"); 6949 mResolver.update(rawContactUri, values, null, null); 6950 assertStoredValue(rawContactUri, RawContacts.BACKUP_ID, "newBackupId"); 6951 assertMetadataDirty(rawContactUri, false); 6952 } 6953 testMarkAsMetadataDirtyForAggregationExceptionChange()6954 public void testMarkAsMetadataDirtyForAggregationExceptionChange() { 6955 long rawContactId1 = RawContactUtil.createRawContact(mResolver, new Account("a", "a")); 6956 long rawContactId2 = RawContactUtil.createRawContact(mResolver, new Account("b", "b")); 6957 6958 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 6959 rawContactId1, rawContactId2); 6960 6961 assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1), 6962 false); 6963 assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2), 6964 false); 6965 } 6966 testMarkAsMetadataNotDirtyForUsageStatsChange()6967 public void testMarkAsMetadataNotDirtyForUsageStatsChange() { 6968 final long rid1 = RawContactUtil.createRawContactWithName(mResolver, "contact", "a"); 6969 final long did1a = ContentUris.parseId(insertEmail(rid1, "email_1_a@email.com")); 6970 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, did1a); 6971 6972 // Usage feedback no longer works, so "false". 6973 assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rid1), false); 6974 } 6975 testMarkAsMetadataDirtyForDataPrimarySettingInsert()6976 public void testMarkAsMetadataDirtyForDataPrimarySettingInsert() { 6977 long rawContactId1 = RawContactUtil.createRawContact(mResolver, new Account("a", "a")); 6978 Uri mailUri11 = insertEmail(rawContactId1, "test1@domain1.com", true, true); 6979 6980 assertStoredValue(mailUri11, Data.IS_PRIMARY, 1); 6981 assertStoredValue(mailUri11, Data.IS_SUPER_PRIMARY, 1); 6982 assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1), 6983 false); 6984 } 6985 testMarkAsMetadataDirtyForDataPrimarySettingUpdate()6986 public void testMarkAsMetadataDirtyForDataPrimarySettingUpdate() { 6987 long rawContactId = RawContactUtil.createRawContact(mResolver, new Account("a", "a")); 6988 Uri mailUri1 = insertEmail(rawContactId, "test1@domain1.com"); 6989 6990 assertStoredValue(mailUri1, Data.IS_PRIMARY, 0); 6991 assertStoredValue(mailUri1, Data.IS_SUPER_PRIMARY, 0); 6992 6993 ContentValues values = new ContentValues(); 6994 values.put(Data.IS_SUPER_PRIMARY, 1); 6995 mResolver.update(mailUri1, values, null, null); 6996 6997 assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 6998 false); 6999 } 7000 testMarkAsMetadataDirtyForDataDelete()7001 public void testMarkAsMetadataDirtyForDataDelete() { 7002 long rawContactId = RawContactUtil.createRawContact(mResolver, new Account("a", "a")); 7003 Uri mailUri1 = insertEmail(rawContactId, "test1@domain1.com", true, true); 7004 7005 mResolver.delete(mailUri1, null, null); 7006 7007 assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 7008 false); 7009 } 7010 testDeleteContactWithoutName()7011 public void testDeleteContactWithoutName() { 7012 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues()); 7013 long rawContactId = ContentUris.parseId(rawContactUri); 7014 7015 Uri phoneUri = insertPhoneNumber(rawContactId, "555-123-45678", true); 7016 7017 long contactId = queryContactId(rawContactId); 7018 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7019 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 7020 7021 int numDeleted = mResolver.delete(lookupUri, null, null); 7022 assertEquals(1, numDeleted); 7023 } 7024 testDeleteContactWithoutAnyData()7025 public void testDeleteContactWithoutAnyData() { 7026 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues()); 7027 long rawContactId = ContentUris.parseId(rawContactUri); 7028 7029 long contactId = queryContactId(rawContactId); 7030 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7031 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 7032 7033 int numDeleted = mResolver.delete(lookupUri, null, null); 7034 assertEquals(1, numDeleted); 7035 } 7036 testDeleteContactWithEscapedUri()7037 public void testDeleteContactWithEscapedUri() { 7038 ContentValues values = new ContentValues(); 7039 values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~"); 7040 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 7041 long rawContactId = ContentUris.parseId(rawContactUri); 7042 7043 long contactId = queryContactId(rawContactId); 7044 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7045 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 7046 assertEquals(1, mResolver.delete(lookupUri, null, null)); 7047 } 7048 testDeleteContactComposedOfSingleLocalRawContact()7049 public void testDeleteContactComposedOfSingleLocalRawContact() { 7050 // Create a raw contact in the local (null) account 7051 long rawContactId = RawContactUtil.createRawContact(mResolver, null); 7052 DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Smith"); 7053 7054 // Delete the contact 7055 long contactId = queryContactId(rawContactId); 7056 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7057 assertEquals(1, mResolver.delete(contactUri, null, null)); 7058 7059 // Assert that the raw contact was removed 7060 Cursor c1 = queryRawContact(rawContactId); 7061 assertEquals(0, c1.getCount()); 7062 c1.close(); 7063 7064 // Assert that the contact was removed 7065 Cursor c2 = mResolver.query(contactUri, null, null, null, ""); 7066 assertEquals(0, c2.getCount()); 7067 c2.close(); 7068 } 7069 testDeleteContactComposedOfTwoLocalRawContacts()7070 public void testDeleteContactComposedOfTwoLocalRawContacts() { 7071 // Create a raw contact in the local (null) account 7072 long rawContactId1 = RawContactUtil.createRawContact(mResolver, null); 7073 DataUtil.insertStructuredName(mResolver, rawContactId1, "John", "Smith"); 7074 7075 // Create another local raw contact with the same name 7076 long rawContactId2 = RawContactUtil.createRawContact(mResolver, null); 7077 DataUtil.insertStructuredName(mResolver, rawContactId2, "John", "Smith"); 7078 7079 // Join the two raw contacts explicitly 7080 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 7081 rawContactId1, rawContactId2); 7082 7083 // Check that the two raw contacts are aggregated together 7084 assertAggregated(rawContactId1, rawContactId2, "John Smith"); 7085 7086 // Delete the aggregate contact 7087 long contactId = queryContactId(rawContactId1); 7088 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7089 assertEquals(1, mResolver.delete(contactUri, null, null)); 7090 7091 // Assert that both of the local raw contacts were removed completely 7092 Cursor c1 = queryRawContact(rawContactId1); 7093 assertEquals(0, c1.getCount()); 7094 c1.close(); 7095 7096 Cursor c2 = queryRawContact(rawContactId2); 7097 assertEquals(0, c2.getCount()); 7098 c2.close(); 7099 7100 // Assert that the contact was removed 7101 Cursor c3 = queryContact(contactId); 7102 assertEquals(0, c3.getCount()); 7103 c3.close(); 7104 } 7105 testDeleteContactComposedOfSomeLocalRawContacts()7106 public void testDeleteContactComposedOfSomeLocalRawContacts() { 7107 // Create a raw contact in the local (null) account 7108 long rawContactId1 = RawContactUtil.createRawContact(mResolver, null); 7109 DataUtil.insertStructuredName(mResolver, rawContactId1, "John", "Smith"); 7110 7111 // Create another one in a non-local account with the same name 7112 long rawContactId2 = RawContactUtil.createRawContact(mResolver, mAccount); 7113 DataUtil.insertStructuredName(mResolver, rawContactId2, "John", "Smith"); 7114 7115 // Check that the two new raw contacts are aggregated together 7116 assertAggregated(rawContactId1, rawContactId2, "John Smith"); 7117 7118 // Delete the aggregate contact 7119 long contactId = queryContactId(rawContactId1); 7120 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7121 assertEquals(1, mResolver.delete(contactUri, null, null)); 7122 7123 // Assert that the local raw contact was removed completely 7124 Cursor c1 = queryRawContact(rawContactId1); 7125 assertEquals(0, c1.getCount()); 7126 c1.close(); 7127 7128 // Assert that the non-local raw contact is still present just marked as deleted 7129 Cursor c2 = queryRawContact(rawContactId2); 7130 assertEquals(1, c2.getCount()); 7131 assertTrue(c2.moveToFirst()); 7132 assertEquals(1, c2.getInt(c2.getColumnIndex(RawContacts.DELETED))); 7133 c2.close(); 7134 7135 // Assert that the contact was removed 7136 Cursor c3 = queryContact(contactId); 7137 assertEquals(0, c3.getCount()); 7138 c3.close(); 7139 } 7140 testQueryContactWithEscapedUri()7141 public void testQueryContactWithEscapedUri() { 7142 ContentValues values = new ContentValues(); 7143 values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~"); 7144 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 7145 long rawContactId = ContentUris.parseId(rawContactUri); 7146 7147 long contactId = queryContactId(rawContactId); 7148 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7149 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 7150 Cursor c = mResolver.query(lookupUri, null, null, null, ""); 7151 assertEquals(1, c.getCount()); 7152 c.close(); 7153 } 7154 testGetPhotoUri()7155 public void testGetPhotoUri() { 7156 ContentValues values = new ContentValues(); 7157 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 7158 long rawContactId = ContentUris.parseId(rawContactUri); 7159 DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe"); 7160 long dataId = ContentUris.parseId(insertPhoto(rawContactId, R.drawable.earth_normal)); 7161 long photoFileId = getStoredLongValue(Data.CONTENT_URI, Data._ID + "=?", 7162 new String[]{String.valueOf(dataId)}, Photo.PHOTO_FILE_ID); 7163 String photoUri = ContentUris.withAppendedId(DisplayPhoto.CONTENT_URI, photoFileId) 7164 .toString(); 7165 7166 assertStoredValue( 7167 ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(rawContactId)), 7168 Contacts.PHOTO_URI, photoUri); 7169 } 7170 testGetPhotoViaLookupUri()7171 public void testGetPhotoViaLookupUri() throws IOException { 7172 long rawContactId = RawContactUtil.createRawContact(mResolver); 7173 long contactId = queryContactId(rawContactId); 7174 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7175 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 7176 String lookupKey = lookupUri.getPathSegments().get(2); 7177 insertPhoto(rawContactId, R.drawable.earth_small); 7178 byte[] thumbnail = loadPhotoFromResource(R.drawable.earth_small, PhotoSize.THUMBNAIL); 7179 7180 // Two forms of lookup key URIs should be valid - one with the contact ID, one without. 7181 Uri photoLookupUriWithId = Uri.withAppendedPath(lookupUri, "photo"); 7182 Uri photoLookupUriWithoutId = Contacts.CONTENT_LOOKUP_URI.buildUpon() 7183 .appendPath(lookupKey).appendPath("photo").build(); 7184 7185 // Try retrieving as a data record. 7186 ContentValues values = new ContentValues(); 7187 values.put(Photo.PHOTO, thumbnail); 7188 assertStoredValues(photoLookupUriWithId, values); 7189 assertStoredValues(photoLookupUriWithoutId, values); 7190 7191 // Try opening as an input stream. 7192 EvenMoreAsserts.assertImageRawData(getContext(), 7193 thumbnail, mResolver.openInputStream(photoLookupUriWithId)); 7194 EvenMoreAsserts.assertImageRawData(getContext(), 7195 thumbnail, mResolver.openInputStream(photoLookupUriWithoutId)); 7196 } 7197 testInputStreamForPhoto()7198 public void testInputStreamForPhoto() throws Exception { 7199 long rawContactId = RawContactUtil.createRawContact(mResolver); 7200 long contactId = queryContactId(rawContactId); 7201 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7202 insertPhoto(rawContactId); 7203 Uri photoUri = Uri.parse(getStoredValue(contactUri, Contacts.PHOTO_URI)); 7204 Uri photoThumbnailUri = Uri.parse(getStoredValue(contactUri, Contacts.PHOTO_THUMBNAIL_URI)); 7205 7206 // Check the thumbnail. 7207 EvenMoreAsserts.assertImageRawData(getContext(), loadTestPhoto(PhotoSize.THUMBNAIL), 7208 mResolver.openInputStream(photoThumbnailUri)); 7209 7210 // Then check the display photo. Note because we only inserted a small photo, but not a 7211 // display photo, this returns the thumbnail image itself, which was compressed at 7212 // the thumnail compression rate, which is why we compare to 7213 // loadTestPhoto(PhotoSize.THUMBNAIL) rather than loadTestPhoto(PhotoSize.DISPLAY_PHOTO) 7214 // here. 7215 // (In other words, loadTestPhoto(PhotoSize.DISPLAY_PHOTO) returns the same photo as 7216 // loadTestPhoto(PhotoSize.THUMBNAIL), except it's compressed at a lower compression rate.) 7217 EvenMoreAsserts.assertImageRawData(getContext(), loadTestPhoto(PhotoSize.THUMBNAIL), 7218 mResolver.openInputStream(photoUri)); 7219 } 7220 testSuperPrimaryPhoto()7221 public void testSuperPrimaryPhoto() { 7222 long rawContactId1 = RawContactUtil.createRawContact(mResolver, new Account("a", "a")); 7223 Uri photoUri1 = insertPhoto(rawContactId1, R.drawable.earth_normal); 7224 long photoId1 = ContentUris.parseId(photoUri1); 7225 7226 long rawContactId2 = RawContactUtil.createRawContact(mResolver, new Account("b", "b")); 7227 Uri photoUri2 = insertPhoto(rawContactId2, R.drawable.earth_normal); 7228 long photoId2 = ContentUris.parseId(photoUri2); 7229 7230 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 7231 rawContactId1, rawContactId2); 7232 7233 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 7234 queryContactId(rawContactId1)); 7235 7236 long photoFileId1 = getStoredLongValue(Data.CONTENT_URI, Data._ID + "=?", 7237 new String[]{String.valueOf(photoId1)}, Photo.PHOTO_FILE_ID); 7238 String photoUri = ContentUris.withAppendedId(DisplayPhoto.CONTENT_URI, photoFileId1) 7239 .toString(); 7240 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1); 7241 assertStoredValue(contactUri, Contacts.PHOTO_URI, photoUri); 7242 7243 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 7244 rawContactId1, rawContactId2); 7245 7246 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 7247 rawContactId1, rawContactId2); 7248 ContentValues values = new ContentValues(); 7249 values.put(Data.IS_SUPER_PRIMARY, 1); 7250 mResolver.update(photoUri2, values, null, null); 7251 7252 contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 7253 queryContactId(rawContactId1)); 7254 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId2); 7255 7256 mResolver.update(photoUri1, values, null, null); 7257 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1); 7258 } 7259 testUpdatePhoto()7260 public void testUpdatePhoto() { 7261 ContentValues values = new ContentValues(); 7262 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 7263 long rawContactId = ContentUris.parseId(rawContactUri); 7264 DataUtil.insertStructuredName(mResolver, rawContactId, "John", "Doe"); 7265 7266 Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, 7267 queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY); 7268 7269 values.clear(); 7270 values.put(Data.RAW_CONTACT_ID, rawContactId); 7271 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 7272 values.putNull(Photo.PHOTO); 7273 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 7274 long photoId = ContentUris.parseId(dataUri); 7275 7276 assertEquals(0, getCount(twigUri, null, null)); 7277 7278 values.clear(); 7279 values.put(Photo.PHOTO, loadTestPhoto()); 7280 mResolver.update(dataUri, values, null, null); 7281 assertNetworkNotified(true); 7282 7283 long twigId = getStoredLongValue(twigUri, Data._ID); 7284 assertEquals(photoId, twigId); 7285 } 7286 testUpdateRawContactDataPhoto()7287 public void testUpdateRawContactDataPhoto() { 7288 // setup a contact with a null photo 7289 ContentValues values = new ContentValues(); 7290 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 7291 long rawContactId = ContentUris.parseId(rawContactUri); 7292 7293 // setup a photo 7294 values.put(Data.RAW_CONTACT_ID, rawContactId); 7295 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 7296 values.putNull(Photo.PHOTO); 7297 7298 // try to do an update before insert should return count == 0 7299 Uri dataUri = Uri.withAppendedPath( 7300 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 7301 RawContacts.Data.CONTENT_DIRECTORY); 7302 assertEquals(0, mResolver.update(dataUri, values, Data.MIMETYPE + "=?", 7303 new String[] {Photo.CONTENT_ITEM_TYPE})); 7304 7305 mResolver.insert(Data.CONTENT_URI, values); 7306 7307 // save a photo to the db 7308 values.clear(); 7309 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 7310 values.put(Photo.PHOTO, loadTestPhoto()); 7311 assertEquals(1, mResolver.update(dataUri, values, Data.MIMETYPE + "=?", 7312 new String[] {Photo.CONTENT_ITEM_TYPE})); 7313 7314 // verify the photo 7315 Cursor storedPhoto = mResolver.query(dataUri, new String[] {Photo.PHOTO}, 7316 Data.MIMETYPE + "=?", new String[] {Photo.CONTENT_ITEM_TYPE}, null); 7317 storedPhoto.moveToFirst(); 7318 MoreAsserts.assertEquals(loadTestPhoto(PhotoSize.THUMBNAIL), storedPhoto.getBlob(0)); 7319 storedPhoto.close(); 7320 } 7321 testOpenDisplayPhotoForContactId()7322 public void testOpenDisplayPhotoForContactId() throws IOException { 7323 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 7324 long contactId = queryContactId(rawContactId); 7325 insertPhoto(rawContactId, R.drawable.earth_normal); 7326 Uri photoUri = Contacts.CONTENT_URI.buildUpon() 7327 .appendPath(String.valueOf(contactId)) 7328 .appendPath(Contacts.Photo.DISPLAY_PHOTO).build(); 7329 EvenMoreAsserts.assertImageRawData(getContext(), 7330 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 7331 mResolver.openInputStream(photoUri)); 7332 } 7333 testOpenDisplayPhotoForContactLookupKey()7334 public void testOpenDisplayPhotoForContactLookupKey() throws IOException { 7335 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 7336 long contactId = queryContactId(rawContactId); 7337 String lookupKey = queryLookupKey(contactId); 7338 insertPhoto(rawContactId, R.drawable.earth_normal); 7339 Uri photoUri = Contacts.CONTENT_LOOKUP_URI.buildUpon() 7340 .appendPath(lookupKey) 7341 .appendPath(Contacts.Photo.DISPLAY_PHOTO).build(); 7342 EvenMoreAsserts.assertImageRawData(getContext(), 7343 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 7344 mResolver.openInputStream(photoUri)); 7345 } 7346 testOpenDisplayPhotoForContactLookupKeyAndId()7347 public void testOpenDisplayPhotoForContactLookupKeyAndId() throws IOException { 7348 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 7349 long contactId = queryContactId(rawContactId); 7350 String lookupKey = queryLookupKey(contactId); 7351 insertPhoto(rawContactId, R.drawable.earth_normal); 7352 Uri photoUri = Contacts.CONTENT_LOOKUP_URI.buildUpon() 7353 .appendPath(lookupKey) 7354 .appendPath(String.valueOf(contactId)) 7355 .appendPath(Contacts.Photo.DISPLAY_PHOTO).build(); 7356 EvenMoreAsserts.assertImageRawData(getContext(), 7357 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 7358 mResolver.openInputStream(photoUri)); 7359 } 7360 testOpenDisplayPhotoForRawContactId()7361 public void testOpenDisplayPhotoForRawContactId() throws IOException { 7362 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 7363 insertPhoto(rawContactId, R.drawable.earth_normal); 7364 Uri photoUri = RawContacts.CONTENT_URI.buildUpon() 7365 .appendPath(String.valueOf(rawContactId)) 7366 .appendPath(RawContacts.DisplayPhoto.CONTENT_DIRECTORY).build(); 7367 EvenMoreAsserts.assertImageRawData(getContext(), 7368 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 7369 mResolver.openInputStream(photoUri)); 7370 } 7371 testOpenDisplayPhotoByPhotoUri()7372 public void testOpenDisplayPhotoByPhotoUri() throws IOException { 7373 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 7374 long contactId = queryContactId(rawContactId); 7375 insertPhoto(rawContactId, R.drawable.earth_normal); 7376 7377 // Get the photo URI out and check the content. 7378 String photoUri = getStoredValue( 7379 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 7380 Contacts.PHOTO_URI); 7381 EvenMoreAsserts.assertImageRawData(getContext(), 7382 loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO), 7383 mResolver.openInputStream(Uri.parse(photoUri))); 7384 } 7385 testPhotoUriForDisplayPhoto()7386 public void testPhotoUriForDisplayPhoto() { 7387 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 7388 long contactId = queryContactId(rawContactId); 7389 7390 // Photo being inserted is larger than a thumbnail, so it will be stored as a file. 7391 long dataId = ContentUris.parseId(insertPhoto(rawContactId, R.drawable.earth_normal)); 7392 String photoFileId = getStoredValue(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), 7393 Photo.PHOTO_FILE_ID); 7394 String photoUri = getStoredValue( 7395 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 7396 Contacts.PHOTO_URI); 7397 7398 // Check that the photo URI differs from the thumbnail. 7399 String thumbnailUri = getStoredValue( 7400 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 7401 Contacts.PHOTO_THUMBNAIL_URI); 7402 assertFalse(photoUri.equals(thumbnailUri)); 7403 7404 // URI should be of the form display_photo/ID 7405 assertEquals(Uri.withAppendedPath(DisplayPhoto.CONTENT_URI, photoFileId).toString(), 7406 photoUri); 7407 } 7408 testPhotoUriForThumbnailPhoto()7409 public void testPhotoUriForThumbnailPhoto() throws IOException { 7410 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 7411 long contactId = queryContactId(rawContactId); 7412 7413 // Photo being inserted is a thumbnail, so it will only be stored in a BLOB. The photo URI 7414 // will fall back to the thumbnail URI. 7415 insertPhoto(rawContactId, R.drawable.earth_small); 7416 String photoUri = getStoredValue( 7417 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 7418 Contacts.PHOTO_URI); 7419 7420 // Check that the photo URI is equal to the thumbnail URI. 7421 String thumbnailUri = getStoredValue( 7422 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 7423 Contacts.PHOTO_THUMBNAIL_URI); 7424 assertEquals(photoUri, thumbnailUri); 7425 7426 // URI should be of the form contacts/ID/photo 7427 assertEquals(Uri.withAppendedPath( 7428 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 7429 Contacts.Photo.CONTENT_DIRECTORY).toString(), 7430 photoUri); 7431 7432 // Loading the photo URI content should get the thumbnail. 7433 EvenMoreAsserts.assertImageRawData(getContext(), 7434 loadPhotoFromResource(R.drawable.earth_small, PhotoSize.THUMBNAIL), 7435 mResolver.openInputStream(Uri.parse(photoUri))); 7436 } 7437 testWriteNewPhotoToAssetFile()7438 public void testWriteNewPhotoToAssetFile() throws Exception { 7439 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 7440 long contactId = queryContactId(rawContactId); 7441 7442 // Load in a huge photo. 7443 final byte[] originalPhoto = loadPhotoFromResource( 7444 R.drawable.earth_huge, PhotoSize.ORIGINAL); 7445 7446 // Write it out. 7447 final Uri writeablePhotoUri = RawContacts.CONTENT_URI.buildUpon() 7448 .appendPath(String.valueOf(rawContactId)) 7449 .appendPath(RawContacts.DisplayPhoto.CONTENT_DIRECTORY).build(); 7450 writePhotoAsync(writeablePhotoUri, originalPhoto); 7451 7452 // Check that the display photo and thumbnail have been set. 7453 String photoUri = null; 7454 for (int i = 0; i < 10 && photoUri == null; i++) { 7455 // Wait a tick for the photo processing to occur. 7456 Thread.sleep(100); 7457 photoUri = getStoredValue( 7458 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 7459 Contacts.PHOTO_URI); 7460 } 7461 7462 assertFalse(TextUtils.isEmpty(photoUri)); 7463 String thumbnailUri = getStoredValue( 7464 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 7465 Contacts.PHOTO_THUMBNAIL_URI); 7466 assertFalse(TextUtils.isEmpty(thumbnailUri)); 7467 assertNotSame(photoUri, thumbnailUri); 7468 7469 // Check the content of the display photo and thumbnail. 7470 EvenMoreAsserts.assertImageRawData(getContext(), 7471 loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.DISPLAY_PHOTO), 7472 mResolver.openInputStream(Uri.parse(photoUri))); 7473 EvenMoreAsserts.assertImageRawData(getContext(), 7474 loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.THUMBNAIL), 7475 mResolver.openInputStream(Uri.parse(thumbnailUri))); 7476 } 7477 testWriteUpdatedPhotoToAssetFile()7478 public void testWriteUpdatedPhotoToAssetFile() throws Exception { 7479 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 7480 long contactId = queryContactId(rawContactId); 7481 7482 // Insert a large photo first. 7483 insertPhoto(rawContactId, R.drawable.earth_large); 7484 String largeEarthPhotoUri = getStoredValue( 7485 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), Contacts.PHOTO_URI); 7486 7487 // Load in a huge photo. 7488 byte[] originalPhoto = loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.ORIGINAL); 7489 7490 // Write it out. 7491 Uri writeablePhotoUri = RawContacts.CONTENT_URI.buildUpon() 7492 .appendPath(String.valueOf(rawContactId)) 7493 .appendPath(RawContacts.DisplayPhoto.CONTENT_DIRECTORY).build(); 7494 writePhotoAsync(writeablePhotoUri, originalPhoto); 7495 7496 // Allow a second for processing to occur. 7497 Thread.sleep(1000); 7498 7499 // Check that the display photo URI has been modified. 7500 String hugeEarthPhotoUri = getStoredValue( 7501 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), Contacts.PHOTO_URI); 7502 assertFalse(hugeEarthPhotoUri.equals(largeEarthPhotoUri)); 7503 7504 // Check the content of the display photo and thumbnail. 7505 String hugeEarthThumbnailUri = getStoredValue( 7506 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 7507 Contacts.PHOTO_THUMBNAIL_URI); 7508 EvenMoreAsserts.assertImageRawData(getContext(), 7509 loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.DISPLAY_PHOTO), 7510 mResolver.openInputStream(Uri.parse(hugeEarthPhotoUri))); 7511 EvenMoreAsserts.assertImageRawData(getContext(), 7512 loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.THUMBNAIL), 7513 mResolver.openInputStream(Uri.parse(hugeEarthThumbnailUri))); 7514 7515 } 7516 writePhotoAsync(final Uri uri, final byte[] photoBytes)7517 private void writePhotoAsync(final Uri uri, final byte[] photoBytes) throws Exception { 7518 AsyncTask<Object, Object, Object> task = new AsyncTask<Object, Object, Object>() { 7519 @Override 7520 protected Object doInBackground(Object... params) { 7521 OutputStream os; 7522 try { 7523 os = mResolver.openOutputStream(uri, "rw"); 7524 os.write(photoBytes); 7525 os.close(); 7526 return null; 7527 } catch (IOException ioe) { 7528 throw new RuntimeException(ioe); 7529 } 7530 } 7531 }; 7532 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])null).get(); 7533 } 7534 testPhotoDimensionLimits()7535 public void testPhotoDimensionLimits() { 7536 ContentValues values = new ContentValues(); 7537 values.put(DisplayPhoto.DISPLAY_MAX_DIM, 256); 7538 values.put(DisplayPhoto.THUMBNAIL_MAX_DIM, 96); 7539 assertStoredValues(DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI, values); 7540 } 7541 testPhotoStoreCleanup()7542 public void testPhotoStoreCleanup() throws IOException { 7543 SynchronousContactsProvider2 provider = (SynchronousContactsProvider2) mActor.provider; 7544 PhotoStore photoStore = provider.getPhotoStore(); 7545 7546 // Trigger an initial cleanup so another one won't happen while we're running this test. 7547 provider.cleanupPhotoStore(); 7548 7549 // Insert a couple of contacts with photos. 7550 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver); 7551 long contactId1 = queryContactId(rawContactId1); 7552 long dataId1 = ContentUris.parseId(insertPhoto(rawContactId1, R.drawable.earth_normal)); 7553 long photoFileId1 = 7554 getStoredLongValue(ContentUris.withAppendedId(Data.CONTENT_URI, dataId1), 7555 Photo.PHOTO_FILE_ID); 7556 7557 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver); 7558 long contactId2 = queryContactId(rawContactId2); 7559 long dataId2 = ContentUris.parseId(insertPhoto(rawContactId2, R.drawable.earth_normal)); 7560 long photoFileId2 = 7561 getStoredLongValue(ContentUris.withAppendedId(Data.CONTENT_URI, dataId2), 7562 Photo.PHOTO_FILE_ID); 7563 7564 // Update the second raw contact with a different photo. 7565 ContentValues values = new ContentValues(); 7566 values.put(Data.RAW_CONTACT_ID, rawContactId2); 7567 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 7568 values.put(Photo.PHOTO, loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.ORIGINAL)); 7569 assertEquals(1, mResolver.update(Data.CONTENT_URI, values, Data._ID + "=?", 7570 new String[]{String.valueOf(dataId2)})); 7571 long replacementPhotoFileId = 7572 getStoredLongValue(ContentUris.withAppendedId(Data.CONTENT_URI, dataId2), 7573 Photo.PHOTO_FILE_ID); 7574 7575 // Insert a third raw contact that has a bogus photo file ID. 7576 long bogusFileId = 1234567; 7577 long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver); 7578 long contactId3 = queryContactId(rawContactId3); 7579 values.clear(); 7580 values.put(Data.RAW_CONTACT_ID, rawContactId3); 7581 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 7582 values.put(Photo.PHOTO, loadPhotoFromResource(R.drawable.earth_normal, 7583 PhotoSize.THUMBNAIL)); 7584 values.put(Photo.PHOTO_FILE_ID, bogusFileId); 7585 values.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 7586 mResolver.insert(Data.CONTENT_URI, values); 7587 7588 // Insert a fourth raw contact with a stream item that has a photo, then remove that photo 7589 // from the photo store. 7590 Account socialAccount = new Account("social", "social"); 7591 long rawContactId4 = RawContactUtil.createRawContactWithName(mResolver, socialAccount); 7592 Uri streamItemUri = 7593 insertStreamItem(rawContactId4, buildGenericStreamItemValues(), socialAccount); 7594 long streamItemId = ContentUris.parseId(streamItemUri); 7595 Uri streamItemPhotoUri = insertStreamItemPhoto( 7596 streamItemId, buildGenericStreamItemPhotoValues(0), socialAccount); 7597 long streamItemPhotoFileId = getStoredLongValue(streamItemPhotoUri, 7598 StreamItemPhotos.PHOTO_FILE_ID); 7599 photoStore.remove(streamItemPhotoFileId); 7600 7601 // Also insert a bogus photo that nobody is using. 7602 long bogusPhotoId = photoStore.insert(new PhotoProcessor(loadPhotoFromResource( 7603 R.drawable.earth_huge, PhotoSize.ORIGINAL), 256, 96)); 7604 7605 // Manually trigger another cleanup in the provider. 7606 provider.cleanupPhotoStore(); 7607 7608 // The following things should have happened. 7609 7610 // 1. Raw contact 1 and its photo remain unaffected. 7611 assertEquals(photoFileId1, (long) getStoredLongValue( 7612 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId1), 7613 Contacts.PHOTO_FILE_ID)); 7614 7615 // 2. Raw contact 2 retains its new photo. The old one is deleted from the photo store. 7616 assertEquals(replacementPhotoFileId, (long) getStoredLongValue( 7617 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId2), 7618 Contacts.PHOTO_FILE_ID)); 7619 assertNull(photoStore.get(photoFileId2)); 7620 7621 // 3. Raw contact 3 should have its photo file reference cleared. 7622 assertNull(getStoredValue( 7623 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId3), 7624 Contacts.PHOTO_FILE_ID)); 7625 7626 // 4. The bogus photo that nobody was using should be cleared from the photo store. 7627 assertNull(photoStore.get(bogusPhotoId)); 7628 7629 // 5. The bogus stream item photo should be cleared from the stream item. 7630 assertStoredValues(Uri.withAppendedPath( 7631 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 7632 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 7633 new ContentValues[0]); 7634 } 7635 testPhotoStoreCleanupForProfile()7636 public void testPhotoStoreCleanupForProfile() { 7637 SynchronousContactsProvider2 provider = (SynchronousContactsProvider2) mActor.provider; 7638 PhotoStore profilePhotoStore = provider.getProfilePhotoStore(); 7639 7640 // Trigger an initial cleanup so another one won't happen while we're running this test. 7641 provider.switchToProfileModeForTest(); 7642 provider.cleanupPhotoStore(); 7643 7644 // Create the profile contact and add a photo. 7645 Account socialAccount = new Account("social", "social"); 7646 ContentValues values = new ContentValues(); 7647 values.put(RawContacts.ACCOUNT_NAME, socialAccount.name); 7648 values.put(RawContacts.ACCOUNT_TYPE, socialAccount.type); 7649 long profileRawContactId = createBasicProfileContact(values); 7650 long profileContactId = queryContactId(profileRawContactId); 7651 long dataId = ContentUris.parseId( 7652 insertPhoto(profileRawContactId, R.drawable.earth_normal)); 7653 long profilePhotoFileId = 7654 getStoredLongValue(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), 7655 Photo.PHOTO_FILE_ID); 7656 7657 // Also add a stream item with a photo. 7658 Uri streamItemUri = 7659 insertStreamItem(profileRawContactId, buildGenericStreamItemValues(), 7660 socialAccount); 7661 long streamItemId = ContentUris.parseId(streamItemUri); 7662 Uri streamItemPhotoUri = insertStreamItemPhoto( 7663 streamItemId, buildGenericStreamItemPhotoValues(0), socialAccount); 7664 long streamItemPhotoFileId = getStoredLongValue(streamItemPhotoUri, 7665 StreamItemPhotos.PHOTO_FILE_ID); 7666 7667 // Remove the stream item photo and the profile photo. 7668 profilePhotoStore.remove(profilePhotoFileId); 7669 profilePhotoStore.remove(streamItemPhotoFileId); 7670 7671 // Manually trigger another cleanup in the provider. 7672 provider.switchToProfileModeForTest(); 7673 provider.cleanupPhotoStore(); 7674 7675 // The following things should have happened. 7676 7677 // The stream item photo should have been removed. 7678 assertStoredValues(Uri.withAppendedPath( 7679 ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId), 7680 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), 7681 new ContentValues[0]); 7682 7683 // The profile photo should have been cleared. 7684 assertNull(getStoredValue( 7685 ContentUris.withAppendedId(Contacts.CONTENT_URI, profileContactId), 7686 Contacts.PHOTO_FILE_ID)); 7687 7688 } 7689 testCleanupDanglingContacts_noDanglingContacts()7690 public void testCleanupDanglingContacts_noDanglingContacts() throws Exception { 7691 SynchronousContactsProvider2 provider = (SynchronousContactsProvider2) mActor.provider; 7692 RawContactUtil.createRawContactWithName(mResolver, "A", "B"); 7693 RawContactUtil.createRawContactWithName(mResolver, "C", "D"); 7694 7695 provider.cleanupDanglingContacts(); 7696 7697 Cursor contactCursor = mResolver.query(Contacts.CONTENT_URI, null, null, null, null); 7698 Cursor rawContactCursor = mResolver.query(RawContacts.CONTENT_URI, null, null, null, null); 7699 7700 // No contacts should be deleted 7701 assertEquals(2, contactCursor.getCount()); 7702 assertEquals(2, rawContactCursor.getCount()); 7703 } 7704 testCleanupDanglingContacts_singleDanglingContacts()7705 public void testCleanupDanglingContacts_singleDanglingContacts() throws Exception { 7706 SynchronousContactsProvider2 provider = (SynchronousContactsProvider2) mActor.provider; 7707 long rawContactId = RawContactUtil.createRawContactWithName(mResolver, "A", "B"); 7708 7709 // Change the contact_id to create dangling contact. 7710 SQLiteDatabase db = provider.getDatabaseHelper().getWritableDatabase(); 7711 db.execSQL("UPDATE raw_contacts SET contact_id = 99999 WHERE _id = " + rawContactId + ";"); 7712 7713 provider.cleanupDanglingContacts(); 7714 7715 // Dangling contact should be deleted from contacts table. 7716 assertEquals(0, mResolver.query(Contacts.CONTENT_URI, null, null, null, null).getCount()); 7717 } 7718 testCleanupDanglingContacts_multipleDanglingContacts()7719 public void testCleanupDanglingContacts_multipleDanglingContacts() throws Exception { 7720 SynchronousContactsProvider2 provider = (SynchronousContactsProvider2) mActor.provider; 7721 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "A", "B"); 7722 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "C", "D"); 7723 RawContactUtil.createRawContactWithName(mResolver, "E", "F"); 7724 7725 final ContactsDatabaseHelper helper = provider.getDatabaseHelper(); 7726 SQLiteDatabase db = helper.getWritableDatabase(); 7727 7728 // Change contact_id of RawContact1 and RawContact2 to create dangling contacts. 7729 db.execSQL("UPDATE raw_contacts SET contact_id = 99998 WHERE _id = " + rawContactId1 + ";"); 7730 db.execSQL("UPDATE raw_contacts SET contact_id = 99999 WHERE _id = " + rawContactId2 + ";"); 7731 7732 provider.cleanupDanglingContacts(); 7733 7734 // Should only be one contact left in the contacts table. 7735 // RawContact1 and RawContact2 should be deleted from the contacts table. 7736 assertEquals(1, mResolver.query(Contacts.CONTENT_URI, null, null, null, null).getCount()); 7737 } 7738 testOverwritePhotoWithThumbnail()7739 public void testOverwritePhotoWithThumbnail() throws IOException { 7740 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 7741 long contactId = queryContactId(rawContactId); 7742 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7743 7744 // Write a regular-size photo. 7745 long dataId = ContentUris.parseId(insertPhoto(rawContactId, R.drawable.earth_normal)); 7746 Long photoFileId = getStoredLongValue(contactUri, Contacts.PHOTO_FILE_ID); 7747 assertTrue(photoFileId != null && photoFileId > 0); 7748 7749 // Now overwrite the photo with a thumbnail-sized photo. 7750 ContentValues update = new ContentValues(); 7751 update.put(Photo.PHOTO, loadPhotoFromResource(R.drawable.earth_small, PhotoSize.ORIGINAL)); 7752 mResolver.update(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), update, null, null); 7753 7754 // Photo file ID should have been nulled out, and the photo URI should be the same as the 7755 // thumbnail URI. 7756 assertNull(getStoredValue(contactUri, Contacts.PHOTO_FILE_ID)); 7757 String photoUri = getStoredValue(contactUri, Contacts.PHOTO_URI); 7758 String thumbnailUri = getStoredValue(contactUri, Contacts.PHOTO_THUMBNAIL_URI); 7759 assertEquals(photoUri, thumbnailUri); 7760 7761 // Retrieving the photo URI should get the thumbnail content. 7762 EvenMoreAsserts.assertImageRawData(getContext(), 7763 loadPhotoFromResource(R.drawable.earth_small, PhotoSize.THUMBNAIL), 7764 mResolver.openInputStream(Uri.parse(photoUri))); 7765 } 7766 testUpdateRawContactSetStarred()7767 public void testUpdateRawContactSetStarred() { 7768 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver); 7769 Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 7770 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver); 7771 Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2); 7772 setAggregationException( 7773 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 7774 7775 long contactId = queryContactId(rawContactId1); 7776 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 7777 assertStoredValue(contactUri, Contacts.STARRED, "0"); 7778 7779 assertDirty(rawContactUri1, true); 7780 assertDirty(rawContactUri2, true); 7781 clearDirty(rawContactUri1); 7782 clearDirty(rawContactUri2); 7783 7784 ContentValues values = new ContentValues(); 7785 values.put(RawContacts.STARRED, "1"); 7786 7787 mResolver.update(rawContactUri1, values, null, null); 7788 7789 assertStoredValue(rawContactUri1, RawContacts.STARRED, "1"); 7790 assertStoredValue(rawContactUri2, RawContacts.STARRED, "0"); 7791 assertStoredValue(contactUri, Contacts.STARRED, "1"); 7792 assertDirty(rawContactUri1, true); 7793 assertNetworkNotified(true); 7794 7795 clearDirty(rawContactUri1); 7796 values.put(RawContacts.STARRED, "0"); 7797 mResolver.update(rawContactUri1, values, null, null); 7798 7799 assertStoredValue(rawContactUri1, RawContacts.STARRED, "0"); 7800 assertStoredValue(rawContactUri2, RawContacts.STARRED, "0"); 7801 assertStoredValue(contactUri, Contacts.STARRED, "0"); 7802 assertDirty(rawContactUri1, true); 7803 assertNetworkNotified(true); 7804 7805 clearDirty(rawContactUri1); 7806 values.put(Contacts.STARRED, "1"); 7807 mResolver.update(contactUri, values, null, null); 7808 7809 assertStoredValue(rawContactUri1, RawContacts.STARRED, "1"); 7810 assertStoredValue(rawContactUri2, RawContacts.STARRED, "1"); 7811 assertStoredValue(contactUri, Contacts.STARRED, "1"); 7812 assertDirty(rawContactUri1, true); 7813 assertNetworkNotified(true); 7814 } 7815 testUpdateContactOptionsSetStarred()7816 public void testUpdateContactOptionsSetStarred() { 7817 long rawContactId = RawContactUtil.createRawContact(mResolver); 7818 long contactId = queryContactId(rawContactId); 7819 String lookupKey = queryLookupKey(contactId); 7820 ContentValues values =new ContentValues(); 7821 values.put(Contacts.STARRED, 1); 7822 7823 Uri contactLookupUri = ContentUris.withAppendedId( 7824 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), contactId); 7825 mResolver.update(contactLookupUri, values, null, null); 7826 assertNetworkNotified(true); 7827 } 7828 testSetAndClearSuperPrimaryEmail()7829 public void testSetAndClearSuperPrimaryEmail() { 7830 long rawContactId1 = RawContactUtil.createRawContact(mResolver, new Account("a", "a")); 7831 Uri mailUri11 = insertEmail(rawContactId1, "test1@domain1.com"); 7832 Uri mailUri12 = insertEmail(rawContactId1, "test2@domain1.com"); 7833 7834 long rawContactId2 = RawContactUtil.createRawContact(mResolver, new Account("b", "b")); 7835 Uri mailUri21 = insertEmail(rawContactId2, "test1@domain2.com"); 7836 Uri mailUri22 = insertEmail(rawContactId2, "test2@domain2.com"); 7837 7838 assertStoredValue(mailUri11, Data.IS_PRIMARY, 0); 7839 assertStoredValue(mailUri11, Data.IS_SUPER_PRIMARY, 0); 7840 assertStoredValue(mailUri12, Data.IS_PRIMARY, 0); 7841 assertStoredValue(mailUri12, Data.IS_SUPER_PRIMARY, 0); 7842 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 7843 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 7844 assertStoredValue(mailUri22, Data.IS_PRIMARY, 0); 7845 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 0); 7846 7847 // Set super primary on the first pair, primary on the second 7848 { 7849 ContentValues values = new ContentValues(); 7850 values.put(Data.IS_SUPER_PRIMARY, 1); 7851 mResolver.update(mailUri11, values, null, null); 7852 } 7853 { 7854 ContentValues values = new ContentValues(); 7855 values.put(Data.IS_SUPER_PRIMARY, 1); 7856 mResolver.update(mailUri22, values, null, null); 7857 } 7858 7859 assertStoredValue(mailUri11, Data.IS_PRIMARY, 1); 7860 assertStoredValue(mailUri11, Data.IS_SUPER_PRIMARY, 1); 7861 assertStoredValue(mailUri12, Data.IS_PRIMARY, 0); 7862 assertStoredValue(mailUri12, Data.IS_SUPER_PRIMARY, 0); 7863 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 7864 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 7865 assertStoredValue(mailUri22, Data.IS_PRIMARY, 1); 7866 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 1); 7867 7868 // Clear primary on the first pair, make sure second is not affected and super_primary is 7869 // also cleared 7870 { 7871 ContentValues values = new ContentValues(); 7872 values.put(Data.IS_PRIMARY, 0); 7873 mResolver.update(mailUri11, values, null, null); 7874 } 7875 7876 assertStoredValue(mailUri11, Data.IS_PRIMARY, 0); 7877 assertStoredValue(mailUri11, Data.IS_SUPER_PRIMARY, 0); 7878 assertStoredValue(mailUri12, Data.IS_PRIMARY, 0); 7879 assertStoredValue(mailUri12, Data.IS_SUPER_PRIMARY, 0); 7880 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 7881 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 7882 assertStoredValue(mailUri22, Data.IS_PRIMARY, 1); 7883 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 1); 7884 7885 // Ensure that we can only clear super_primary, if we specify the correct data row 7886 { 7887 ContentValues values = new ContentValues(); 7888 values.put(Data.IS_SUPER_PRIMARY, 0); 7889 mResolver.update(mailUri21, values, null, null); 7890 } 7891 7892 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 7893 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 7894 assertStoredValue(mailUri22, Data.IS_PRIMARY, 1); 7895 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 1); 7896 7897 // Ensure that we can only clear primary, if we specify the correct data row 7898 { 7899 ContentValues values = new ContentValues(); 7900 values.put(Data.IS_PRIMARY, 0); 7901 mResolver.update(mailUri21, values, null, null); 7902 } 7903 7904 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 7905 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 7906 assertStoredValue(mailUri22, Data.IS_PRIMARY, 1); 7907 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 1); 7908 7909 // Now clear super-primary for real 7910 { 7911 ContentValues values = new ContentValues(); 7912 values.put(Data.IS_SUPER_PRIMARY, 0); 7913 mResolver.update(mailUri22, values, null, null); 7914 } 7915 7916 assertStoredValue(mailUri11, Data.IS_PRIMARY, 0); 7917 assertStoredValue(mailUri11, Data.IS_SUPER_PRIMARY, 0); 7918 assertStoredValue(mailUri12, Data.IS_PRIMARY, 0); 7919 assertStoredValue(mailUri12, Data.IS_SUPER_PRIMARY, 0); 7920 assertStoredValue(mailUri21, Data.IS_PRIMARY, 0); 7921 assertStoredValue(mailUri21, Data.IS_SUPER_PRIMARY, 0); 7922 assertStoredValue(mailUri22, Data.IS_PRIMARY, 1); 7923 assertStoredValue(mailUri22, Data.IS_SUPER_PRIMARY, 0); 7924 } 7925 7926 /** 7927 * Common function for the testNewPrimaryIn* functions. Its four configurations 7928 * are each called from its own test 7929 */ testChangingPrimary(boolean inUpdate, boolean withSuperPrimary)7930 public void testChangingPrimary(boolean inUpdate, boolean withSuperPrimary) { 7931 long rawContactId = RawContactUtil.createRawContact(mResolver, new Account("a", "a")); 7932 Uri mailUri1 = insertEmail(rawContactId, "test1@domain1.com", true); 7933 7934 if (withSuperPrimary) { 7935 final ContentValues values = new ContentValues(); 7936 values.put(Data.IS_SUPER_PRIMARY, 1); 7937 mResolver.update(mailUri1, values, null, null); 7938 } 7939 7940 assertStoredValue(mailUri1, Data.IS_PRIMARY, 1); 7941 assertStoredValue(mailUri1, Data.IS_SUPER_PRIMARY, withSuperPrimary ? 1 : 0); 7942 7943 // Insert another item 7944 final Uri mailUri2; 7945 if (inUpdate) { 7946 mailUri2 = insertEmail(rawContactId, "test2@domain1.com"); 7947 7948 assertStoredValue(mailUri1, Data.IS_PRIMARY, 1); 7949 assertStoredValue(mailUri1, Data.IS_SUPER_PRIMARY, withSuperPrimary ? 1 : 0); 7950 assertStoredValue(mailUri2, Data.IS_PRIMARY, 0); 7951 assertStoredValue(mailUri2, Data.IS_SUPER_PRIMARY, 0); 7952 7953 final ContentValues values = new ContentValues(); 7954 values.put(Data.IS_PRIMARY, 1); 7955 mResolver.update(mailUri2, values, null, null); 7956 } else { 7957 // directly add as default 7958 mailUri2 = insertEmail(rawContactId, "test2@domain1.com", true); 7959 } 7960 7961 // Ensure that primary has been unset on the first 7962 // If withSuperPrimary is set, also ensure that is has been moved to the new item 7963 assertStoredValue(mailUri1, Data.IS_PRIMARY, 0); 7964 assertStoredValue(mailUri1, Data.IS_SUPER_PRIMARY, 0); 7965 assertStoredValue(mailUri2, Data.IS_PRIMARY, 1); 7966 assertStoredValue(mailUri2, Data.IS_SUPER_PRIMARY, withSuperPrimary ? 1 : 0); 7967 } 7968 testNewPrimaryInInsert()7969 public void testNewPrimaryInInsert() { 7970 testChangingPrimary(false, false); 7971 } 7972 testNewPrimaryInInsertWithSuperPrimary()7973 public void testNewPrimaryInInsertWithSuperPrimary() { 7974 testChangingPrimary(false, true); 7975 } 7976 testNewPrimaryInUpdate()7977 public void testNewPrimaryInUpdate() { 7978 testChangingPrimary(true, false); 7979 } 7980 testNewPrimaryInUpdateWithSuperPrimary()7981 public void testNewPrimaryInUpdateWithSuperPrimary() { 7982 testChangingPrimary(true, true); 7983 } 7984 testContactSortOrder()7985 public void testContactSortOrder() { 7986 assertEquals(ContactsColumns.PHONEBOOK_BUCKET_PRIMARY + ", " 7987 + Contacts.SORT_KEY_PRIMARY, 7988 ContactsProvider2.getLocalizedSortOrder(Contacts.SORT_KEY_PRIMARY)); 7989 assertEquals(ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE + ", " 7990 + Contacts.SORT_KEY_ALTERNATIVE, 7991 ContactsProvider2.getLocalizedSortOrder(Contacts.SORT_KEY_ALTERNATIVE)); 7992 assertEquals(ContactsColumns.PHONEBOOK_BUCKET_PRIMARY + " DESC, " 7993 + Contacts.SORT_KEY_PRIMARY + " DESC", 7994 ContactsProvider2.getLocalizedSortOrder(Contacts.SORT_KEY_PRIMARY + " DESC")); 7995 String suffix = " COLLATE LOCALIZED DESC"; 7996 assertEquals(ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE + suffix 7997 + ", " + Contacts.SORT_KEY_ALTERNATIVE + suffix, 7998 ContactsProvider2.getLocalizedSortOrder(Contacts.SORT_KEY_ALTERNATIVE 7999 + suffix)); 8000 } 8001 testContactCounts()8002 public void testContactCounts() { 8003 Uri uri = Contacts.CONTENT_URI.buildUpon() 8004 .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true").build(); 8005 8006 RawContactUtil.createRawContact(mResolver); 8007 RawContactUtil.createRawContactWithName(mResolver, "James", "Sullivan"); 8008 RawContactUtil.createRawContactWithName(mResolver, "The Abominable", "Snowman"); 8009 RawContactUtil.createRawContactWithName(mResolver, "Mike", "Wazowski"); 8010 RawContactUtil.createRawContactWithName(mResolver, "randall", "boggs"); 8011 RawContactUtil.createRawContactWithName(mResolver, "Boo", null); 8012 RawContactUtil.createRawContactWithName(mResolver, "Mary", null); 8013 RawContactUtil.createRawContactWithName(mResolver, "Roz", null); 8014 // Contacts with null display names get sorted to the end (using the number bucket) 8015 RawContactUtil.createRawContactWithName(mResolver, null, null); 8016 8017 Cursor cursor = mResolver.query(uri, 8018 new String[]{Contacts.DISPLAY_NAME}, 8019 null, null, Contacts.SORT_KEY_PRIMARY); 8020 8021 assertFirstLetterValues(cursor, "B", "J", "M", "R", "T", "#"); 8022 assertFirstLetterCounts(cursor, 1, 1, 2, 2, 1, 2); 8023 cursor.close(); 8024 8025 cursor = mResolver.query(uri, 8026 new String[]{Contacts.DISPLAY_NAME}, 8027 null, null, Contacts.SORT_KEY_ALTERNATIVE + " COLLATE LOCALIZED DESC"); 8028 8029 assertFirstLetterValues(cursor, "#", "W", "S", "R", "M", "B"); 8030 assertFirstLetterCounts(cursor, 2, 1, 2, 1, 1, 2); 8031 cursor.close(); 8032 } 8033 assertFirstLetterValues(Cursor cursor, String... expected)8034 private void assertFirstLetterValues(Cursor cursor, String... expected) { 8035 String[] actual = cursor.getExtras() 8036 .getStringArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES); 8037 MoreAsserts.assertEquals(expected, actual); 8038 } 8039 assertFirstLetterCounts(Cursor cursor, int... expected)8040 private void assertFirstLetterCounts(Cursor cursor, int... expected) { 8041 int[] actual = cursor.getExtras() 8042 .getIntArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS); 8043 MoreAsserts.assertEquals(expected, actual); 8044 } 8045 testReadBooleanQueryParameter()8046 public void testReadBooleanQueryParameter() { 8047 assertBooleanUriParameter("foo:bar", "bool", true, true); 8048 assertBooleanUriParameter("foo:bar", "bool", false, false); 8049 assertBooleanUriParameter("foo:bar?bool=0", "bool", true, false); 8050 assertBooleanUriParameter("foo:bar?bool=1", "bool", false, true); 8051 assertBooleanUriParameter("foo:bar?bool=false", "bool", true, false); 8052 assertBooleanUriParameter("foo:bar?bool=true", "bool", false, true); 8053 assertBooleanUriParameter("foo:bar?bool=FaLsE", "bool", true, false); 8054 assertBooleanUriParameter("foo:bar?bool=false&some=some", "bool", true, false); 8055 assertBooleanUriParameter("foo:bar?bool=1&some=some", "bool", false, true); 8056 assertBooleanUriParameter("foo:bar?some=bool", "bool", true, true); 8057 assertBooleanUriParameter("foo:bar?bool", "bool", true, true); 8058 } 8059 assertBooleanUriParameter(String uriString, String parameter, boolean defaultValue, boolean expectedValue)8060 private void assertBooleanUriParameter(String uriString, String parameter, 8061 boolean defaultValue, boolean expectedValue) { 8062 assertEquals(expectedValue, ContactsProvider2.readBooleanQueryParameter( 8063 Uri.parse(uriString), parameter, defaultValue)); 8064 } 8065 testGetQueryParameter()8066 public void testGetQueryParameter() { 8067 assertQueryParameter("foo:bar", "param", null); 8068 assertQueryParameter("foo:bar?param", "param", null); 8069 assertQueryParameter("foo:bar?param=", "param", ""); 8070 assertQueryParameter("foo:bar?param=val", "param", "val"); 8071 assertQueryParameter("foo:bar?param=val&some=some", "param", "val"); 8072 assertQueryParameter("foo:bar?some=some¶m=val", "param", "val"); 8073 assertQueryParameter("foo:bar?some=some¶m=val&else=else", "param", "val"); 8074 assertQueryParameter("foo:bar?param=john%40doe.com", "param", "john@doe.com"); 8075 assertQueryParameter("foo:bar?some_param=val", "param", null); 8076 assertQueryParameter("foo:bar?some_param=val1¶m=val2", "param", "val2"); 8077 assertQueryParameter("foo:bar?some_param=val1¶m=", "param", ""); 8078 assertQueryParameter("foo:bar?some_param=val1¶m", "param", null); 8079 assertQueryParameter("foo:bar?some_param=val1&another_param=val2¶m=val3", 8080 "param", "val3"); 8081 assertQueryParameter("foo:bar?some_param=val1¶m=val2&some_param=val3", 8082 "param", "val2"); 8083 assertQueryParameter("foo:bar?param=val1&some_param=val2", "param", "val1"); 8084 assertQueryParameter("foo:bar?p=val1&pp=val2", "p", "val1"); 8085 assertQueryParameter("foo:bar?pp=val1&p=val2", "p", "val2"); 8086 assertQueryParameter("foo:bar?ppp=val1&pp=val2&p=val3", "p", "val3"); 8087 assertQueryParameter("foo:bar?ppp=val&", "p", null); 8088 } 8089 testMissingAccountTypeParameter()8090 public void testMissingAccountTypeParameter() { 8091 // Try querying for RawContacts only using ACCOUNT_NAME 8092 final Uri queryUri = RawContacts.CONTENT_URI.buildUpon().appendQueryParameter( 8093 RawContacts.ACCOUNT_NAME, "lolwut").build(); 8094 try { 8095 final Cursor cursor = mResolver.query(queryUri, null, null, null, null); 8096 fail("Able to query with incomplete account query parameters"); 8097 } catch (IllegalArgumentException e) { 8098 // Expected behavior. 8099 } 8100 } 8101 testInsertInconsistentAccountType()8102 public void testInsertInconsistentAccountType() { 8103 // Try inserting RawContact with inconsistent Accounts 8104 final Account red = new Account("red", "red"); 8105 final Account blue = new Account("blue", "blue"); 8106 8107 final ContentValues values = new ContentValues(); 8108 values.put(RawContacts.ACCOUNT_NAME, red.name); 8109 values.put(RawContacts.ACCOUNT_TYPE, red.type); 8110 8111 final Uri insertUri = TestUtil.maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, 8112 blue); 8113 try { 8114 mResolver.insert(insertUri, values); 8115 fail("Able to insert RawContact with inconsistent account details"); 8116 } catch (IllegalArgumentException e) { 8117 // Expected behavior. 8118 } 8119 } 8120 testProviderStatusNoContactsNoAccounts()8121 public void testProviderStatusNoContactsNoAccounts() throws Exception { 8122 assertProviderStatus(ProviderStatus.STATUS_EMPTY); 8123 } 8124 testProviderStatusOnlyLocalContacts()8125 public void testProviderStatusOnlyLocalContacts() throws Exception { 8126 long rawContactId = RawContactUtil.createRawContact(mResolver); 8127 assertProviderStatus(ProviderStatus.STATUS_NORMAL); 8128 mResolver.delete( 8129 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), null, null); 8130 assertProviderStatus(ProviderStatus.STATUS_EMPTY); 8131 } 8132 testProviderStatusWithAccounts()8133 public void testProviderStatusWithAccounts() throws Exception { 8134 assertProviderStatus(ProviderStatus.STATUS_EMPTY); 8135 mActor.setAccounts(new Account[]{TestUtil.ACCOUNT_1}); 8136 ((ContactsProvider2)getProvider()).onAccountsUpdated(new Account[]{TestUtil.ACCOUNT_1}); 8137 assertProviderStatus(ProviderStatus.STATUS_NORMAL); 8138 mActor.setAccounts(new Account[0]); 8139 ((ContactsProvider2)getProvider()).onAccountsUpdated(new Account[0]); 8140 assertProviderStatus(ProviderStatus.STATUS_EMPTY); 8141 } 8142 assertProviderStatus(int expectedProviderStatus)8143 private void assertProviderStatus(int expectedProviderStatus) { 8144 Cursor cursor = mResolver.query(ProviderStatus.CONTENT_URI, 8145 new String[]{ProviderStatus.STATUS}, null, null, 8146 null); 8147 assertTrue(cursor.moveToFirst()); 8148 assertEquals(expectedProviderStatus, cursor.getInt(0)); 8149 cursor.close(); 8150 } 8151 testProperties()8152 public void testProperties() throws Exception { 8153 ContactsProvider2 provider = (ContactsProvider2)getProvider(); 8154 ContactsDatabaseHelper helper = (ContactsDatabaseHelper)provider.getDatabaseHelper(); 8155 assertNull(helper.getProperty("non-existent", null)); 8156 assertEquals("default", helper.getProperty("non-existent", "default")); 8157 8158 helper.setProperty("existent1", "string1"); 8159 helper.setProperty("existent2", "string2"); 8160 assertEquals("string1", helper.getProperty("existent1", "default")); 8161 assertEquals("string2", helper.getProperty("existent2", "default")); 8162 helper.setProperty("existent1", null); 8163 assertEquals("default", helper.getProperty("existent1", "default")); 8164 } 8165 8166 private class VCardTestUriCreator { 8167 private String mLookup1; 8168 private String mLookup2; 8169 VCardTestUriCreator(String lookup1, String lookup2)8170 public VCardTestUriCreator(String lookup1, String lookup2) { 8171 super(); 8172 mLookup1 = lookup1; 8173 mLookup2 = lookup2; 8174 } 8175 getUri1()8176 public Uri getUri1() { 8177 return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup1); 8178 } 8179 getUri2()8180 public Uri getUri2() { 8181 return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup2); 8182 } 8183 getCombinedUri()8184 public Uri getCombinedUri() { 8185 return Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, 8186 Uri.encode(mLookup1 + ":" + mLookup2)); 8187 } 8188 } 8189 createVCardTestContacts()8190 private VCardTestUriCreator createVCardTestContacts() { 8191 final long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount, 8192 RawContacts.SOURCE_ID, "4:12"); 8193 DataUtil.insertStructuredName(mResolver, rawContactId1, "John", "Doe"); 8194 8195 final long rawContactId2 = RawContactUtil.createRawContact(mResolver, mAccount, 8196 RawContacts.SOURCE_ID, "3:4%121"); 8197 DataUtil.insertStructuredName(mResolver, rawContactId2, "Jane", "Doh"); 8198 8199 final long contactId1 = queryContactId(rawContactId1); 8200 final long contactId2 = queryContactId(rawContactId2); 8201 final Uri contact1Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId1); 8202 final Uri contact2Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId2); 8203 final String lookup1 = 8204 Uri.encode(Contacts.getLookupUri(mResolver, contact1Uri).getPathSegments().get(2)); 8205 final String lookup2 = 8206 Uri.encode(Contacts.getLookupUri(mResolver, contact2Uri).getPathSegments().get(2)); 8207 return new VCardTestUriCreator(lookup1, lookup2); 8208 } 8209 testQueryMultiVCard()8210 public void testQueryMultiVCard() { 8211 // No need to create any contacts here, because the query for multiple vcards 8212 // does not go into the database at all 8213 Uri uri = Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, Uri.encode("123:456")); 8214 Cursor cursor = mResolver.query(uri, null, null, null, null); 8215 assertEquals(1, cursor.getCount()); 8216 assertTrue(cursor.moveToFirst()); 8217 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 8218 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 8219 8220 // The resulting name contains date and time. Ensure that before and after are correct 8221 assertTrue(filename.startsWith("vcards_")); 8222 assertTrue(filename.endsWith(".vcf")); 8223 cursor.close(); 8224 } 8225 testQueryFileSingleVCard()8226 public void testQueryFileSingleVCard() { 8227 final VCardTestUriCreator contacts = createVCardTestContacts(); 8228 8229 { 8230 Cursor cursor = mResolver.query(contacts.getUri1(), null, null, null, null); 8231 assertEquals(1, cursor.getCount()); 8232 assertTrue(cursor.moveToFirst()); 8233 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 8234 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 8235 assertEquals("John Doe.vcf", filename); 8236 cursor.close(); 8237 } 8238 8239 { 8240 Cursor cursor = mResolver.query(contacts.getUri2(), null, null, null, null); 8241 assertEquals(1, cursor.getCount()); 8242 assertTrue(cursor.moveToFirst()); 8243 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 8244 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 8245 assertEquals("Jane Doh.vcf", filename); 8246 cursor.close(); 8247 } 8248 } 8249 testQueryFileProfileVCard()8250 public void testQueryFileProfileVCard() { 8251 createBasicProfileContact(new ContentValues()); 8252 Cursor cursor = mResolver.query(Profile.CONTENT_VCARD_URI, null, null, null, null); 8253 assertEquals(1, cursor.getCount()); 8254 assertTrue(cursor.moveToFirst()); 8255 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 8256 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 8257 assertEquals("Mia Prophyl.vcf", filename); 8258 cursor.close(); 8259 } 8260 testOpenAssetFileMultiVCard()8261 public void testOpenAssetFileMultiVCard() throws IOException { 8262 final VCardTestUriCreator contacts = createVCardTestContacts(); 8263 8264 final AssetFileDescriptor descriptor = 8265 mResolver.openAssetFileDescriptor(contacts.getCombinedUri(), "r"); 8266 final FileInputStream inputStream = descriptor.createInputStream(); 8267 String data = readToEnd(inputStream); 8268 inputStream.close(); 8269 descriptor.close(); 8270 8271 // Ensure that the resulting VCard has both contacts 8272 assertTrue(data.contains("N:Doe;John;;;")); 8273 assertTrue(data.contains("N:Doh;Jane;;;")); 8274 } 8275 testOpenAssetFileSingleVCard()8276 public void testOpenAssetFileSingleVCard() throws IOException { 8277 final VCardTestUriCreator contacts = createVCardTestContacts(); 8278 8279 // Ensure that the right VCard is being created in each case 8280 { 8281 final AssetFileDescriptor descriptor = 8282 mResolver.openAssetFileDescriptor(contacts.getUri1(), "r"); 8283 final FileInputStream inputStream = descriptor.createInputStream(); 8284 final String data = readToEnd(inputStream); 8285 inputStream.close(); 8286 descriptor.close(); 8287 8288 assertTrue(data.contains("N:Doe;John;;;")); 8289 assertFalse(data.contains("N:Doh;Jane;;;")); 8290 } 8291 8292 { 8293 final AssetFileDescriptor descriptor = 8294 mResolver.openAssetFileDescriptor(contacts.getUri2(), "r"); 8295 final FileInputStream inputStream = descriptor.createInputStream(); 8296 final String data = readToEnd(inputStream); 8297 inputStream.close(); 8298 descriptor.close(); 8299 8300 assertFalse(data.contains("N:Doe;John;;;")); 8301 assertTrue(data.contains("N:Doh;Jane;;;")); 8302 } 8303 } 8304 testAutoGroupMembership()8305 public void testAutoGroupMembership() { 8306 long g1 = createGroup(mAccount, "g1", "t1", 0, true /* autoAdd */, false /* favorite */); 8307 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 8308 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, true /* autoAdd */, false /* favorite */); 8309 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, false/* favorite */); 8310 long r1 = RawContactUtil.createRawContact(mResolver, mAccount); 8311 long r2 = RawContactUtil.createRawContact(mResolver, mAccountTwo); 8312 long r3 = RawContactUtil.createRawContact(mResolver, null); 8313 8314 Cursor c = queryGroupMemberships(mAccount); 8315 try { 8316 assertTrue(c.moveToNext()); 8317 assertEquals(g1, c.getLong(0)); 8318 assertEquals(r1, c.getLong(1)); 8319 assertFalse(c.moveToNext()); 8320 } finally { 8321 c.close(); 8322 } 8323 8324 c = queryGroupMemberships(mAccountTwo); 8325 try { 8326 assertTrue(c.moveToNext()); 8327 assertEquals(g3, c.getLong(0)); 8328 assertEquals(r2, c.getLong(1)); 8329 assertFalse(c.moveToNext()); 8330 } finally { 8331 c.close(); 8332 } 8333 } 8334 testNoAutoAddMembershipAfterGroupCreation()8335 public void testNoAutoAddMembershipAfterGroupCreation() { 8336 long r1 = RawContactUtil.createRawContact(mResolver, mAccount); 8337 long r2 = RawContactUtil.createRawContact(mResolver, mAccount); 8338 long r3 = RawContactUtil.createRawContact(mResolver, mAccount); 8339 long r4 = RawContactUtil.createRawContact(mResolver, mAccountTwo); 8340 long r5 = RawContactUtil.createRawContact(mResolver, mAccountTwo); 8341 long r6 = RawContactUtil.createRawContact(mResolver, null); 8342 8343 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 8344 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8345 8346 long g1 = createGroup(mAccount, "g1", "t1", 0, true /* autoAdd */, false /* favorite */); 8347 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 8348 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, true /* autoAdd */, false/* favorite */); 8349 8350 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 8351 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8352 } 8353 8354 // create some starred and non-starred contacts, some associated with account, some not 8355 // favorites group created 8356 // the starred contacts should be added to group 8357 // favorites group removed 8358 // no change to starred status testFavoritesMembershipAfterGroupCreation()8359 public void testFavoritesMembershipAfterGroupCreation() { 8360 long r1 = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.STARRED, "1"); 8361 long r2 = RawContactUtil.createRawContact(mResolver, mAccount); 8362 long r3 = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.STARRED, "1"); 8363 long r4 = RawContactUtil.createRawContact(mResolver, mAccountTwo, RawContacts.STARRED, "1"); 8364 long r5 = RawContactUtil.createRawContact(mResolver, mAccountTwo); 8365 long r6 = RawContactUtil.createRawContact(mResolver, null, RawContacts.STARRED, "1"); 8366 long r7 = RawContactUtil.createRawContact(mResolver, null); 8367 8368 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 8369 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8370 8371 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 8372 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 8373 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, false /* autoAdd */, false/* favorite */); 8374 8375 assertTrue(queryRawContactIsStarred(r1)); 8376 assertFalse(queryRawContactIsStarred(r2)); 8377 assertTrue(queryRawContactIsStarred(r3)); 8378 assertTrue(queryRawContactIsStarred(r4)); 8379 assertFalse(queryRawContactIsStarred(r5)); 8380 assertTrue(queryRawContactIsStarred(r6)); 8381 assertFalse(queryRawContactIsStarred(r7)); 8382 8383 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8384 Cursor c = queryGroupMemberships(mAccount); 8385 try { 8386 assertTrue(c.moveToNext()); 8387 assertEquals(g1, c.getLong(0)); 8388 assertEquals(r1, c.getLong(1)); 8389 assertTrue(c.moveToNext()); 8390 assertEquals(g1, c.getLong(0)); 8391 assertEquals(r3, c.getLong(1)); 8392 assertFalse(c.moveToNext()); 8393 } finally { 8394 c.close(); 8395 } 8396 8397 updateItem(RawContacts.CONTENT_URI, r6, 8398 RawContacts.ACCOUNT_NAME, mAccount.name, 8399 RawContacts.ACCOUNT_TYPE, mAccount.type); 8400 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8401 c = queryGroupMemberships(mAccount); 8402 try { 8403 assertTrue(c.moveToNext()); 8404 assertEquals(g1, c.getLong(0)); 8405 assertEquals(r1, c.getLong(1)); 8406 assertTrue(c.moveToNext()); 8407 assertEquals(g1, c.getLong(0)); 8408 assertEquals(r3, c.getLong(1)); 8409 assertTrue(c.moveToNext()); 8410 assertEquals(g1, c.getLong(0)); 8411 assertEquals(r6, c.getLong(1)); 8412 assertFalse(c.moveToNext()); 8413 } finally { 8414 c.close(); 8415 } 8416 8417 mResolver.delete(ContentUris.withAppendedId(Groups.CONTENT_URI, g1), null, null); 8418 8419 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 8420 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8421 8422 assertTrue(queryRawContactIsStarred(r1)); 8423 assertFalse(queryRawContactIsStarred(r2)); 8424 assertTrue(queryRawContactIsStarred(r3)); 8425 assertTrue(queryRawContactIsStarred(r4)); 8426 assertFalse(queryRawContactIsStarred(r5)); 8427 assertTrue(queryRawContactIsStarred(r6)); 8428 assertFalse(queryRawContactIsStarred(r7)); 8429 } 8430 testFavoritesGroupMembershipChangeAfterStarChange()8431 public void testFavoritesGroupMembershipChangeAfterStarChange() { 8432 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 8433 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false/* favorite */); 8434 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, true /* favorite */); 8435 long g5 = createGroup(mAccountTwo, "g5", "t5", 0, false /* autoAdd */, false/* favorite */); 8436 long r1 = RawContactUtil.createRawContact(mResolver, mAccount, RawContacts.STARRED, "1"); 8437 long r2 = RawContactUtil.createRawContact(mResolver, mAccount); 8438 long r3 = RawContactUtil.createRawContact(mResolver, mAccountTwo); 8439 8440 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8441 Cursor c = queryGroupMemberships(mAccount); 8442 try { 8443 assertTrue(c.moveToNext()); 8444 assertEquals(g1, c.getLong(0)); 8445 assertEquals(r1, c.getLong(1)); 8446 assertFalse(c.moveToNext()); 8447 } finally { 8448 c.close(); 8449 } 8450 8451 // remove the star from r1 8452 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "0")); 8453 8454 // Since no raw contacts are starred, there should be no group memberships. 8455 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 8456 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8457 8458 // mark r1 as starred 8459 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "1")); 8460 // Now that r1 is starred it should have a membership in the one groups from mAccount 8461 // that is marked as a favorite. 8462 // There should be no memberships in mAccountTwo since it has no starred raw contacts. 8463 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8464 c = queryGroupMemberships(mAccount); 8465 try { 8466 assertTrue(c.moveToNext()); 8467 assertEquals(g1, c.getLong(0)); 8468 assertEquals(r1, c.getLong(1)); 8469 assertFalse(c.moveToNext()); 8470 } finally { 8471 c.close(); 8472 } 8473 8474 // remove the star from r1 8475 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "0")); 8476 // Since no raw contacts are starred, there should be no group memberships. 8477 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 8478 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8479 8480 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(r1)); 8481 assertNotNull(contactUri); 8482 8483 // mark r1 as starred via its contact lookup uri 8484 assertEquals(1, updateItem(contactUri, Contacts.STARRED, "1")); 8485 // Now that r1 is starred it should have a membership in the one groups from mAccount 8486 // that is marked as a favorite. 8487 // There should be no memberships in mAccountTwo since it has no starred raw contacts. 8488 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8489 c = queryGroupMemberships(mAccount); 8490 try { 8491 assertTrue(c.moveToNext()); 8492 assertEquals(g1, c.getLong(0)); 8493 assertEquals(r1, c.getLong(1)); 8494 assertFalse(c.moveToNext()); 8495 } finally { 8496 c.close(); 8497 } 8498 8499 // remove the star from r1 8500 updateItem(contactUri, Contacts.STARRED, "0"); 8501 // Since no raw contacts are starred, there should be no group memberships. 8502 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 8503 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8504 } 8505 testStarChangedAfterGroupMembershipChange()8506 public void testStarChangedAfterGroupMembershipChange() { 8507 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 8508 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false/* favorite */); 8509 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, true /* favorite */); 8510 long g5 = createGroup(mAccountTwo, "g5", "t5", 0, false /* autoAdd */, false/* favorite */); 8511 long r1 = RawContactUtil.createRawContact(mResolver, mAccount); 8512 long r2 = RawContactUtil.createRawContact(mResolver, mAccount); 8513 long r3 = RawContactUtil.createRawContact(mResolver, mAccountTwo); 8514 8515 assertFalse(queryRawContactIsStarred(r1)); 8516 assertFalse(queryRawContactIsStarred(r2)); 8517 assertFalse(queryRawContactIsStarred(r3)); 8518 8519 Cursor c; 8520 8521 // add r1 to one favorites group 8522 // r1's star should automatically be set 8523 // r1 should automatically be added to the other favorites group 8524 Uri urir1g1 = insertGroupMembership(r1, g1); 8525 assertTrue(queryRawContactIsStarred(r1)); 8526 assertFalse(queryRawContactIsStarred(r2)); 8527 assertFalse(queryRawContactIsStarred(r3)); 8528 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8529 c = queryGroupMemberships(mAccount); 8530 try { 8531 assertTrue(c.moveToNext()); 8532 assertEquals(g1, c.getLong(0)); 8533 assertEquals(r1, c.getLong(1)); 8534 assertFalse(c.moveToNext()); 8535 } finally { 8536 c.close(); 8537 } 8538 8539 // remove r1 from one favorites group 8540 mResolver.delete(urir1g1, null, null); 8541 // r1's star should no longer be set 8542 assertFalse(queryRawContactIsStarred(r1)); 8543 assertFalse(queryRawContactIsStarred(r2)); 8544 assertFalse(queryRawContactIsStarred(r3)); 8545 // there should be no membership rows 8546 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 8547 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8548 8549 // add r3 to the one favorites group for that account 8550 // r3's star should automatically be set 8551 Uri urir3g4 = insertGroupMembership(r3, g4); 8552 assertFalse(queryRawContactIsStarred(r1)); 8553 assertFalse(queryRawContactIsStarred(r2)); 8554 assertTrue(queryRawContactIsStarred(r3)); 8555 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 8556 c = queryGroupMemberships(mAccountTwo); 8557 try { 8558 assertTrue(c.moveToNext()); 8559 assertEquals(g4, c.getLong(0)); 8560 assertEquals(r3, c.getLong(1)); 8561 assertFalse(c.moveToNext()); 8562 } finally { 8563 c.close(); 8564 } 8565 8566 // remove r3 from the favorites group 8567 mResolver.delete(urir3g4, null, null); 8568 // r3's star should automatically be cleared 8569 assertFalse(queryRawContactIsStarred(r1)); 8570 assertFalse(queryRawContactIsStarred(r2)); 8571 assertFalse(queryRawContactIsStarred(r3)); 8572 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 8573 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 8574 } 8575 testReadOnlyRawContact()8576 public void testReadOnlyRawContact() { 8577 long rawContactId = RawContactUtil.createRawContact(mResolver); 8578 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 8579 storeValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "first"); 8580 storeValue(rawContactUri, RawContacts.RAW_CONTACT_IS_READ_ONLY, 1); 8581 8582 storeValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "second"); 8583 assertStoredValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "first"); 8584 8585 Uri syncAdapterUri = rawContactUri.buildUpon() 8586 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "1") 8587 .build(); 8588 storeValue(syncAdapterUri, RawContacts.CUSTOM_RINGTONE, "third"); 8589 assertStoredValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "third"); 8590 } 8591 testReadOnlyDataRow()8592 public void testReadOnlyDataRow() { 8593 long rawContactId = RawContactUtil.createRawContact(mResolver); 8594 Uri emailUri = insertEmail(rawContactId, "email"); 8595 Uri phoneUri = insertPhoneNumber(rawContactId, "555-1111"); 8596 8597 storeValue(emailUri, Data.IS_READ_ONLY, "1"); 8598 storeValue(emailUri, Email.ADDRESS, "changed"); 8599 storeValue(phoneUri, Phone.NUMBER, "555-2222"); 8600 assertStoredValue(emailUri, Email.ADDRESS, "email"); 8601 assertStoredValue(phoneUri, Phone.NUMBER, "555-2222"); 8602 8603 Uri syncAdapterUri = emailUri.buildUpon() 8604 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "1") 8605 .build(); 8606 storeValue(syncAdapterUri, Email.ADDRESS, "changed"); 8607 assertStoredValue(emailUri, Email.ADDRESS, "changed"); 8608 } 8609 testContactWithReadOnlyRawContact()8610 public void testContactWithReadOnlyRawContact() { 8611 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 8612 Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 8613 storeValue(rawContactUri1, RawContacts.CUSTOM_RINGTONE, "first"); 8614 8615 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 8616 Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2); 8617 storeValue(rawContactUri2, RawContacts.CUSTOM_RINGTONE, "second"); 8618 storeValue(rawContactUri2, RawContacts.RAW_CONTACT_IS_READ_ONLY, 1); 8619 8620 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 8621 rawContactId1, rawContactId2); 8622 8623 long contactId = queryContactId(rawContactId1); 8624 8625 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 8626 storeValue(contactUri, Contacts.CUSTOM_RINGTONE, "rt"); 8627 assertStoredValue(contactUri, Contacts.CUSTOM_RINGTONE, "rt"); 8628 assertStoredValue(rawContactUri1, RawContacts.CUSTOM_RINGTONE, "rt"); 8629 assertStoredValue(rawContactUri2, RawContacts.CUSTOM_RINGTONE, "second"); 8630 } 8631 testNameParsingQuery()8632 public void testNameParsingQuery() { 8633 Uri uri = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name") 8634 .appendQueryParameter(StructuredName.DISPLAY_NAME, "Mr. John Q. Doe Jr.").build(); 8635 Cursor cursor = mResolver.query(uri, null, null, null, null); 8636 ContentValues values = new ContentValues(); 8637 values.put(StructuredName.DISPLAY_NAME, "Mr. John Q. Doe Jr."); 8638 values.put(StructuredName.PREFIX, "Mr."); 8639 values.put(StructuredName.GIVEN_NAME, "John"); 8640 values.put(StructuredName.MIDDLE_NAME, "Q."); 8641 values.put(StructuredName.FAMILY_NAME, "Doe"); 8642 values.put(StructuredName.SUFFIX, "Jr."); 8643 values.put(StructuredName.FULL_NAME_STYLE, FullNameStyle.WESTERN); 8644 assertTrue(cursor.moveToFirst()); 8645 assertCursorValues(cursor, values); 8646 cursor.close(); 8647 } 8648 testNameConcatenationQuery()8649 public void testNameConcatenationQuery() { 8650 Uri uri = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name") 8651 .appendQueryParameter(StructuredName.PREFIX, "Mr") 8652 .appendQueryParameter(StructuredName.GIVEN_NAME, "John") 8653 .appendQueryParameter(StructuredName.MIDDLE_NAME, "Q.") 8654 .appendQueryParameter(StructuredName.FAMILY_NAME, "Doe") 8655 .appendQueryParameter(StructuredName.SUFFIX, "Jr.") 8656 .build(); 8657 Cursor cursor = mResolver.query(uri, null, null, null, null); 8658 ContentValues values = new ContentValues(); 8659 values.put(StructuredName.DISPLAY_NAME, "Mr John Q. Doe, Jr."); 8660 values.put(StructuredName.PREFIX, "Mr"); 8661 values.put(StructuredName.GIVEN_NAME, "John"); 8662 values.put(StructuredName.MIDDLE_NAME, "Q."); 8663 values.put(StructuredName.FAMILY_NAME, "Doe"); 8664 values.put(StructuredName.SUFFIX, "Jr."); 8665 values.put(StructuredName.FULL_NAME_STYLE, FullNameStyle.WESTERN); 8666 assertTrue(cursor.moveToFirst()); 8667 assertCursorValues(cursor, values); 8668 cursor.close(); 8669 } 8670 testBuildSingleRowResult()8671 public void testBuildSingleRowResult() { 8672 checkBuildSingleRowResult( 8673 new String[] {"b"}, 8674 new String[] {"a", "b"}, 8675 new Integer[] {1, 2}, 8676 new Integer[] {2} 8677 ); 8678 8679 checkBuildSingleRowResult( 8680 new String[] {"b", "a", "b"}, 8681 new String[] {"a", "b"}, 8682 new Integer[] {1, 2}, 8683 new Integer[] {2, 1, 2} 8684 ); 8685 8686 checkBuildSingleRowResult( 8687 null, // all columns 8688 new String[] {"a", "b"}, 8689 new Integer[] {1, 2}, 8690 new Integer[] {1, 2} 8691 ); 8692 8693 try { 8694 // Access non-existent column 8695 ContactsProvider2.buildSingleRowResult(new String[] {"a"}, new String[] {"b"}, 8696 new Object[] {1}); 8697 fail(); 8698 } catch (IllegalArgumentException expected) { 8699 } 8700 } 8701 checkBuildSingleRowResult(String[] projection, String[] availableColumns, Object[] data, Integer[] expectedValues)8702 private void checkBuildSingleRowResult(String[] projection, String[] availableColumns, 8703 Object[] data, Integer[] expectedValues) { 8704 final Cursor c = ContactsProvider2.buildSingleRowResult(projection, availableColumns, data); 8705 try { 8706 assertTrue(c.moveToFirst()); 8707 assertEquals(1, c.getCount()); 8708 assertEquals(expectedValues.length, c.getColumnCount()); 8709 8710 for (int i = 0; i < expectedValues.length; i++) { 8711 assertEquals("column " + i, expectedValues[i], (Integer) c.getInt(i)); 8712 } 8713 } finally { 8714 c.close(); 8715 } 8716 } 8717 testDataUsageFeedbackAndDelete()8718 public void testDataUsageFeedbackAndDelete() { 8719 8720 sMockClock.install(); 8721 sMockClock.setCurrentTimeMillis(System.currentTimeMillis()); 8722 final long startTime = sMockClock.currentTimeMillis(); 8723 8724 final long rid1 = RawContactUtil.createRawContactWithName(mResolver, "contact", "a"); 8725 final long did1a = ContentUris.parseId(insertEmail(rid1, "email_1_a@email.com")); 8726 final long did1b = ContentUris.parseId(insertEmail(rid1, "email_1_b@email.com")); 8727 final long did1p = ContentUris.parseId(insertPhoneNumber(rid1, "555-555-5555")); 8728 8729 final long rid2 = RawContactUtil.createRawContactWithName(mResolver, "contact", "b"); 8730 final long did2a = ContentUris.parseId(insertEmail(rid2, "email_2_a@email.com")); 8731 final long did2p = ContentUris.parseId(insertPhoneNumber(rid2, "555-555-5556")); 8732 8733 // Aggregate 1 and 2 8734 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rid1, rid2); 8735 8736 final long rid3 = RawContactUtil.createRawContactWithName(mResolver, "contact", "c"); 8737 final long did3a = ContentUris.parseId(insertEmail(rid3, "email_3@email.com")); 8738 final long did3p = ContentUris.parseId(insertPhoneNumber(rid3, "555-3333")); 8739 8740 final long rid4 = RawContactUtil.createRawContactWithName(mResolver, "contact", "d"); 8741 final long did4p = ContentUris.parseId(insertPhoneNumber(rid4, "555-4444")); 8742 8743 final long cid1 = queryContactId(rid1); 8744 final long cid3 = queryContactId(rid3); 8745 final long cid4 = queryContactId(rid4); 8746 8747 // Make sure 1+2, 3 and 4 aren't aggregated 8748 MoreAsserts.assertNotEqual(cid1, cid3); 8749 MoreAsserts.assertNotEqual(cid1, cid4); 8750 MoreAsserts.assertNotEqual(cid3, cid4); 8751 8752 // time = startTime 8753 8754 // First, there's no frequent. (We use strequent here only because frequent is hidden 8755 // and may be removed someday.) 8756 assertRowCount(0, Contacts.CONTENT_STREQUENT_URI, null, null); 8757 8758 // Test 1. touch data 1a 8759 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, did1a); 8760 8761 // (We no longer populate frequent, so 0.) 8762 assertRowCount(0, Contacts.CONTENT_STREQUENT_URI, null, null); 8763 8764 sMockClock.advanceDay(); 8765 8766 // Test 2. touch data 1a, 2a and 3a 8767 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, did1a, did2a, did3a); 8768 8769 // (We no longer populate frequent, so 0.) 8770 assertRowCount(0, Contacts.CONTENT_STREQUENT_URI, null, null); 8771 8772 sMockClock.advanceDay(); 8773 8774 // Test 2. touch data 2p (call) 8775 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did2p); 8776 8777 // (We no longer populate frequent, so 0.) 8778 assertRowCount(0, Contacts.CONTENT_STREQUENT_URI, null, null); 8779 8780 sMockClock.advanceDay(); 8781 8782 // Test 3. touch data 2p and 3p (short text) 8783 updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, did2p, did3p); 8784 8785 // Let's check the tables. 8786 8787 // Fist, check the data_usage_stat table, which has no public URI. 8788 assertStoredValuesDb("SELECT " + DataUsageStatColumns.DATA_ID + 8789 "," + DataUsageStatColumns.USAGE_TYPE_INT + 8790 "," + DataUsageStatColumns.RAW_TIMES_USED + 8791 "," + DataUsageStatColumns.RAW_LAST_TIME_USED + 8792 " FROM " + Tables.DATA_USAGE_STAT, null 8793 ); 8794 8795 // Next, check the raw_contacts table 8796 assertStoredValuesWithProjection(RawContacts.CONTENT_URI, 8797 cv(RawContacts._ID, rid1, 8798 RawContacts.TIMES_CONTACTED, 0, 8799 RawContacts.LAST_TIME_CONTACTED, 0 8800 ), 8801 cv(RawContacts._ID, rid2, 8802 RawContacts.TIMES_CONTACTED, 0, 8803 RawContacts.LAST_TIME_CONTACTED, 0 8804 ), 8805 cv(RawContacts._ID, rid3, 8806 RawContacts.TIMES_CONTACTED, 0, 8807 RawContacts.LAST_TIME_CONTACTED, 0 8808 ), 8809 cv(RawContacts._ID, rid4, 8810 RawContacts.TIMES_CONTACTED, 0, 8811 RawContacts.LAST_TIME_CONTACTED, 0 8812 ) 8813 ); 8814 8815 // Lastly, check the contacts table. 8816 8817 // Note contact1.TIMES_CONTACTED = 4, even though raw_contact1.TIMES_CONTACTED + 8818 // raw_contact1.TIMES_CONTACTED = 5, because in test 2, data 1a and data 2a were touched 8819 // at once. 8820 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 8821 cv(Contacts._ID, cid1, 8822 Contacts.TIMES_CONTACTED, 0, 8823 Contacts.LAST_TIME_CONTACTED, 0 8824 ), 8825 cv(Contacts._ID, cid3, 8826 Contacts.TIMES_CONTACTED, 0, 8827 Contacts.LAST_TIME_CONTACTED, 0 8828 ), 8829 cv(Contacts._ID, cid4, 8830 Contacts.TIMES_CONTACTED, 0, 8831 Contacts.LAST_TIME_CONTACTED, 0 8832 ) 8833 ); 8834 8835 // Let's test the delete too. 8836 assertTrue(mResolver.delete(DataUsageFeedback.DELETE_USAGE_URI, null, null) > 0); 8837 8838 // Now there's no frequent. 8839 assertRowCount(0, Contacts.CONTENT_STREQUENT_URI, null, null); 8840 8841 // No rows in the stats table. 8842 assertStoredValuesDb("SELECT " + DataUsageStatColumns.DATA_ID + 8843 " FROM " + Tables.DATA_USAGE_STAT, null, 8844 new ContentValues[0]); 8845 8846 // The following values should all be 0 or null. 8847 assertRowCount(0, Contacts.CONTENT_URI, Contacts.TIMES_CONTACTED + ">0", null); 8848 assertRowCount(0, Contacts.CONTENT_URI, Contacts.LAST_TIME_CONTACTED + ">0", null); 8849 assertRowCount(0, RawContacts.CONTENT_URI, RawContacts.TIMES_CONTACTED + ">0", null); 8850 assertRowCount(0, RawContacts.CONTENT_URI, RawContacts.LAST_TIME_CONTACTED + ">0", null); 8851 8852 // Calling it when there's no usage stats will still return a positive value. 8853 assertTrue(mResolver.delete(DataUsageFeedback.DELETE_USAGE_URI, null, null) > 0); 8854 } 8855 8856 /******************************************************* 8857 * Delta api tests. 8858 */ testContactDelete_hasDeleteLog()8859 public void testContactDelete_hasDeleteLog() { 8860 sMockClock.install(); 8861 long start = sMockClock.currentTimeMillis(); 8862 DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete(); 8863 DatabaseAsserts.assertHasDeleteLogGreaterThan(mResolver, ids.mContactId, start); 8864 8865 // Clean up. Must also remove raw contact. 8866 RawContactUtil.delete(mResolver, ids.mRawContactId, true); 8867 } 8868 testContactDelete_marksRawContactsForDeletion()8869 public void testContactDelete_marksRawContactsForDeletion() { 8870 DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete(mAccount); 8871 8872 String[] projection = new String[]{ContactsContract.RawContacts.DIRTY, 8873 ContactsContract.RawContacts.DELETED}; 8874 String[] record = RawContactUtil.queryByRawContactId(mResolver, ids.mRawContactId, 8875 projection); 8876 assertEquals("1", record[0]); 8877 assertEquals("1", record[1]); 8878 8879 // Clean up 8880 RawContactUtil.delete(mResolver, ids.mRawContactId, true); 8881 } 8882 testContactDelete_checkRawContactContactId()8883 public void testContactDelete_checkRawContactContactId() { 8884 DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete(mAccount); 8885 8886 String[] projection = new String[]{ContactsContract.RawContacts.CONTACT_ID}; 8887 String[] record = RawContactUtil.queryByRawContactId(mResolver, ids.mRawContactId, 8888 projection); 8889 assertNull(record[0]); 8890 8891 // Clean up 8892 RawContactUtil.delete(mResolver, ids.mRawContactId, true); 8893 } 8894 testContactUpdate_metadataChange()8895 public void testContactUpdate_metadataChange() { 8896 DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver); 8897 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, ids.mRawContactId); 8898 assertDirty(rawContactUri, true); 8899 clearDirty(rawContactUri); 8900 8901 ContentValues values = new ContentValues(); 8902 values.put(Contacts.PINNED, 1); 8903 8904 ContactUtil.update(mResolver, ids.mContactId, values); 8905 assertDirty(rawContactUri, false); 8906 assertMetadataDirty(rawContactUri, false); 8907 assertNetworkNotified(false); 8908 } 8909 testContactUpdate_updatesContactUpdatedTimestamp()8910 public void testContactUpdate_updatesContactUpdatedTimestamp() { 8911 sMockClock.install(); 8912 DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver); 8913 8914 long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 8915 8916 ContentValues values = new ContentValues(); 8917 values.put(ContactsContract.Contacts.STARRED, 1); 8918 8919 sMockClock.advance(); 8920 ContactUtil.update(mResolver, ids.mContactId, values); 8921 8922 long newTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 8923 assertTrue(newTime > baseTime); 8924 8925 // Clean up 8926 RawContactUtil.delete(mResolver, ids.mRawContactId, true); 8927 } 8928 8929 // This implicitly tests the Contact create case. testRawContactCreate_updatesContactUpdatedTimestamp()8930 public void testRawContactCreate_updatesContactUpdatedTimestamp() { 8931 long startTime = System.currentTimeMillis(); 8932 8933 long rawContactId = RawContactUtil.createRawContactWithName(mResolver); 8934 long lastUpdated = getContactLastUpdatedTimestampByRawContactId(mResolver, rawContactId); 8935 8936 assertTrue(lastUpdated > startTime); 8937 8938 // Clean up 8939 RawContactUtil.delete(mResolver, rawContactId, true); 8940 } 8941 testRawContactUpdate_updatesContactUpdatedTimestamp()8942 public void testRawContactUpdate_updatesContactUpdatedTimestamp() { 8943 DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver); 8944 8945 long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 8946 8947 ContentValues values = new ContentValues(); 8948 values.put(ContactsContract.RawContacts.STARRED, 1); 8949 RawContactUtil.update(mResolver, ids.mRawContactId, values); 8950 8951 long newTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 8952 assertTrue(newTime > baseTime); 8953 8954 // Clean up 8955 RawContactUtil.delete(mResolver, ids.mRawContactId, true); 8956 } 8957 testRawContactPsuedoDelete_hasDeleteLogForContact()8958 public void testRawContactPsuedoDelete_hasDeleteLogForContact() { 8959 DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver); 8960 8961 long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 8962 8963 RawContactUtil.delete(mResolver, ids.mRawContactId, false); 8964 8965 DatabaseAsserts.assertHasDeleteLogGreaterThan(mResolver, ids.mContactId, baseTime); 8966 8967 // clean up 8968 RawContactUtil.delete(mResolver, ids.mRawContactId, true); 8969 } 8970 testRawContactDelete_hasDeleteLogForContact()8971 public void testRawContactDelete_hasDeleteLogForContact() { 8972 DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver); 8973 8974 long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 8975 8976 RawContactUtil.delete(mResolver, ids.mRawContactId, true); 8977 8978 DatabaseAsserts.assertHasDeleteLogGreaterThan(mResolver, ids.mContactId, baseTime); 8979 8980 // already clean 8981 } 8982 getContactLastUpdatedTimestampByRawContactId(ContentResolver resolver, long rawContactId)8983 private long getContactLastUpdatedTimestampByRawContactId(ContentResolver resolver, 8984 long rawContactId) { 8985 long contactId = RawContactUtil.queryContactIdByRawContactId(mResolver, rawContactId); 8986 MoreAsserts.assertNotEqual(CommonDatabaseUtils.NOT_FOUND, contactId); 8987 8988 return ContactUtil.queryContactLastUpdatedTimestamp(mResolver, contactId); 8989 } 8990 testDataInsert_updatesContactLastUpdatedTimestamp()8991 public void testDataInsert_updatesContactLastUpdatedTimestamp() { 8992 sMockClock.install(); 8993 DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver); 8994 long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 8995 8996 sMockClock.advance(); 8997 insertPhoneNumberAndReturnDataId(ids.mRawContactId); 8998 8999 long newTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 9000 assertTrue(newTime > baseTime); 9001 9002 // Clean up 9003 RawContactUtil.delete(mResolver, ids.mRawContactId, true); 9004 } 9005 testDataDelete_updatesContactLastUpdatedTimestamp()9006 public void testDataDelete_updatesContactLastUpdatedTimestamp() { 9007 sMockClock.install(); 9008 DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver); 9009 9010 long dataId = insertPhoneNumberAndReturnDataId(ids.mRawContactId); 9011 9012 long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 9013 9014 sMockClock.advance(); 9015 DataUtil.delete(mResolver, dataId); 9016 9017 long newTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 9018 assertTrue(newTime > baseTime); 9019 9020 // Clean up 9021 RawContactUtil.delete(mResolver, ids.mRawContactId, true); 9022 } 9023 testDataUpdate_updatesContactLastUpdatedTimestamp()9024 public void testDataUpdate_updatesContactLastUpdatedTimestamp() { 9025 sMockClock.install(); 9026 DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver); 9027 9028 long dataId = insertPhoneNumberAndReturnDataId(ids.mRawContactId); 9029 9030 long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 9031 9032 sMockClock.advance(); 9033 ContentValues values = new ContentValues(); 9034 values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, "555-5555"); 9035 DataUtil.update(mResolver, dataId, values); 9036 9037 long newTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId); 9038 assertTrue(newTime > baseTime); 9039 9040 // Clean up 9041 RawContactUtil.delete(mResolver, ids.mRawContactId, true); 9042 } 9043 insertPhoneNumberAndReturnDataId(long rawContactId)9044 private long insertPhoneNumberAndReturnDataId(long rawContactId) { 9045 Uri uri = insertPhoneNumber(rawContactId, "1-800-GOOG-411"); 9046 return ContentUris.parseId(uri); 9047 } 9048 testDeletedContactsDelete_isUnsupported()9049 public void testDeletedContactsDelete_isUnsupported() { 9050 final Uri URI = ContactsContract.DeletedContacts.CONTENT_URI; 9051 DatabaseAsserts.assertDeleteIsUnsupported(mResolver, URI); 9052 9053 Uri uri = ContentUris.withAppendedId(URI, 1L); 9054 DatabaseAsserts.assertDeleteIsUnsupported(mResolver, uri); 9055 } 9056 testDeletedContactsInsert_isUnsupported()9057 public void testDeletedContactsInsert_isUnsupported() { 9058 final Uri URI = ContactsContract.DeletedContacts.CONTENT_URI; 9059 DatabaseAsserts.assertInsertIsUnsupported(mResolver, URI); 9060 } 9061 9062 testQueryDeletedContactsByContactId()9063 public void testQueryDeletedContactsByContactId() { 9064 DatabaseAsserts.ContactIdPair ids = assertContactCreateDelete(); 9065 9066 MoreAsserts.assertNotEqual(CommonDatabaseUtils.NOT_FOUND, 9067 DeletedContactUtil.queryDeletedTimestampForContactId(mResolver, ids.mContactId)); 9068 } 9069 testQueryDeletedContactsAll()9070 public void testQueryDeletedContactsAll() { 9071 final int numDeletes = 10; 9072 9073 // Since we cannot clean out delete log from previous tests, we need to account for that 9074 // by querying for the count first. 9075 final long startCount = DeletedContactUtil.getCount(mResolver); 9076 9077 for (int i = 0; i < numDeletes; i++) { 9078 assertContactCreateDelete(); 9079 } 9080 9081 final long endCount = DeletedContactUtil.getCount(mResolver); 9082 9083 assertEquals(numDeletes, endCount - startCount); 9084 } 9085 testQueryDeletedContactsSinceTimestamp()9086 public void testQueryDeletedContactsSinceTimestamp() { 9087 sMockClock.install(); 9088 9089 // Before 9090 final HashSet<Long> beforeIds = new HashSet<Long>(); 9091 beforeIds.add(assertContactCreateDelete().mContactId); 9092 beforeIds.add(assertContactCreateDelete().mContactId); 9093 9094 final long start = sMockClock.currentTimeMillis(); 9095 9096 // After 9097 final HashSet<Long> afterIds = new HashSet<Long>(); 9098 afterIds.add(assertContactCreateDelete().mContactId); 9099 afterIds.add(assertContactCreateDelete().mContactId); 9100 afterIds.add(assertContactCreateDelete().mContactId); 9101 9102 final String[] projection = new String[]{ 9103 ContactsContract.DeletedContacts.CONTACT_ID, 9104 ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP 9105 }; 9106 final List<String[]> records = DeletedContactUtil.querySinceTimestamp(mResolver, projection, 9107 start); 9108 for (String[] record : records) { 9109 // Check ids to make sure we only have the ones that came after the time. 9110 final long contactId = Long.parseLong(record[0]); 9111 assertFalse(beforeIds.contains(contactId)); 9112 assertTrue(afterIds.contains(contactId)); 9113 9114 // Check times to make sure they came after 9115 assertTrue(Long.parseLong(record[1]) > start); 9116 } 9117 } 9118 9119 /** 9120 * Creates a contact in the local account. Assert it's not present in the delete log. 9121 * Delete it. And assert that the contact record is no longer present. 9122 * 9123 * @return The contact id and raw contact id that was created. 9124 */ assertContactCreateDelete()9125 private DatabaseAsserts.ContactIdPair assertContactCreateDelete() { 9126 return assertContactCreateDelete(null); 9127 } 9128 9129 /** 9130 * Creates a contact in the given account. Assert it's not present in the delete log. 9131 * Delete it. And assert that the contact record is no longer present. 9132 * @return The contact id and raw contact id that was created. 9133 */ assertContactCreateDelete(Account account)9134 private DatabaseAsserts.ContactIdPair assertContactCreateDelete(Account account) { 9135 DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver, 9136 account); 9137 9138 assertEquals(CommonDatabaseUtils.NOT_FOUND, 9139 DeletedContactUtil.queryDeletedTimestampForContactId(mResolver, ids.mContactId)); 9140 9141 sMockClock.advance(); 9142 ContactUtil.delete(mResolver, ids.mContactId); 9143 9144 assertFalse(ContactUtil.recordExistsForContactId(mResolver, ids.mContactId)); 9145 9146 return ids; 9147 } 9148 9149 /** 9150 * End delta api tests. 9151 ******************************************************/ 9152 9153 /******************************************************* 9154 * Pinning support tests 9155 */ testPinnedPositionsUpdate()9156 public void testPinnedPositionsUpdate() { 9157 final DatabaseAsserts.ContactIdPair i1 = DatabaseAsserts.assertAndCreateContact(mResolver); 9158 final DatabaseAsserts.ContactIdPair i2 = DatabaseAsserts.assertAndCreateContact(mResolver); 9159 final DatabaseAsserts.ContactIdPair i3 = DatabaseAsserts.assertAndCreateContact(mResolver); 9160 final DatabaseAsserts.ContactIdPair i4 = DatabaseAsserts.assertAndCreateContact(mResolver); 9161 9162 final int unpinned = PinnedPositions.UNPINNED; 9163 9164 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9165 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, unpinned, Contacts.STARRED, 0), 9166 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, unpinned, Contacts.STARRED, 0), 9167 cv(Contacts._ID, i3.mContactId, Contacts.PINNED, unpinned, Contacts.STARRED, 0), 9168 cv(Contacts._ID, i4.mContactId, Contacts.PINNED, unpinned, Contacts.STARRED, 0) 9169 ); 9170 9171 assertStoredValuesWithProjection(RawContacts.CONTENT_URI, 9172 cv(RawContacts._ID, i1.mRawContactId, RawContacts.PINNED, unpinned), 9173 cv(RawContacts._ID, i2.mRawContactId, RawContacts.PINNED, unpinned), 9174 cv(RawContacts._ID, i3.mRawContactId, RawContacts.PINNED, unpinned), 9175 cv(RawContacts._ID, i4.mRawContactId, RawContacts.PINNED, unpinned) 9176 ); 9177 9178 final ArrayList<ContentProviderOperation> operations = 9179 new ArrayList<ContentProviderOperation>(); 9180 9181 operations.add(newPinningOperation(i1.mContactId, 1, true)); 9182 operations.add(newPinningOperation(i3.mContactId, 3, true)); 9183 operations.add(newPinningOperation(i4.mContactId, 2, false)); 9184 9185 CommonDatabaseUtils.applyBatch(mResolver, operations); 9186 9187 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9188 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, 1, Contacts.STARRED, 1), 9189 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, unpinned, Contacts.STARRED, 0), 9190 cv(Contacts._ID, i3.mContactId, Contacts.PINNED, 3, Contacts.STARRED, 1), 9191 cv(Contacts._ID, i4.mContactId, Contacts.PINNED, 2, Contacts.STARRED, 0) 9192 ); 9193 9194 // Make sure the values are propagated to raw contacts 9195 9196 assertStoredValuesWithProjection(RawContacts.CONTENT_URI, 9197 cv(RawContacts._ID, i1.mRawContactId, RawContacts.PINNED, 1), 9198 cv(RawContacts._ID, i2.mRawContactId, RawContacts.PINNED, unpinned), 9199 cv(RawContacts._ID, i3.mRawContactId, RawContacts.PINNED, 3), 9200 cv(RawContacts._ID, i4.mRawContactId, RawContacts.PINNED, 2) 9201 ); 9202 9203 operations.clear(); 9204 9205 // Now unpin the contact 9206 operations.add(newPinningOperation(i3.mContactId, unpinned, false)); 9207 9208 CommonDatabaseUtils.applyBatch(mResolver, operations); 9209 9210 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9211 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, 1, Contacts.STARRED, 1), 9212 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, unpinned, Contacts.STARRED, 0), 9213 cv(Contacts._ID, i3.mContactId, Contacts.PINNED, unpinned, Contacts.STARRED, 0), 9214 cv(Contacts._ID, i4.mContactId, Contacts.PINNED, 2, Contacts.STARRED, 0) 9215 ); 9216 9217 assertStoredValuesWithProjection(RawContacts.CONTENT_URI, 9218 cv(Contacts._ID, i1.mRawContactId, RawContacts.PINNED, 1, RawContacts.STARRED, 1), 9219 cv(Contacts._ID, i2.mRawContactId, RawContacts.PINNED, unpinned, 9220 RawContacts.STARRED, 0), 9221 cv(Contacts._ID, i3.mRawContactId, RawContacts.PINNED, unpinned, 9222 RawContacts.STARRED, 0), 9223 cv(Contacts._ID, i4.mRawContactId, RawContacts.PINNED, 2, RawContacts.STARRED, 0) 9224 ); 9225 } 9226 testPinnedPositionsAfterJoinAndSplit()9227 public void testPinnedPositionsAfterJoinAndSplit() { 9228 final DatabaseAsserts.ContactIdPair i1 = DatabaseAsserts.assertAndCreateContactWithName( 9229 mResolver, "A", "Smith"); 9230 final DatabaseAsserts.ContactIdPair i2 = DatabaseAsserts.assertAndCreateContactWithName( 9231 mResolver, "B", "Smith"); 9232 final DatabaseAsserts.ContactIdPair i3 = DatabaseAsserts.assertAndCreateContactWithName( 9233 mResolver, "C", "Smith"); 9234 final DatabaseAsserts.ContactIdPair i4 = DatabaseAsserts.assertAndCreateContactWithName( 9235 mResolver, "D", "Smith"); 9236 final DatabaseAsserts.ContactIdPair i5 = DatabaseAsserts.assertAndCreateContactWithName( 9237 mResolver, "E", "Smith"); 9238 final DatabaseAsserts.ContactIdPair i6 = DatabaseAsserts.assertAndCreateContactWithName( 9239 mResolver, "F", "Smith"); 9240 9241 final ArrayList<ContentProviderOperation> operations = 9242 new ArrayList<ContentProviderOperation>(); 9243 9244 operations.add(newPinningOperation(i1.mContactId, 1, true)); 9245 operations.add(newPinningOperation(i2.mContactId, 2, true)); 9246 operations.add(newPinningOperation(i3.mContactId, 3, true)); 9247 operations.add(newPinningOperation(i5.mContactId, 5, true)); 9248 operations.add(newPinningOperation(i6.mContactId, 6, true)); 9249 9250 CommonDatabaseUtils.applyBatch(mResolver, operations); 9251 9252 // aggregate raw contact 1 and 4 together. 9253 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, i1.mRawContactId, 9254 i4.mRawContactId); 9255 9256 // If only one contact is pinned, the resulting contact should inherit the pinned position 9257 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9258 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, 1), 9259 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, 2), 9260 cv(Contacts._ID, i3.mContactId, Contacts.PINNED, 3), 9261 cv(Contacts._ID, i5.mContactId, Contacts.PINNED, 5), 9262 cv(Contacts._ID, i6.mContactId, Contacts.PINNED, 6) 9263 ); 9264 9265 assertStoredValuesWithProjection(RawContacts.CONTENT_URI, 9266 cv(RawContacts._ID, i1.mRawContactId, RawContacts.PINNED, 1, 9267 RawContacts.STARRED, 1), 9268 cv(RawContacts._ID, i2.mRawContactId, RawContacts.PINNED, 2, 9269 RawContacts.STARRED, 1), 9270 cv(RawContacts._ID, i3.mRawContactId, RawContacts.PINNED, 3, 9271 RawContacts.STARRED, 1), 9272 cv(RawContacts._ID, i4.mRawContactId, RawContacts.PINNED, PinnedPositions.UNPINNED, 9273 RawContacts.STARRED, 0), 9274 cv(RawContacts._ID, i5.mRawContactId, RawContacts.PINNED, 5, 9275 RawContacts.STARRED, 1), 9276 cv(RawContacts._ID, i6.mRawContactId, RawContacts.PINNED, 6, 9277 RawContacts.STARRED, 1) 9278 ); 9279 9280 // aggregate raw contact 2 and 3 together. 9281 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, i2.mRawContactId, 9282 i3.mRawContactId); 9283 9284 // If both raw contacts are pinned, the resulting contact should inherit the lower 9285 // pinned position 9286 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9287 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, 1), 9288 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, 2), 9289 cv(Contacts._ID, i5.mContactId, Contacts.PINNED, 5), 9290 cv(Contacts._ID, i6.mContactId, Contacts.PINNED, 6) 9291 ); 9292 9293 assertStoredValuesWithProjection(RawContacts.CONTENT_URI, 9294 cv(RawContacts._ID, i1.mRawContactId, RawContacts.PINNED, 1), 9295 cv(RawContacts._ID, i2.mRawContactId, RawContacts.PINNED, 2), 9296 cv(RawContacts._ID, i3.mRawContactId, RawContacts.PINNED, 3), 9297 cv(RawContacts._ID, i4.mRawContactId, RawContacts.PINNED, 9298 PinnedPositions.UNPINNED), 9299 cv(RawContacts._ID, i5.mRawContactId, RawContacts.PINNED, 5), 9300 cv(RawContacts._ID, i6.mRawContactId, RawContacts.PINNED, 6) 9301 ); 9302 9303 // split the aggregated raw contacts 9304 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, i1.mRawContactId, 9305 i4.mRawContactId); 9306 9307 // raw contacts should be unpinned after being split, but still starred 9308 assertStoredValuesWithProjection(RawContacts.CONTENT_URI, 9309 cv(RawContacts._ID, i1.mRawContactId, RawContacts.PINNED, 1, 9310 RawContacts.STARRED, 1), 9311 cv(RawContacts._ID, i2.mRawContactId, RawContacts.PINNED, 2, 9312 RawContacts.STARRED, 1), 9313 cv(RawContacts._ID, i3.mRawContactId, RawContacts.PINNED, 3, 9314 RawContacts.STARRED, 1), 9315 cv(RawContacts._ID, i4.mRawContactId, RawContacts.PINNED, PinnedPositions.UNPINNED, 9316 RawContacts.STARRED, 0), 9317 cv(RawContacts._ID, i5.mRawContactId, RawContacts.PINNED, 5, 9318 RawContacts.STARRED, 1), 9319 cv(RawContacts._ID, i6.mRawContactId, RawContacts.PINNED, 6, 9320 RawContacts.STARRED, 1) 9321 ); 9322 9323 // now demote contact 5 9324 operations.clear(); 9325 operations.add(newPinningOperation(i5.mContactId, PinnedPositions.DEMOTED, false)); 9326 CommonDatabaseUtils.applyBatch(mResolver, operations); 9327 9328 // Get new contact Ids for contacts composing of raw contacts 1 and 4 because they have 9329 // changed. 9330 final long cId1 = RawContactUtil.queryContactIdByRawContactId(mResolver, i1.mRawContactId); 9331 final long cId4 = RawContactUtil.queryContactIdByRawContactId(mResolver, i4.mRawContactId); 9332 9333 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9334 cv(Contacts._ID, cId1, Contacts.PINNED, 1), 9335 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, 2), 9336 cv(Contacts._ID, cId4, Contacts.PINNED, PinnedPositions.UNPINNED), 9337 cv(Contacts._ID, i5.mContactId, Contacts.PINNED, PinnedPositions.DEMOTED), 9338 cv(Contacts._ID, i6.mContactId, Contacts.PINNED, 6) 9339 ); 9340 9341 // aggregate contacts 5 and 6 together 9342 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, i5.mRawContactId, 9343 i6.mRawContactId); 9344 9345 // The resulting contact should have a pinned value of 6 9346 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9347 cv(Contacts._ID, cId1, Contacts.PINNED, 1), 9348 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, 2), 9349 cv(Contacts._ID, cId4, Contacts.PINNED, PinnedPositions.UNPINNED), 9350 cv(Contacts._ID, i5.mContactId, Contacts.PINNED, 6) 9351 ); 9352 } 9353 testDefaultAccountSet_throwException()9354 public void testDefaultAccountSet_throwException() { 9355 mActor.setAccounts(new Account[]{mAccount}); 9356 try { 9357 mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD, 9358 null, null); 9359 fail(); 9360 } catch (SecurityException expected) { 9361 } 9362 9363 mActor.addPermissions("android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS"); 9364 try { 9365 Bundle bundle = new Bundle(); 9366 bundle.putString(Settings.ACCOUNT_NAME, "account1"); // no account type specified 9367 mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD, 9368 null, bundle); 9369 fail(); 9370 } catch (IllegalArgumentException expected) { 9371 } 9372 9373 try { 9374 Bundle bundle = new Bundle(); 9375 bundle.putString(Settings.ACCOUNT_NAME, "account1"); 9376 bundle.putString(Settings.ACCOUNT_TYPE, "account type1"); 9377 bundle.putString(Settings.DATA_SET, "c"); // data set should not be set. 9378 mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD, 9379 null, bundle); 9380 fail(); 9381 } catch (IllegalArgumentException expected) { 9382 } 9383 9384 try { 9385 Bundle bundle = new Bundle(); 9386 bundle.putString(Settings.ACCOUNT_NAME, "account2"); // invalid account 9387 bundle.putString(Settings.ACCOUNT_TYPE, "account type2"); 9388 mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD, 9389 null, bundle); 9390 fail(); 9391 } catch (IllegalArgumentException expected) { 9392 } 9393 } 9394 testDefaultAccountSetAndQuery()9395 public void testDefaultAccountSetAndQuery() { 9396 Bundle response = mResolver.call(ContactsContract.AUTHORITY_URI, 9397 Settings.QUERY_DEFAULT_ACCOUNT_METHOD, null, null); 9398 Account account = response.getParcelable(Settings.KEY_DEFAULT_ACCOUNT); 9399 assertNull(account); 9400 9401 mActor.addPermissions("android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS"); 9402 mActor.setAccounts(new Account[]{mAccount}); 9403 // Set ("account1", "account type1") account as the default account. 9404 Bundle bundle = new Bundle(); 9405 bundle.putString(Settings.ACCOUNT_NAME, "account1"); 9406 bundle.putString(Settings.ACCOUNT_TYPE, "account type1"); 9407 mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD, 9408 null, bundle); 9409 9410 response = mResolver.call(ContactsContract.AUTHORITY_URI, 9411 Settings.QUERY_DEFAULT_ACCOUNT_METHOD, null, null); 9412 account = response.getParcelable(Settings.KEY_DEFAULT_ACCOUNT); 9413 assertEquals("account1", account.name); 9414 assertEquals("account type1", account.type); 9415 9416 // Set NULL account as default account. 9417 bundle = new Bundle(); 9418 mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD, 9419 null, bundle); 9420 9421 response = mResolver.call(ContactsContract.AUTHORITY_URI, 9422 Settings.QUERY_DEFAULT_ACCOUNT_METHOD, null, null); 9423 account = response.getParcelable(Settings.KEY_DEFAULT_ACCOUNT); 9424 assertNull(account); 9425 } 9426 testPinnedPositionsDemoteIllegalArguments()9427 public void testPinnedPositionsDemoteIllegalArguments() { 9428 try { 9429 mResolver.call(ContactsContract.AUTHORITY_URI, PinnedPositions.UNDEMOTE_METHOD, 9430 null, null); 9431 fail(); 9432 } catch (IllegalArgumentException expected) { 9433 } 9434 9435 try { 9436 mResolver.call(ContactsContract.AUTHORITY_URI, PinnedPositions.UNDEMOTE_METHOD, 9437 "1.1", null); 9438 fail(); 9439 } catch (IllegalArgumentException expected) { 9440 } 9441 9442 try { 9443 mResolver.call(ContactsContract.AUTHORITY_URI, PinnedPositions.UNDEMOTE_METHOD, 9444 "NotANumber", null); 9445 fail(); 9446 } catch (IllegalArgumentException expected) { 9447 } 9448 9449 // Valid contact ID that does not correspond to an actual contact is silently ignored 9450 mResolver.call(ContactsContract.AUTHORITY_URI, PinnedPositions.UNDEMOTE_METHOD, "999", 9451 null); 9452 } 9453 testPinnedPositionsAfterDemoteAndUndemote()9454 public void testPinnedPositionsAfterDemoteAndUndemote() { 9455 final DatabaseAsserts.ContactIdPair i1 = DatabaseAsserts.assertAndCreateContact(mResolver); 9456 final DatabaseAsserts.ContactIdPair i2 = DatabaseAsserts.assertAndCreateContact(mResolver); 9457 9458 // Pin contact 1 and demote contact 2 9459 final ArrayList<ContentProviderOperation> operations = 9460 new ArrayList<ContentProviderOperation>(); 9461 operations.add(newPinningOperation(i1.mContactId, 1, true)); 9462 operations.add(newPinningOperation(i2.mContactId, PinnedPositions.DEMOTED, false)); 9463 CommonDatabaseUtils.applyBatch(mResolver, operations); 9464 9465 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9466 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, 1, Contacts.STARRED, 1), 9467 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, PinnedPositions.DEMOTED, 9468 Contacts.STARRED, 0) 9469 ); 9470 9471 assertStoredValuesWithProjection(RawContacts.CONTENT_URI, 9472 cv(RawContacts._ID, i1.mRawContactId, RawContacts.PINNED, 1, 9473 RawContacts.STARRED, 1), 9474 cv(RawContacts._ID, i2.mRawContactId, RawContacts.PINNED, PinnedPositions.DEMOTED, 9475 RawContacts.STARRED, 0) 9476 ); 9477 9478 // Now undemote both contacts 9479 mResolver.call(ContactsContract.AUTHORITY_URI, PinnedPositions.UNDEMOTE_METHOD, 9480 String.valueOf(i1.mContactId), null); 9481 mResolver.call(ContactsContract.AUTHORITY_URI, PinnedPositions.UNDEMOTE_METHOD, 9482 String.valueOf(i2.mContactId), null); 9483 9484 9485 // Contact 1 remains pinned at 0, while contact 2 becomes unpinned 9486 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9487 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, 1, Contacts.STARRED, 1), 9488 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, PinnedPositions.UNPINNED, 9489 Contacts.STARRED, 0) 9490 ); 9491 9492 assertStoredValuesWithProjection(RawContacts.CONTENT_URI, 9493 cv(RawContacts._ID, i1.mRawContactId, RawContacts.PINNED, 1, 9494 RawContacts.STARRED, 1), 9495 cv(RawContacts._ID, i2.mRawContactId, RawContacts.PINNED, PinnedPositions.UNPINNED, 9496 RawContacts.STARRED, 0) 9497 ); 9498 } 9499 9500 /** 9501 * Verifies that any existing pinned contacts have their pinned positions incremented by one 9502 * after the upgrade step 9503 */ testPinnedPositionsUpgradeTo906_PinnedContactsIncrementedByOne()9504 public void testPinnedPositionsUpgradeTo906_PinnedContactsIncrementedByOne() { 9505 final DatabaseAsserts.ContactIdPair i1 = DatabaseAsserts.assertAndCreateContact(mResolver); 9506 final DatabaseAsserts.ContactIdPair i2 = DatabaseAsserts.assertAndCreateContact(mResolver); 9507 final DatabaseAsserts.ContactIdPair i3 = DatabaseAsserts.assertAndCreateContact(mResolver); 9508 final ArrayList<ContentProviderOperation> operations = 9509 new ArrayList<ContentProviderOperation>(); 9510 operations.add(newPinningOperation(i1.mContactId, 0, true)); 9511 operations.add(newPinningOperation(i2.mContactId, 5, true)); 9512 operations.add(newPinningOperation(i3.mContactId, Integer.MAX_VALUE - 2, true)); 9513 CommonDatabaseUtils.applyBatch(mResolver, operations); 9514 9515 final ContactsDatabaseHelper helper = 9516 ((ContactsDatabaseHelper) ((ContactsProvider2) getProvider()).getDatabaseHelper()); 9517 SQLiteDatabase db = helper.getWritableDatabase(); 9518 helper.upgradeToVersion906(db); 9519 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9520 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, 1), 9521 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, 6), 9522 cv(Contacts._ID, i3.mContactId, Contacts.PINNED, Integer.MAX_VALUE - 1) 9523 ); 9524 } 9525 9526 /** 9527 * Verifies that any unpinned contacts (or those with pinned position Integer.MAX_VALUE - 1) 9528 * have their pinned positions correctly set to 0 after the upgrade step. 9529 */ testPinnedPositionsUpgradeTo906_UnpinnedValueCorrectlyUpdated()9530 public void testPinnedPositionsUpgradeTo906_UnpinnedValueCorrectlyUpdated() { 9531 final DatabaseAsserts.ContactIdPair i1 = DatabaseAsserts.assertAndCreateContact(mResolver); 9532 final DatabaseAsserts.ContactIdPair i2 = DatabaseAsserts.assertAndCreateContact(mResolver); 9533 final ArrayList<ContentProviderOperation> operations = 9534 new ArrayList<ContentProviderOperation>(); 9535 operations.add(newPinningOperation(i1.mContactId, Integer.MAX_VALUE -1 , true)); 9536 operations.add(newPinningOperation(i2.mContactId, Integer.MAX_VALUE, true)); 9537 CommonDatabaseUtils.applyBatch(mResolver, operations); 9538 9539 final ContactsDatabaseHelper helper = 9540 ((ContactsDatabaseHelper) ((ContactsProvider2) getProvider()).getDatabaseHelper()); 9541 SQLiteDatabase db = helper.getWritableDatabase(); 9542 helper.upgradeToVersion906(db); 9543 9544 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9545 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, 0), 9546 cv(Contacts._ID, i2.mContactId, Contacts.PINNED, 0) 9547 ); 9548 } 9549 9550 /** 9551 * Tests the functionality of the 9552 * {@link ContactsContract.PinnedPositions#pin(ContentResolver, long, int)} API. 9553 */ testPinnedPositions_ContactsContractPinnedPositionsPin()9554 public void testPinnedPositions_ContactsContractPinnedPositionsPin() { 9555 final DatabaseAsserts.ContactIdPair i1 = DatabaseAsserts.assertAndCreateContact(mResolver); 9556 9557 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9558 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, PinnedPositions.UNPINNED) 9559 ); 9560 9561 ContactsContract.PinnedPositions.pin(mResolver, i1.mContactId, 5); 9562 9563 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9564 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, 5) 9565 ); 9566 9567 ContactsContract.PinnedPositions.pin(mResolver, i1.mContactId, PinnedPositions.UNPINNED); 9568 9569 assertStoredValuesWithProjection(Contacts.CONTENT_URI, 9570 cv(Contacts._ID, i1.mContactId, Contacts.PINNED, PinnedPositions.UNPINNED) 9571 ); 9572 } 9573 newPinningOperation(long id, int pinned, boolean star)9574 private ContentProviderOperation newPinningOperation(long id, int pinned, boolean star) { 9575 final Uri uri = Uri.withAppendedPath(Contacts.CONTENT_URI, String.valueOf(id)); 9576 final ContentValues values = new ContentValues(); 9577 values.put(Contacts.PINNED, pinned); 9578 values.put(Contacts.STARRED, star ? 1 : 0); 9579 return ContentProviderOperation.newUpdate(uri).withValues(values).build(); 9580 } 9581 9582 /** 9583 * End pinning support tests 9584 ******************************************************/ 9585 testAuthorization_authorize()9586 public void testAuthorization_authorize() throws Exception { 9587 // Setup 9588 ContentValues values = new ContentValues(); 9589 long id1 = createContact(values, "Noah", "Tever", "18004664411", 9590 "email@email.com", StatusUpdates.OFFLINE, 0, 0, 0, 0); 9591 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id1); 9592 9593 // Execute: pre authorize the contact 9594 Uri authorizedUri = getPreAuthorizedUri(contactUri); 9595 9596 // Sanity check: URIs are different 9597 assertNotSame(authorizedUri, contactUri); 9598 9599 // Verify: the URI is pre authorized 9600 final ContactsProvider2 cp = (ContactsProvider2) getProvider(); 9601 assertTrue(cp.isValidPreAuthorizedUri(authorizedUri)); 9602 } 9603 testAuthorization_unauthorized()9604 public void testAuthorization_unauthorized() throws Exception { 9605 // Setup 9606 ContentValues values = new ContentValues(); 9607 long id1 = createContact(values, "Noah", "Tever", "18004664411", 9608 "email@email.com", StatusUpdates.OFFLINE, 0, 0, 0, 0); 9609 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id1); 9610 9611 // Verify: the URI is *not* pre authorized 9612 final ContactsProvider2 cp = (ContactsProvider2) getProvider(); 9613 assertFalse(cp.isValidPreAuthorizedUri(contactUri)); 9614 } 9615 testAuthorization_invalidAuthorization()9616 public void testAuthorization_invalidAuthorization() throws Exception { 9617 // Setup 9618 ContentValues values = new ContentValues(); 9619 long id1 = createContact(values, "Noah", "Tever", "18004664411", 9620 "email@email.com", StatusUpdates.OFFLINE, 0, 0, 0, 0); 9621 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id1); 9622 9623 // Execute: pre authorize the contact and then modify the resulting URI slightly 9624 Uri authorizedUri = getPreAuthorizedUri(contactUri); 9625 Uri almostAuthorizedUri = Uri.parse(authorizedUri.toString() + "2"); 9626 9627 // Verify: the URI is not pre authorized 9628 final ContactsProvider2 cp = (ContactsProvider2) getProvider(); 9629 assertFalse(cp.isValidPreAuthorizedUri(almostAuthorizedUri)); 9630 } 9631 testAuthorization_expired()9632 public void testAuthorization_expired() throws Exception { 9633 // Setup 9634 ContentValues values = new ContentValues(); 9635 long id1 = createContact(values, "Noah", "Tever", "18004664411", 9636 "email@email.com", StatusUpdates.OFFLINE, 0, 0, 0, 0); 9637 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id1); 9638 sMockClock.install(); 9639 9640 // Execute: pre authorize the contact 9641 Uri authorizedUri = getPreAuthorizedUri(contactUri); 9642 sMockClock.setCurrentTimeMillis(sMockClock.currentTimeMillis() + 1000000); 9643 9644 // Verify: the authorization for the URI expired 9645 final ContactsProvider2 cp = (ContactsProvider2) getProvider(); 9646 assertFalse(cp.isValidPreAuthorizedUri(authorizedUri)); 9647 } 9648 testAuthorization_contactUpgrade()9649 public void testAuthorization_contactUpgrade() throws Exception { 9650 ContactsDatabaseHelper helper = 9651 ((ContactsDatabaseHelper) ((ContactsProvider2) getProvider()).getDatabaseHelper()); 9652 SQLiteDatabase db = helper.getWritableDatabase(); 9653 9654 // Perform the unit tests against an upgraded version of the database, instead of a freshly 9655 // created version of the database. 9656 helper.upgradeToVersion1002(db); 9657 testAuthorization_authorize(); 9658 helper.upgradeToVersion1002(db); 9659 testAuthorization_expired(); 9660 helper.upgradeToVersion1002(db); 9661 testAuthorization_expired(); 9662 helper.upgradeToVersion1002(db); 9663 testAuthorization_invalidAuthorization(); 9664 } 9665 getPreAuthorizedUri(Uri uri)9666 private Uri getPreAuthorizedUri(Uri uri) { 9667 final Bundle uriBundle = new Bundle(); 9668 uriBundle.putParcelable(ContactsContract.Authorization.KEY_URI_TO_AUTHORIZE, uri); 9669 final Bundle authResponse = mResolver.call( 9670 ContactsContract.AUTHORITY_URI, 9671 ContactsContract.Authorization.AUTHORIZATION_METHOD, 9672 null, 9673 uriBundle); 9674 return (Uri) authResponse.getParcelable( 9675 ContactsContract.Authorization.KEY_AUTHORIZED_URI); 9676 } 9677 9678 /** 9679 * End Authorization Tests 9680 ******************************************************/ 9681 queryGroupMemberships(Account account)9682 private Cursor queryGroupMemberships(Account account) { 9683 Cursor c = mResolver.query(TestUtil.maybeAddAccountQueryParameters(Data.CONTENT_URI, 9684 account), 9685 new String[] {GroupMembership.GROUP_ROW_ID, GroupMembership.RAW_CONTACT_ID}, 9686 Data.MIMETYPE + "=?", new String[] {GroupMembership.CONTENT_ITEM_TYPE}, 9687 GroupMembership.GROUP_SOURCE_ID); 9688 return c; 9689 } 9690 readToEnd(FileInputStream inputStream)9691 private String readToEnd(FileInputStream inputStream) { 9692 try { 9693 System.out.println("DECLARED INPUT STREAM LENGTH: " + inputStream.available()); 9694 int ch; 9695 StringBuilder stringBuilder = new StringBuilder(); 9696 int index = 0; 9697 while (true) { 9698 ch = inputStream.read(); 9699 System.out.println("READ CHARACTER: " + index + " " + ch); 9700 if (ch == -1) { 9701 break; 9702 } 9703 stringBuilder.append((char)ch); 9704 index++; 9705 } 9706 return stringBuilder.toString(); 9707 } catch (IOException e) { 9708 return null; 9709 } 9710 } 9711 assertQueryParameter(String uriString, String parameter, String expectedValue)9712 private void assertQueryParameter(String uriString, String parameter, String expectedValue) { 9713 assertEquals(expectedValue, ContactsProvider2.getQueryParameter( 9714 Uri.parse(uriString), parameter)); 9715 } 9716 createContact(ContentValues values, String firstName, String givenName, String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, long groupId, int chatMode)9717 private long createContact(ContentValues values, String firstName, String givenName, 9718 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 9719 long groupId, int chatMode) { 9720 return createContact(values, firstName, givenName, phoneNumber, email, presenceStatus, 9721 timesContacted, starred, groupId, chatMode, false); 9722 } 9723 createContact(ContentValues values, String firstName, String givenName, String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, long groupId, int chatMode, boolean isUserProfile)9724 private long createContact(ContentValues values, String firstName, String givenName, 9725 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 9726 long groupId, int chatMode, boolean isUserProfile) { 9727 return queryContactId(createRawContact(values, firstName, givenName, phoneNumber, email, 9728 presenceStatus, timesContacted, starred, groupId, chatMode, isUserProfile)); 9729 } 9730 createRawContact(ContentValues values, String firstName, String givenName, String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, long groupId, int chatMode)9731 private long createRawContact(ContentValues values, String firstName, String givenName, 9732 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 9733 long groupId, int chatMode) { 9734 long rawContactId = createRawContact(values, phoneNumber, email, presenceStatus, 9735 timesContacted, starred, groupId, chatMode); 9736 DataUtil.insertStructuredName(mResolver, rawContactId, firstName, givenName); 9737 return rawContactId; 9738 } 9739 createRawContact(ContentValues values, String firstName, String givenName, String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, long groupId, int chatMode, boolean isUserProfile)9740 private long createRawContact(ContentValues values, String firstName, String givenName, 9741 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 9742 long groupId, int chatMode, boolean isUserProfile) { 9743 long rawContactId = createRawContact(values, phoneNumber, email, presenceStatus, 9744 timesContacted, starred, groupId, chatMode, isUserProfile); 9745 DataUtil.insertStructuredName(mResolver, rawContactId, firstName, givenName); 9746 return rawContactId; 9747 } 9748 createRawContact(ContentValues values, String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, long groupId, int chatMode)9749 private long createRawContact(ContentValues values, String phoneNumber, String email, 9750 int presenceStatus, int timesContacted, int starred, long groupId, int chatMode) { 9751 return createRawContact(values, phoneNumber, email, presenceStatus, timesContacted, starred, 9752 groupId, chatMode, false); 9753 } 9754 createRawContact(ContentValues values, String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, long groupId, int chatMode, boolean isUserProfile)9755 private long createRawContact(ContentValues values, String phoneNumber, String email, 9756 int presenceStatus, int timesContacted, int starred, long groupId, int chatMode, 9757 boolean isUserProfile) { 9758 values.put(RawContacts.STARRED, starred); 9759 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 9760 values.put(RawContacts.CUSTOM_RINGTONE, "beethoven5"); 9761 values.put(RawContacts.TIMES_CONTACTED, timesContacted); 9762 9763 Uri rawContactUri; 9764 if (isUserProfile) { 9765 rawContactUri = insertProfileRawContact(values); 9766 } else { 9767 rawContactUri = insertRawContact(values); 9768 } 9769 9770 long rawContactId = ContentUris.parseId(rawContactUri); 9771 Uri photoUri = insertPhoto(rawContactId); 9772 long photoId = ContentUris.parseId(photoUri); 9773 values.put(Contacts.PHOTO_ID, photoId); 9774 if (!TextUtils.isEmpty(phoneNumber)) { 9775 insertPhoneNumber(rawContactId, phoneNumber); 9776 } 9777 if (!TextUtils.isEmpty(email)) { 9778 insertEmail(rawContactId, email); 9779 } 9780 9781 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, email, presenceStatus, "hacking", 9782 chatMode, isUserProfile); 9783 9784 if (groupId != 0) { 9785 insertGroupMembership(rawContactId, groupId); 9786 } 9787 9788 return rawContactId; 9789 } 9790 9791 /** 9792 * Creates a raw contact with pre-set values under the user's profile. 9793 * @param profileValues Values to be used to create the entry (common values will be 9794 * automatically populated in createRawContact()). 9795 * @return the raw contact ID that was created. 9796 */ createBasicProfileContact(ContentValues profileValues)9797 private long createBasicProfileContact(ContentValues profileValues) { 9798 long profileRawContactId = createRawContact(profileValues, "Mia", "Prophyl", 9799 "18005554411", "mia.prophyl@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 9800 StatusUpdates.CAPABILITY_HAS_CAMERA, true); 9801 profileValues.put(Contacts.DISPLAY_NAME, "Mia Prophyl"); 9802 return profileRawContactId; 9803 } 9804 9805 /** 9806 * Creates a raw contact with pre-set values that is not under the user's profile. 9807 * @param nonProfileValues Values to be used to create the entry (common values will be 9808 * automatically populated in createRawContact()). 9809 * @return the raw contact ID that was created. 9810 */ createBasicNonProfileContact(ContentValues nonProfileValues)9811 private long createBasicNonProfileContact(ContentValues nonProfileValues) { 9812 long nonProfileRawContactId = createRawContact(nonProfileValues, "John", "Doe", 9813 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 9814 StatusUpdates.CAPABILITY_HAS_CAMERA, false); 9815 nonProfileValues.put(Contacts.DISPLAY_NAME, "John Doe"); 9816 return nonProfileRawContactId; 9817 } 9818 putDataValues(ContentValues values, long rawContactId)9819 private void putDataValues(ContentValues values, long rawContactId) { 9820 values.put(Data.RAW_CONTACT_ID, rawContactId); 9821 values.put(Data.MIMETYPE, "testmimetype"); 9822 values.put(Data.RES_PACKAGE, "oldpackage"); 9823 values.put(Data.IS_PRIMARY, 1); 9824 values.put(Data.IS_SUPER_PRIMARY, 1); 9825 values.put(Data.DATA1, "one"); 9826 values.put(Data.DATA2, "two"); 9827 values.put(Data.DATA3, "three"); 9828 values.put(Data.DATA4, "four"); 9829 values.put(Data.DATA5, "five"); 9830 values.put(Data.DATA6, "six"); 9831 values.put(Data.DATA7, "seven"); 9832 values.put(Data.DATA8, "eight"); 9833 values.put(Data.DATA9, "nine"); 9834 values.put(Data.DATA10, "ten"); 9835 values.put(Data.DATA11, "eleven"); 9836 values.put(Data.DATA12, "twelve"); 9837 values.put(Data.DATA13, "thirteen"); 9838 values.put(Data.DATA14, "fourteen"); 9839 values.put(Data.DATA15, "fifteen".getBytes()); 9840 values.put(Data.CARRIER_PRESENCE, Data.CARRIER_PRESENCE_VT_CAPABLE); 9841 values.put(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME, "preferredcomponentname"); 9842 values.put(Data.PREFERRED_PHONE_ACCOUNT_ID, "preferredid"); 9843 values.put(Data.SYNC1, "sync1"); 9844 values.put(Data.SYNC2, "sync2"); 9845 values.put(Data.SYNC3, "sync3"); 9846 values.put(Data.SYNC4, "sync4"); 9847 } 9848 9849 /** 9850 * @param data1 email address or phone number 9851 * @param usageType One of {@link DataUsageFeedback#USAGE_TYPE} 9852 * @param values ContentValues for this feedback. Useful for incrementing 9853 * {Contacts#TIMES_CONTACTED} in the ContentValue. Can be null. 9854 */ sendFeedback(String data1, String usageType, ContentValues values)9855 private void sendFeedback(String data1, String usageType, ContentValues values) { 9856 final long dataId = getStoredLongValue(Data.CONTENT_URI, 9857 Data.DATA1 + "=?", new String[] { data1 }, Data._ID); 9858 assertEquals(0, updateDataUsageFeedback(usageType, dataId)); 9859 if (values != null && values.containsKey(Contacts.TIMES_CONTACTED)) { 9860 values.put(Contacts.TIMES_CONTACTED, values.getAsInteger(Contacts.TIMES_CONTACTED) + 1); 9861 } 9862 } 9863 updateDataUsageFeedback(String usageType, Uri resultUri)9864 private void updateDataUsageFeedback(String usageType, Uri resultUri) { 9865 final long id = ContentUris.parseId(resultUri); 9866 final boolean successful = updateDataUsageFeedback(usageType, id) > 0; 9867 assertFalse(successful); // shouldn't succeed 9868 } 9869 updateDataUsageFeedback(String usageType, long... ids)9870 private int updateDataUsageFeedback(String usageType, long... ids) { 9871 final StringBuilder idList = new StringBuilder(); 9872 for (long id : ids) { 9873 if (idList.length() > 0) idList.append(","); 9874 idList.append(id); 9875 } 9876 return mResolver.update(DataUsageFeedback.FEEDBACK_URI.buildUpon() 9877 .appendPath(idList.toString()) 9878 .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, usageType) 9879 .build(), new ContentValues(), null, null); 9880 } 9881 hasChineseCollator()9882 private boolean hasChineseCollator() { 9883 final Locale locale[] = Collator.getAvailableLocales(); 9884 for (int i = 0; i < locale.length; i++) { 9885 if (locale[i].equals(Locale.CHINA)) { 9886 return true; 9887 } 9888 } 9889 return false; 9890 } 9891 hasJapaneseCollator()9892 private boolean hasJapaneseCollator() { 9893 final Locale locale[] = Collator.getAvailableLocales(); 9894 for (int i = 0; i < locale.length; i++) { 9895 if (locale[i].equals(Locale.JAPAN)) { 9896 return true; 9897 } 9898 } 9899 return false; 9900 } 9901 hasGermanCollator()9902 private boolean hasGermanCollator() { 9903 final Locale locale[] = Collator.getAvailableLocales(); 9904 for (int i = 0; i < locale.length; i++) { 9905 if (locale[i].equals(Locale.GERMANY)) { 9906 return true; 9907 } 9908 } 9909 return false; 9910 } 9911 9912 9913 /** 9914 * Asserts the equality of two Uri objects, ignoring the order of the query parameters. 9915 */ assertUriEquals(Uri expected, Uri actual)9916 public static void assertUriEquals(Uri expected, Uri actual) { 9917 assertEquals(expected.getScheme(), actual.getScheme()); 9918 assertEquals(expected.getAuthority(), actual.getAuthority()); 9919 assertEquals(expected.getPath(), actual.getPath()); 9920 assertEquals(expected.getFragment(), actual.getFragment()); 9921 Set<String> expectedParameterNames = expected.getQueryParameterNames(); 9922 Set<String> actualParameterNames = actual.getQueryParameterNames(); 9923 assertEquals(expectedParameterNames.size(), actualParameterNames.size()); 9924 assertTrue(expectedParameterNames.containsAll(actualParameterNames)); 9925 for (String parameterName : expectedParameterNames) { 9926 assertEquals(expected.getQueryParameter(parameterName), 9927 actual.getQueryParameter(parameterName)); 9928 } 9929 9930 } 9931 } 9932