1 /* 2 * Copyright (C) 2010 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.contacts.common.model; 18 19 import android.content.ContentUris; 20 import android.net.Uri; 21 import android.provider.ContactsContract.CommonDataKinds.GroupMembership; 22 import android.provider.ContactsContract.CommonDataKinds.StructuredName; 23 import android.provider.ContactsContract.Contacts; 24 import android.provider.ContactsContract.Data; 25 import android.provider.ContactsContract.DisplayNameSources; 26 import android.provider.ContactsContract.RawContacts; 27 import android.provider.ContactsContract.StatusUpdates; 28 import android.test.LoaderTestCase; 29 import android.test.suitebuilder.annotation.LargeTest; 30 31 import com.android.contacts.common.model.AccountTypeManager; 32 import com.android.contacts.common.test.mocks.ContactsMockContext; 33 import com.android.contacts.common.test.mocks.MockContentProvider; 34 import com.android.contacts.common.model.account.AccountType; 35 import com.android.contacts.common.model.account.AccountWithDataSet; 36 import com.android.contacts.common.model.account.BaseAccountType; 37 import com.android.contacts.common.test.InjectedServices; 38 import com.android.contacts.common.test.mocks.MockAccountTypeManager; 39 40 /** 41 * Runs ContactLoader tests for the the contact-detail and editor view. 42 */ 43 @LargeTest 44 public class ContactLoaderTest extends LoaderTestCase { 45 private ContactsMockContext mMockContext; 46 private MockContentProvider mContactsProvider; 47 48 @Override 49 protected void setUp() throws Exception { 50 super.setUp(); 51 mMockContext = new ContactsMockContext(getContext()); 52 mContactsProvider = mMockContext.getContactsProvider(); 53 54 InjectedServices services = new InjectedServices(); 55 AccountType accountType = new BaseAccountType() { 56 @Override 57 public boolean areContactsWritable() { 58 return false; 59 } 60 }; 61 accountType.accountType = "mockAccountType"; 62 63 AccountWithDataSet account = 64 new AccountWithDataSet("mockAccountName", "mockAccountType", null); 65 66 AccountTypeManager.setInstanceForTest( 67 new MockAccountTypeManager( 68 new AccountType[]{accountType}, new AccountWithDataSet[]{account})); 69 } 70 71 @Override 72 protected void tearDown() throws Exception { 73 mMockContext = null; 74 mContactsProvider = null; 75 super.tearDown(); 76 } 77 78 private Contact assertLoadContact(Uri uri) { 79 final ContactLoader loader = new ContactLoader(mMockContext, uri, true); 80 return getLoaderResultSynchronously(loader); 81 } 82 83 public void testNullUri() { 84 Contact result = assertLoadContact(null); 85 assertTrue(result.isError()); 86 } 87 88 public void testEmptyUri() { 89 Contact result = assertLoadContact(Uri.EMPTY); 90 assertTrue(result.isError()); 91 } 92 93 public void testInvalidUri() { 94 Contact result = assertLoadContact(Uri.parse("content://wtf")); 95 assertTrue(result.isError()); 96 } 97 98 public void testLoadContactWithContactIdUri() { 99 // Use content Uris that only contain the ID 100 final long contactId = 1; 101 final long rawContactId = 11; 102 final long dataId = 21; 103 104 final String lookupKey = "aa%12%@!"; 105 final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 106 final Uri entityUri = Uri.withAppendedPath(baseUri, Contacts.Entity.CONTENT_DIRECTORY); 107 final Uri lookupUri = ContentUris.withAppendedId( 108 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), 109 contactId); 110 111 ContactQueries queries = new ContactQueries(); 112 mContactsProvider.expectTypeQuery(baseUri, Contacts.CONTENT_ITEM_TYPE); 113 queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey); 114 115 Contact contact = assertLoadContact(baseUri); 116 117 assertEquals(contactId, contact.getId()); 118 assertEquals(rawContactId, contact.getNameRawContactId()); 119 assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource()); 120 assertEquals(lookupKey, contact.getLookupKey()); 121 assertEquals(lookupUri, contact.getLookupUri()); 122 assertEquals(1, contact.getRawContacts().size()); 123 assertEquals(1, contact.getStatuses().size()); 124 mContactsProvider.verify(); 125 } 126 127 public void testLoadContactWithOldStyleUri() { 128 // Use content Uris that only contain the ID but use the format used in Donut 129 final long contactId = 1; 130 final long rawContactId = 11; 131 final long dataId = 21; 132 133 final String lookupKey = "aa%12%@!"; 134 final Uri legacyUri = ContentUris.withAppendedId( 135 Uri.parse("content://contacts"), rawContactId); 136 final Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 137 final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 138 final Uri lookupUri = ContentUris.withAppendedId( 139 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), 140 contactId); 141 final Uri entityUri = Uri.withAppendedPath(lookupUri, Contacts.Entity.CONTENT_DIRECTORY); 142 143 ContactQueries queries = new ContactQueries(); 144 queries.fetchContactIdAndLookupFromRawContactUri(rawContactUri, contactId, lookupKey); 145 queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey); 146 147 Contact contact = assertLoadContact(legacyUri); 148 149 assertEquals(contactId, contact.getId()); 150 assertEquals(rawContactId, contact.getNameRawContactId()); 151 assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource()); 152 assertEquals(lookupKey, contact.getLookupKey()); 153 assertEquals(lookupUri, contact.getLookupUri()); 154 assertEquals(1, contact.getRawContacts().size()); 155 assertEquals(1, contact.getStatuses().size()); 156 mContactsProvider.verify(); 157 } 158 159 public void testLoadContactWithRawContactIdUri() { 160 // Use content Uris that only contain the ID but use the format used in Donut 161 final long contactId = 1; 162 final long rawContactId = 11; 163 final long dataId = 21; 164 165 final String lookupKey = "aa%12%@!"; 166 final Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 167 final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 168 final Uri lookupUri = ContentUris.withAppendedId( 169 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), 170 contactId); 171 final Uri entityUri = Uri.withAppendedPath(lookupUri, Contacts.Entity.CONTENT_DIRECTORY); 172 173 ContactQueries queries = new ContactQueries(); 174 mContactsProvider.expectTypeQuery(rawContactUri, RawContacts.CONTENT_ITEM_TYPE); 175 queries.fetchContactIdAndLookupFromRawContactUri(rawContactUri, contactId, lookupKey); 176 queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey); 177 178 Contact contact = assertLoadContact(rawContactUri); 179 180 assertEquals(contactId, contact.getId()); 181 assertEquals(rawContactId, contact.getNameRawContactId()); 182 assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource()); 183 assertEquals(lookupKey, contact.getLookupKey()); 184 assertEquals(lookupUri, contact.getLookupUri()); 185 assertEquals(1, contact.getRawContacts().size()); 186 assertEquals(1, contact.getStatuses().size()); 187 mContactsProvider.verify(); 188 } 189 190 public void testLoadContactWithContactLookupUri() { 191 // Use lookup-style Uris that do not contain the Contact-ID 192 193 final long contactId = 1; 194 final long rawContactId = 11; 195 final long dataId = 21; 196 197 final String lookupKey = "aa%12%@!"; 198 final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 199 final Uri lookupNoIdUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey); 200 final Uri lookupUri = ContentUris.withAppendedId(lookupNoIdUri, contactId); 201 final Uri entityUri = Uri.withAppendedPath(lookupNoIdUri, Contacts.Entity.CONTENT_DIRECTORY); 202 203 ContactQueries queries = new ContactQueries(); 204 mContactsProvider.expectTypeQuery(lookupNoIdUri, Contacts.CONTENT_ITEM_TYPE); 205 queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey); 206 207 Contact contact = assertLoadContact(lookupNoIdUri); 208 209 assertEquals(contactId, contact.getId()); 210 assertEquals(rawContactId, contact.getNameRawContactId()); 211 assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource()); 212 assertEquals(lookupKey, contact.getLookupKey()); 213 assertEquals(lookupUri, contact.getLookupUri()); 214 assertEquals(1, contact.getRawContacts().size()); 215 assertEquals(1, contact.getStatuses().size()); 216 mContactsProvider.verify(); 217 } 218 219 public void testLoadContactWithContactLookupAndIdUri() { 220 // Use lookup-style Uris that also contain the Contact-ID 221 final long contactId = 1; 222 final long rawContactId = 11; 223 final long dataId = 21; 224 225 final String lookupKey = "aa%12%@!"; 226 final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 227 final Uri lookupUri = ContentUris.withAppendedId( 228 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), 229 contactId); 230 final Uri entityUri = Uri.withAppendedPath(lookupUri, Contacts.Entity.CONTENT_DIRECTORY); 231 232 ContactQueries queries = new ContactQueries(); 233 mContactsProvider.expectTypeQuery(lookupUri, Contacts.CONTENT_ITEM_TYPE); 234 queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey); 235 236 Contact contact = assertLoadContact(lookupUri); 237 238 assertEquals(contactId, contact.getId()); 239 assertEquals(rawContactId, contact.getNameRawContactId()); 240 assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource()); 241 assertEquals(lookupKey, contact.getLookupKey()); 242 assertEquals(lookupUri, contact.getLookupUri()); 243 assertEquals(1, contact.getRawContacts().size()); 244 assertEquals(1, contact.getStatuses().size()); 245 mContactsProvider.verify(); 246 } 247 248 public void testLoadContactWithContactLookupWithIncorrectIdUri() { 249 // Use lookup-style Uris that contain incorrect Contact-ID 250 // (we want to ensure that still the correct contact is chosen) 251 252 final long contactId = 1; 253 final long wrongContactId = 2; 254 final long rawContactId = 11; 255 final long wrongRawContactId = 12; 256 final long dataId = 21; 257 258 final String lookupKey = "aa%12%@!"; 259 final String wrongLookupKey = "ab%12%@!"; 260 final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 261 final Uri wrongBaseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, wrongContactId); 262 final Uri lookupUri = ContentUris.withAppendedId( 263 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), 264 contactId); 265 final Uri lookupWithWrongIdUri = ContentUris.withAppendedId( 266 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), 267 wrongContactId); 268 final Uri entityUri = Uri.withAppendedPath(lookupWithWrongIdUri, 269 Contacts.Entity.CONTENT_DIRECTORY); 270 271 ContactQueries queries = new ContactQueries(); 272 mContactsProvider.expectTypeQuery(lookupWithWrongIdUri, Contacts.CONTENT_ITEM_TYPE); 273 queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey); 274 275 Contact contact = assertLoadContact(lookupWithWrongIdUri); 276 277 assertEquals(contactId, contact.getId()); 278 assertEquals(rawContactId, contact.getNameRawContactId()); 279 assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource()); 280 assertEquals(lookupKey, contact.getLookupKey()); 281 assertEquals(lookupUri, contact.getLookupUri()); 282 assertEquals(1, contact.getRawContacts().size()); 283 assertEquals(1, contact.getStatuses().size()); 284 285 mContactsProvider.verify(); 286 } 287 288 class ContactQueries { 289 public void fetchAllData( 290 Uri baseUri, long contactId, long rawContactId, long dataId, String encodedLookup) { 291 mContactsProvider.expectQuery(baseUri) 292 .withProjection(new String[] { 293 Contacts.NAME_RAW_CONTACT_ID, Contacts.DISPLAY_NAME_SOURCE, 294 Contacts.LOOKUP_KEY, Contacts.DISPLAY_NAME, 295 Contacts.DISPLAY_NAME_ALTERNATIVE, Contacts.PHONETIC_NAME, 296 Contacts.PHOTO_ID, Contacts.STARRED, Contacts.CONTACT_PRESENCE, 297 Contacts.CONTACT_STATUS, Contacts.CONTACT_STATUS_TIMESTAMP, 298 Contacts.CONTACT_STATUS_RES_PACKAGE, Contacts.CONTACT_STATUS_LABEL, 299 300 Contacts.Entity.CONTACT_ID, 301 Contacts.Entity.RAW_CONTACT_ID, 302 303 RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_TYPE, 304 RawContacts.DATA_SET, RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 305 RawContacts.DIRTY, RawContacts.VERSION, RawContacts.SOURCE_ID, 306 RawContacts.SYNC1, RawContacts.SYNC2, RawContacts.SYNC3, RawContacts.SYNC4, 307 RawContacts.DELETED, RawContacts.NAME_VERIFIED, 308 309 Contacts.Entity.DATA_ID, 310 311 Data.DATA1, Data.DATA2, Data.DATA3, Data.DATA4, Data.DATA5, 312 Data.DATA6, Data.DATA7, Data.DATA8, Data.DATA9, Data.DATA10, 313 Data.DATA11, Data.DATA12, Data.DATA13, Data.DATA14, Data.DATA15, 314 Data.SYNC1, Data.SYNC2, Data.SYNC3, Data.SYNC4, 315 Data.DATA_VERSION, Data.IS_PRIMARY, 316 Data.IS_SUPER_PRIMARY, Data.MIMETYPE, Data.RES_PACKAGE, 317 318 GroupMembership.GROUP_SOURCE_ID, 319 320 Data.PRESENCE, Data.CHAT_CAPABILITY, 321 Data.STATUS, Data.STATUS_RES_PACKAGE, Data.STATUS_ICON, 322 Data.STATUS_LABEL, Data.STATUS_TIMESTAMP, 323 324 Contacts.PHOTO_URI, 325 326 Contacts.SEND_TO_VOICEMAIL, 327 Contacts.CUSTOM_RINGTONE, 328 Contacts.IS_USER_PROFILE, 329 }) 330 .withSortOrder(Contacts.Entity.RAW_CONTACT_ID) 331 .returnRow( 332 rawContactId, 40, 333 "aa%12%@!", "John Doe", "Doe, John", "jdo", 334 0, 0, StatusUpdates.AVAILABLE, 335 "Having lunch", 0, 336 "mockPkg1", 10, 337 338 contactId, 339 rawContactId, 340 341 "mockAccountName", "mockAccountType", null, "mockAccountType", 342 0, 1, 0, 343 "sync1", "sync2", "sync3", "sync4", 344 0, 0, 345 346 dataId, 347 348 "dat1", "dat2", "dat3", "dat4", "dat5", 349 "dat6", "dat7", "dat8", "dat9", "dat10", 350 "dat11", "dat12", "dat13", "dat14", "dat15", 351 "syn1", "syn2", "syn3", "syn4", 352 353 0, 0, 354 0, StructuredName.CONTENT_ITEM_TYPE, "mockPkg2", 355 356 "groupId", 357 358 StatusUpdates.INVISIBLE, null, 359 "Having dinner", "mockPkg3", 0, 360 20, 0, 361 362 "content:some.photo.uri", 363 364 0, 365 null, 366 0 367 ); 368 } 369 370 void fetchLookupAndId(final Uri sourceUri, final long expectedContactId, 371 final String expectedEncodedLookup) { 372 mContactsProvider.expectQuery(sourceUri) 373 .withProjection(Contacts.LOOKUP_KEY, Contacts._ID) 374 .returnRow(expectedEncodedLookup, expectedContactId); 375 } 376 377 void fetchContactIdAndLookupFromRawContactUri(final Uri rawContactUri, 378 final long expectedContactId, final String expectedEncodedLookup) { 379 // TODO: use a lighter query by joining rawcontacts with contacts in provider 380 // (See ContactContracts.java) 381 final Uri dataUri = Uri.withAppendedPath(rawContactUri, 382 RawContacts.Data.CONTENT_DIRECTORY); 383 mContactsProvider.expectQuery(dataUri) 384 .withProjection(RawContacts.CONTACT_ID, Contacts.LOOKUP_KEY) 385 .returnRow(expectedContactId, expectedEncodedLookup); 386 } 387 } 388 } 389