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