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