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