• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.app.SearchManager;
20 import android.content.ContentProvider;
21 import android.content.ContentUris;
22 import android.content.ContentValues;
23 import android.database.Cursor;
24 import android.net.Uri;
25 import android.provider.Contacts;
26 import android.provider.Contacts.ContactMethods;
27 import android.provider.Contacts.Extensions;
28 import android.provider.Contacts.GroupMembership;
29 import android.provider.Contacts.Groups;
30 import android.provider.Contacts.Organizations;
31 import android.provider.Contacts.People;
32 import android.provider.Contacts.Phones;
33 import android.provider.Contacts.Photos;
34 import android.provider.Contacts.Presence;
35 import android.provider.Contacts.Settings;
36 import android.provider.ContactsContract;
37 import android.test.suitebuilder.annotation.MediumTest;
38 
39 import java.io.IOException;
40 
41 /**
42  * Tests for legacy contacts APIs.
43  *
44  * Run the test like this:
45  * <code>
46  * adb shell am instrument -e class com.android.providers.contacts.LegacyContactsProviderTest -w \
47  *         com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
48  * </code>
49  *
50  * Note that this SHOULD be a large test, but had to be bumped down to medium due to a bug in the
51  * SQLite cleanup code.
52  */
53 @MediumTest
54 @SuppressWarnings("deprecation")
55 public class LegacyContactsProviderTest extends BaseContactsProvider2Test {
56 
57     @Override
getProviderClass()58     protected Class<? extends ContentProvider> getProviderClass() {
59        return SynchronousContactsProvider2.class;
60     }
61 
62     @Override
getAuthority()63     protected String getAuthority() {
64         return Contacts.AUTHORITY + ";" + ContactsContract.AUTHORITY;
65     }
66 
testPeopleInsert()67     public void testPeopleInsert() {
68         ContentValues values = new ContentValues();
69         putContactValues(values);
70 
71         Uri uri = mResolver.insert(People.CONTENT_URI, values);
72         assertStoredValues(uri, values);
73         assertSelection(People.CONTENT_URI, values, "people", People._ID, ContentUris.parseId(uri));
74     }
75 
testPeopleUpdate()76     public void testPeopleUpdate() {
77         ContentValues values = new ContentValues();
78         putContactValues(values);
79 
80         Uri uri = mResolver.insert(People.CONTENT_URI, values);
81         long personId = ContentUris.parseId(uri);
82         assertStoredValues(uri, values);
83         assertSelection(People.CONTENT_URI, values, "people", People._ID, personId);
84 
85         values.clear();
86         putContactValues2(values);
87         mResolver.update(uri, values, null, null);
88         assertStoredValues(uri, values);
89 
90         values.clear();
91         putContactValues(values);
92         mResolver.update(People.CONTENT_URI, values, People._ID + "=" + personId, null);
93         assertStoredValues(uri, values);
94     }
95 
testPeopleDelete()96     public void testPeopleDelete() {
97         ContentValues values = new ContentValues();
98         values.put(People.NAME, "John Doe");
99         Uri personId = mResolver.insert(People.CONTENT_URI, values);
100         mResolver.delete(personId, null, null);
101 
102         Cursor c = mResolver.query(personId, null, People.NAME + "='John Doe'" , null, null);
103         assertEquals("Record count after deletion", 0, c.getCount());
104         c.close();
105 
106         try {
107             mResolver.query(People.DELETED_CONTENT_URI, null, null, null, null);
108         } catch (UnsupportedOperationException e) {
109             // Expected exception
110         }
111     }
112 
testPeopleFilter()113     public void testPeopleFilter() {
114         ContentValues values = new ContentValues();
115         values.put(People.NAME, "Deer Doe");
116         mResolver.insert(People.CONTENT_URI, values);
117 
118         values.clear();
119         values.put(People.NAME, "Dear Dough");
120         mResolver.insert(People.CONTENT_URI, values);
121 
122         values.clear();
123         values.put(People.NAME, "D.R. Dauwe");
124         mResolver.insert(People.CONTENT_URI, values);
125 
126         assertFilteredContacts("d", "Deer Doe", "Dear Dough", "D.R. Dauwe");
127         assertFilteredContacts("de", "Deer Doe", "Dear Dough");
128         assertFilteredContacts("dee", "Deer Doe");
129         assertFilteredContacts("der");
130     }
131 
testDefaultDisplayName()132     public void testDefaultDisplayName() {
133         ContentValues values = new ContentValues();
134         values.put(People.NAME, "John Doe");
135         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
136         assertStoredValue(personUri, People.DISPLAY_NAME, "John Doe");
137     }
138 
testPrimaryOrganization()139     public void testPrimaryOrganization() {
140         ContentValues values = new ContentValues();
141         final Uri personUri = mResolver.insert(People.CONTENT_URI, values);
142         long personId = ContentUris.parseId(personUri);
143 
144         // Primary
145         values.clear();
146         values.put(Organizations.ISPRIMARY, 1);
147         values.put(Organizations.COMPANY, "Google");
148         values.put(Organizations.TYPE, Organizations.TYPE_WORK);
149         values.put(Organizations.PERSON_ID, personId);
150         Uri orgUri1 = mResolver.insert(Organizations.CONTENT_URI, values);
151 
152         // Non-primary
153         values.clear();
154         values.put(Organizations.COMPANY, "Acme");
155         values.put(Organizations.TYPE, Organizations.TYPE_WORK);
156         values.put(Organizations.PERSON_ID, personId);
157         Uri orgUri2 = mResolver.insert(Organizations.CONTENT_URI, values);
158 
159         values.clear();
160         values.put(People.PRIMARY_ORGANIZATION_ID, ContentUris.parseId(orgUri1));
161         values.put(People.DISPLAY_NAME, "Google");
162         assertStoredValues(personUri, values);
163 
164         // Remove the original primary organization
165         mResolver.delete(orgUri1, null, null);
166 
167         values.clear();
168         values.put(People.PRIMARY_ORGANIZATION_ID, ContentUris.parseId(orgUri2));
169         values.put(People.DISPLAY_NAME, "Acme");
170         assertStoredValues(personUri, values);
171 
172         // Remove the remaining organization
173         mResolver.delete(orgUri2, null, null);
174 
175         values.clear();
176         values.putNull(People.PRIMARY_ORGANIZATION_ID);
177         values.putNull(People.DISPLAY_NAME);
178         assertStoredValues(personUri, values);
179     }
180 
testPrimaryPhone()181     public void testPrimaryPhone() {
182         ContentValues values = new ContentValues();
183         putContactValuesExceptName(values);
184 
185         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
186         long personId = ContentUris.parseId(personUri);
187 
188         // Primary
189         values.clear();
190         values.put(Phones.ISPRIMARY, 1);
191         values.put(Phones.TYPE, Phones.TYPE_WORK);
192         values.put(Phones.PERSON_ID, personId);
193         values.put(Phones.NUMBER, "12345");
194         Uri phoneUri1 = mResolver.insert(Phones.CONTENT_URI, values);
195 
196         // Non-primary
197         values.clear();
198         values.put(Phones.TYPE, Phones.TYPE_WORK);
199         values.put(Phones.PERSON_ID, personId);
200         values.put(Phones.NUMBER, "67890");
201         Uri phoneUri2 = mResolver.insert(Phones.CONTENT_URI, values);
202 
203         values.clear();
204         values.put(People.PRIMARY_PHONE_ID, ContentUris.parseId(phoneUri1));
205         values.put(People.DISPLAY_NAME, "12345");
206         assertStoredValues(personUri, values);
207 
208         values.clear();
209         putContactValuesExceptName(values);
210         values.put(People.PRIMARY_PHONE_ID, ContentUris.parseId(phoneUri1));
211         assertStoredValues(phoneUri2, values);
212 
213         // Remove the primary phone number
214         mResolver.delete(phoneUri1, null, null);
215 
216         values.clear();
217         values.put(People.PRIMARY_PHONE_ID, ContentUris.parseId(phoneUri2));
218         values.put(People.DISPLAY_NAME, "67890");
219         assertStoredValues(personUri, values);
220 
221         // Remove the remaining phone number
222         mResolver.delete(phoneUri2, null, null);
223 
224         values.clear();
225         values.putNull(People.PRIMARY_PHONE_ID);
226         values.putNull(People.DISPLAY_NAME);
227         assertStoredValues(personUri, values);
228     }
229 
testEmailCrud()230     public void testEmailCrud() {
231         ContentValues values = new ContentValues();
232         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
233         long personId = ContentUris.parseId(personUri);
234 
235         // Primary
236         values.clear();
237         values.put(ContactMethods.PERSON_ID, personId);
238         values.put(ContactMethods.KIND, Contacts.KIND_EMAIL);
239         values.put(ContactMethods.TYPE, ContactMethods.TYPE_HOME);
240         values.put(ContactMethods.DATA, "foo@acme.com");
241         values.put(ContactMethods.ISPRIMARY, 1);
242         Uri emailUri1 = mResolver.insert(ContactMethods.CONTENT_URI, values);
243 
244         assertEquals(ContactMethods.CONTENT_EMAIL_ITEM_TYPE, mResolver.getType(emailUri1));
245 
246         assertStoredValues(ContactMethods.CONTENT_URI,
247                 ContactMethods._ID + "=" + ContentUris.parseId(emailUri1), null, values);
248         assertStoredValues(ContactMethods.CONTENT_EMAIL_URI,
249                 ContactMethods._ID + "=" + ContentUris.parseId(emailUri1), null, values);
250     }
251 
testPrimaryEmail()252     public void testPrimaryEmail() {
253         ContentValues values = new ContentValues();
254         putContactValuesExceptName(values);
255         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
256         long personId = ContentUris.parseId(personUri);
257 
258         // Primary
259         values.clear();
260         values.put(ContactMethods.PERSON_ID, personId);
261         values.put(ContactMethods.KIND, Contacts.KIND_EMAIL);
262         values.put(ContactMethods.TYPE, ContactMethods.TYPE_HOME);
263         values.put(ContactMethods.DATA, "foo@acme.com");
264         values.put(ContactMethods.ISPRIMARY, 1);
265         Uri emailUri1 = mResolver.insert(ContactMethods.CONTENT_URI, values);
266 
267         // Non-primary
268         values.clear();
269         values.put(ContactMethods.PERSON_ID, personId);
270         values.put(ContactMethods.KIND, Contacts.KIND_EMAIL);
271         values.put(ContactMethods.TYPE, ContactMethods.TYPE_WORK);
272         values.put(ContactMethods.DATA, "bar@acme.com");
273         Uri emailUri2 = mResolver.insert(ContactMethods.CONTENT_URI, values);
274 
275         values.clear();
276         values.put(People.PRIMARY_EMAIL_ID, ContentUris.parseId(emailUri1));
277         values.put(People.DISPLAY_NAME, "foo@acme.com");
278         assertStoredValues(personUri, values);
279 
280         values.clear();
281         putContactValuesExceptName(values);
282         values.put(People.PRIMARY_EMAIL_ID, ContentUris.parseId(emailUri1));
283         assertStoredValues(emailUri2, values);
284 
285         // Remove the primary email
286         mResolver.delete(emailUri1, null, null);
287 
288         values.clear();
289         values.put(People.PRIMARY_EMAIL_ID, ContentUris.parseId(emailUri2));
290         values.put(People.DISPLAY_NAME, "bar@acme.com");
291         assertStoredValues(personUri, values);
292 
293         // Remove the remaining email
294         mResolver.delete(emailUri2, null, null);
295 
296         values.clear();
297         values.putNull(People.PRIMARY_EMAIL_ID);
298         values.putNull(People.DISPLAY_NAME);
299         assertStoredValues(personUri, values);
300     }
301 
testMarkAsContacted()302     public void testMarkAsContacted() {
303         ContentValues values = new ContentValues();
304         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
305         long personId = ContentUris.parseId(personUri);
306 
307         int timesContactedBefore =
308                 Integer.parseInt(getStoredValue(personUri, People.TIMES_CONTACTED));
309         long timeBefore = System.currentTimeMillis();
310         People.markAsContacted(mResolver, personId);
311         long timeAfter = System.currentTimeMillis();
312 
313         long lastContacted = Long.parseLong(getStoredValue(personUri, People.LAST_TIME_CONTACTED));
314         int timesContactedAfter =
315             Integer.parseInt(getStoredValue(personUri, People.TIMES_CONTACTED));
316 
317         assertTrue(lastContacted >= timeBefore);
318         assertTrue(lastContacted <= timeAfter);
319         assertEquals(timesContactedAfter, timesContactedBefore + 1);
320     }
321 
testOrganizationsInsert()322     public void testOrganizationsInsert() {
323         ContentValues values = new ContentValues();
324         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
325         long personId = ContentUris.parseId(personUri);
326 
327         values.clear();
328         values.put(Organizations.COMPANY, "Sierra");
329         values.put(Organizations.PERSON_ID, personId);
330         values.put(Organizations.TYPE, Organizations.TYPE_CUSTOM);
331         values.put(Organizations.LABEL, "Club");
332         values.put(Organizations.TITLE, "Member");
333         values.put(Organizations.ISPRIMARY, 1);
334 
335         Uri uri = mResolver.insert(Organizations.CONTENT_URI, values);
336         assertStoredValues(uri, values);
337         assertSelection(Organizations.CONTENT_URI, values,
338                 "organizations", Organizations._ID, ContentUris.parseId(uri));
339 
340         assertPersonIdConstraint(Organizations.CONTENT_URI, Organizations.TYPE,
341                 Organizations.TYPE_WORK);
342 
343         assertTypeAndLabelConstraints(Organizations.CONTENT_URI, Organizations.PERSON_ID, personId,
344                 Organizations.TYPE, Organizations.TYPE_CUSTOM, Organizations.TYPE_OTHER,
345                 Organizations.LABEL);
346 
347 
348         Uri twigUri = Uri.withAppendedPath(personUri, Organizations.CONTENT_DIRECTORY);
349         assertStoredValues(twigUri, values);
350 
351         Uri twigUriWithId = ContentUris.withAppendedId(twigUri, ContentUris.parseId(uri));
352         assertStoredValues(twigUriWithId, values);
353     }
354 
testOrganizationsUpdate()355     public void testOrganizationsUpdate() {
356         ContentValues values = new ContentValues();
357         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
358         long personId = ContentUris.parseId(personUri);
359 
360         values.clear();
361         values.put(Organizations.COMPANY, "Sierra");
362         values.put(Organizations.PERSON_ID, personId);
363         values.put(Organizations.TYPE, Organizations.TYPE_CUSTOM);
364         values.put(Organizations.LABEL, "Club");
365         values.put(Organizations.TITLE, "Member");
366         values.put(Organizations.ISPRIMARY, 0);
367 
368         Uri uri = mResolver.insert(Organizations.CONTENT_URI, values);
369 
370         values.clear();
371         values.put(Organizations.COMPANY, "Planetary");
372         values.put(Organizations.PERSON_ID, personId);
373         values.put(Organizations.TYPE, Organizations.TYPE_CUSTOM);
374         values.put(Organizations.LABEL, "Society");
375         values.put(Organizations.TITLE, "Chair");
376         values.put(Organizations.ISPRIMARY, 1);
377 
378         mResolver.update(uri, values, null, null);
379 
380         assertStoredValues(uri, values);
381     }
382 
testPhonesInsert()383     public void testPhonesInsert() {
384         ContentValues values = new ContentValues();
385         putContactValues(values);
386         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
387         long personId = ContentUris.parseId(personUri);
388 
389         values.clear();
390         values.put(Phones.PERSON_ID, personId);
391         values.put(Phones.TYPE, Phones.TYPE_CUSTOM);
392         values.put(Phones.LABEL, "Directory");
393         values.put(Phones.NUMBER, "1-800-4664-411");
394         values.put(Phones.ISPRIMARY, 1);
395 
396         Uri uri = mResolver.insert(Phones.CONTENT_URI, values);
397         ContentValues expectedResults[] = new ContentValues[1];
398         // Adding another value to assert
399         expectedResults[0] = new ContentValues(values);
400         expectedResults[0].put(Phones.NUMBER_KEY, "11446640081");
401 
402         // The result is joined with People
403         putContactValues(expectedResults[0]);
404         assertStoredValues(uri, expectedResults);
405         assertSelection(Phones.CONTENT_URI, values, "phones",
406                 Phones._ID, ContentUris.parseId(uri));
407 
408         // Access the phone through People
409         Uri twigUri = Uri.withAppendedPath(personUri, People.Phones.CONTENT_DIRECTORY);
410         assertStoredValues(twigUri, expectedResults);
411 
412         // Now the person should be joined with Phone
413         values.clear();
414         putContactValues(values);
415         values.put(People.TYPE, Phones.TYPE_CUSTOM);
416         values.put(People.LABEL, "Directory");
417         values.put(People.NUMBER, "1-800-4664-411");
418         assertStoredValues(personUri, values);
419 
420         assertPersonIdConstraint(Phones.CONTENT_URI, Phones.TYPE, Phones.TYPE_WORK);
421 
422         assertTypeAndLabelConstraints(Phones.CONTENT_URI, Phones.PERSON_ID, personId, Phones.TYPE,
423                 Phones.TYPE_CUSTOM, Phones.TYPE_OTHER, Phones.LABEL);
424     }
425 
testPhonesUpdate()426     public void testPhonesUpdate() {
427         ContentValues values = new ContentValues();
428         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
429         long personId = ContentUris.parseId(personUri);
430 
431         values.clear();
432         values.put(Phones.PERSON_ID, personId);
433         values.put(Phones.TYPE, Phones.TYPE_CUSTOM);
434         values.put(Phones.LABEL, "Directory");
435         values.put(Phones.NUMBER, "1-800-4664-411");
436         values.put(Phones.ISPRIMARY, 0);
437 
438         Uri uri = mResolver.insert(Phones.CONTENT_URI, values);
439 
440         values.clear();
441         values.put(Phones.PERSON_ID, personId);
442         values.put(Phones.TYPE, Phones.TYPE_FAX_HOME);
443         values.putNull(Phones.LABEL);
444         values.put(Phones.NUMBER, "1-800-555-4663");
445         values.put(Phones.ISPRIMARY, 1);
446 
447         mResolver.update(uri, values, null, null);
448 
449         ContentValues[] expectedValues = new ContentValues[1];
450         expectedValues[0] = values;
451         expectedValues[0].put(Phones.NUMBER_KEY, "36645550081");
452         assertStoredValues(uri, expectedValues);
453     }
454 
testPhonesFilterQuery()455     public void testPhonesFilterQuery() {
456         ContentValues values = new ContentValues();
457         putContactValues(values);
458         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
459         long personId = ContentUris.parseId(personUri);
460 
461         values.clear();
462         values.put(Phones.PERSON_ID, personId);
463         values.put(Phones.TYPE, Phones.TYPE_CUSTOM);
464         values.put(Phones.LABEL, "Directory");
465         values.put(Phones.NUMBER, "800-4664-411");
466         values.put(Phones.ISPRIMARY, 1);
467 
468         Uri uri = mResolver.insert(Phones.CONTENT_URI, values);
469 
470         Uri filterUri1 = Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, "18004664411");
471         ContentValues[] expectedValues = new ContentValues[1];
472         expectedValues[0] = values;
473         expectedValues[0].put(Phones.NUMBER_KEY, "1144664008");
474         assertStoredValues(filterUri1, expectedValues);
475 
476         Uri filterUri2 = Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, "7773334444");
477         assertEquals(0, getCount(filterUri2, null, null));
478     }
479 
testEmailInsert()480     public void testEmailInsert() {
481         assertContactMethodInsert(Contacts.KIND_EMAIL,
482                 ContactMethods.TYPE_CUSTOM, "Some other way", "foo@acme.com", null, true);
483     }
484 
testEmailUpdate()485     public void testEmailUpdate() {
486         assertContactMethodUpdate(Contacts.KIND_EMAIL,
487                 ContactMethods.TYPE_CUSTOM, "Some other way", "foo@acme.com", null, false,
488                 ContactMethods.TYPE_HOME, null, "bar@acme.com", "aux", true);
489     }
490 
testImInsertStandard()491     public void testImInsertStandard() {
492         assertContactMethodInsert(Contacts.KIND_IM,
493                 ContactMethods.TYPE_CUSTOM, "Some other way", "pre:3", "Bar", true);
494     }
495 
testImUpdateStandard()496     public void testImUpdateStandard() {
497         assertContactMethodUpdate(Contacts.KIND_IM,
498                 ContactMethods.TYPE_CUSTOM, "Some other way", "pre:3", "Bar", false,
499                 ContactMethods.TYPE_WORK, null, "pre:4", "Buz", true);
500     }
501 
testImInsertCustom()502     public void testImInsertCustom() {
503         assertContactMethodInsert(Contacts.KIND_IM,
504                 ContactMethods.TYPE_CUSTOM, "Some other way", "custom:my_proto", "Bar", true);
505     }
506 
testImUpdateCustom()507     public void testImUpdateCustom() {
508         assertContactMethodUpdate(Contacts.KIND_IM,
509                 ContactMethods.TYPE_CUSTOM, "Some other way", "custom:my_proto", "Bar", false,
510                 ContactMethods.TYPE_HOME, null, "custom:my_other_proto", "Buz", true);
511     }
512 
testPostalInsert()513     public void testPostalInsert() {
514         assertContactMethodInsert(Contacts.KIND_POSTAL,
515                 ContactMethods.TYPE_CUSTOM, "Some other way", "Foo", "Bar", true);
516     }
517 
testPostalUpdate()518     public void testPostalUpdate() {
519         assertContactMethodUpdate(Contacts.KIND_POSTAL,
520                 ContactMethods.TYPE_CUSTOM, "Some other way", "Foo", "Bar", false,
521                 ContactMethods.TYPE_WORK, null, "Biz", "Baz", true);
522     }
523 
assertContactMethodInsert(int kind, int type, String label, String data, String auxData, boolean primary)524     private void assertContactMethodInsert(int kind, int type, String label, String data,
525             String auxData, boolean primary) {
526         ContentValues values = new ContentValues();
527         putContactValues(values);
528         final Uri personUri = mResolver.insert(People.CONTENT_URI, values);
529         long personId = ContentUris.parseId(personUri);
530 
531         values.clear();
532         values.put(ContactMethods.PERSON_ID, personId);
533         values.put(ContactMethods.KIND, kind);
534         values.put(ContactMethods.TYPE, type);
535         values.put(ContactMethods.LABEL, label);
536         values.put(ContactMethods.DATA, data);
537         values.put(ContactMethods.AUX_DATA, auxData);
538         values.put(ContactMethods.ISPRIMARY, primary ? 1 : 0);
539 
540         Uri uri = mResolver.insert(ContactMethods.CONTENT_URI, values);
541 
542         // The result is joined with People
543         putContactValues(values);
544         assertStoredValues(uri, values);
545         assertSelection(ContactMethods.CONTENT_URI, values, "contact_methods",
546                 ContactMethods._ID, ContentUris.parseId(uri));
547 
548         // Access the contact method through People
549         Uri twigUri = Uri.withAppendedPath(personUri, People.ContactMethods.CONTENT_DIRECTORY);
550         assertStoredValues(twigUri, values);
551 
552         assertPersonIdConstraint(ContactMethods.CONTENT_URI, ContactMethods.TYPE,
553                 ContactMethods.TYPE_WORK);
554 
555         assertTypeAndLabelConstraints(ContactMethods.CONTENT_URI, ContactMethods.PERSON_ID,
556                 personId, ContactMethods.TYPE, ContactMethods.TYPE_CUSTOM,
557                 ContactMethods.TYPE_OTHER, ContactMethods.LABEL);
558     }
559 
assertContactMethodUpdate(int kind, int type1, String label1, String data1, String auxData1, boolean primary1, int type2, String label2, String data2, String auxData2, boolean primary2)560     private void assertContactMethodUpdate(int kind,
561             int type1, String label1, String data1, String auxData1, boolean primary1,
562             int type2, String label2, String data2, String auxData2, boolean primary2) {
563         ContentValues values = new ContentValues();
564         putContactValues(values);
565         final Uri personUri = mResolver.insert(People.CONTENT_URI, values);
566         long personId = ContentUris.parseId(personUri);
567 
568         values.clear();
569         values.put(ContactMethods.PERSON_ID, personId);
570         values.put(ContactMethods.KIND, kind);
571         values.put(ContactMethods.TYPE, type1);
572         values.put(ContactMethods.LABEL, label1);
573         values.put(ContactMethods.DATA, data1);
574         values.put(ContactMethods.AUX_DATA, auxData1);
575         values.put(ContactMethods.ISPRIMARY, primary1 ? 1 : 0);
576 
577         Uri uri = mResolver.insert(ContactMethods.CONTENT_URI, values);
578 
579         values.clear();
580         values.put(ContactMethods.TYPE, type2);
581         values.put(ContactMethods.LABEL, label2);
582         values.put(ContactMethods.DATA, data2);
583         values.put(ContactMethods.AUX_DATA, auxData2);
584         values.put(ContactMethods.ISPRIMARY, primary2 ? 1 : 0);
585         mResolver.update(uri, values, null, null);
586 
587         assertStoredValues(uri, values);
588     }
589 
testExtensionsInsert()590     public void testExtensionsInsert() {
591         ContentValues values = new ContentValues();
592         final Uri personUri = mResolver.insert(People.CONTENT_URI, values);
593         long personId = ContentUris.parseId(personUri);
594 
595         values.clear();
596         values.put(Extensions.PERSON_ID, personId);
597         values.put(Extensions.NAME, "Foo");
598         values.put(Extensions.VALUE, "Bar");
599 
600         Uri uri = mResolver.insert(Extensions.CONTENT_URI, values);
601         assertStoredValues(uri, values);
602         assertSelection(Extensions.CONTENT_URI, values, "extensions",
603                 Extensions._ID, ContentUris.parseId(uri));
604 
605         // Access the extensions through People
606         Uri twigUri = Uri.withAppendedPath(personUri, People.Extensions.CONTENT_DIRECTORY);
607         assertStoredValues(twigUri, values);
608     }
609 
testExtensionsUpdate()610     public void testExtensionsUpdate() {
611         ContentValues values = new ContentValues();
612         final Uri personUri = mResolver.insert(People.CONTENT_URI, values);
613         long personId = ContentUris.parseId(personUri);
614 
615         values.clear();
616         values.put(Extensions.PERSON_ID, personId);
617         values.put(Extensions.NAME, "Foo");
618         values.put(Extensions.VALUE, "Bar");
619 
620         Uri uri = mResolver.insert(Extensions.CONTENT_URI, values);
621 
622         values.clear();
623         values.put(Extensions.NAME, "Biz");
624         values.put(Extensions.VALUE, "Baz");
625         mResolver.update(uri, values, null, null);
626 
627         assertStoredValues(uri, values);
628     }
629 
testGroupsInsert()630     public void testGroupsInsert() {
631         ContentValues values = new ContentValues();
632         values.put(Groups.NAME, "Galois");
633         values.put(Groups.NOTES, "Abel");
634         values.put(Groups.SYSTEM_ID, "12345");
635 
636         Uri groupUri = mResolver.insert(Groups.CONTENT_URI, values);
637         assertStoredValues(groupUri, values);
638     }
639 
testGroupsUpdate()640     public void testGroupsUpdate() {
641         ContentValues values = new ContentValues();
642         values.put(Groups.NAME, "Galois");
643         values.put(Groups.NOTES, "Abel");
644         values.put(Groups.SYSTEM_ID, "12345");
645 
646         Uri groupUri = mResolver.insert(Groups.CONTENT_URI, values);
647 
648         values.clear();
649         values.put(Groups.NAME, "Klein");
650         values.put(Groups.NOTES, "Vierergruppe");
651         values.put(Groups.SYSTEM_ID, "1234");
652         mResolver.update(groupUri, values, null, null);
653         assertStoredValues(groupUri, values);
654     }
655 
testGroupMembershipsInsert()656     public void testGroupMembershipsInsert() {
657         ContentValues values = new ContentValues();
658         values.put(Groups.NOTES, "Abel");
659         Uri groupUri = insertLegacyGroup("Galois", values);
660         Uri personUri = insertPerson("Klein", values);
661         Uri membershipUri = insertLegacyGroupMembership(groupUri, personUri, values);
662         values.put(Groups.NAME, "Galois");
663         values.put(Groups.NOTES, "Abel");
664 
665         assertStoredValues(membershipUri, values);
666         assertSelection(GroupMembership.CONTENT_URI, values, "groupmembership",
667                 GroupMembership._ID, ContentUris.parseId(membershipUri));
668 
669         Uri personsGroupsUri = Uri.withAppendedPath(personUri, GroupMembership.CONTENT_DIRECTORY);
670         assertStoredValues(personsGroupsUri, values);
671     }
672 
testAddToGroup()673     public void testAddToGroup() {
674         ContentValues values = new ContentValues();
675         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
676         long personId = ContentUris.parseId(personUri);
677 
678         values.clear();
679         values.put(Groups.NAME, "Galois");
680         Uri groupUri = mResolver.insert(Groups.CONTENT_URI, values);
681 
682         People.addToGroup(mResolver, personId, "Galois");
683 
684         values.clear();
685         values.put(GroupMembership.GROUP_ID, ContentUris.parseId(groupUri));
686         values.put(GroupMembership.PERSON_ID, personId);
687 
688         Uri personsGroupsUri = Uri.withAppendedPath(personUri, GroupMembership.CONTENT_DIRECTORY);
689         assertStoredValues(personsGroupsUri, values);
690     }
691 
testGroupMembersByGroupName()692     public void testGroupMembersByGroupName() {
693         ContentValues values = new ContentValues();
694         Uri groupUri1 = insertLegacyGroup("Galois", values);
695         Uri personUri1 = insertPerson("Klein", values);
696         insertLegacyGroupMembership(groupUri1, personUri1, values);
697 
698         Uri groupUri2 = insertLegacyGroup("Euler", values);
699         Uri personUri2 = insertPerson("Lagrange", values);
700         insertLegacyGroupMembership(groupUri2, personUri2, values);
701 
702         // NOTE: testing non-public API support
703         assertStoredValue(Uri.parse("content://contacts/groups/name/Galois/members"),
704                 People.NAME, "Klein");
705         assertStoredValue(Uri.parse("content://contacts/groups/name/Euler/members"),
706                 People.NAME, "Lagrange");
707     }
708 
testPhotoUpdate()709     public void testPhotoUpdate() throws Exception {
710         byte[] photo = loadPhotoFromResource(
711                 com.android.providers.contacts.tests.R.drawable.earth_small, PhotoSize.ORIGINAL);
712         byte[] thumbnailedPhoto = loadPhotoFromResource(
713                 com.android.providers.contacts.tests.R.drawable.earth_small, PhotoSize.THUMBNAIL);
714 
715         ContentValues values = new ContentValues();
716         Uri personUri = mResolver.insert(People.CONTENT_URI, values);
717 
718         values.clear();
719         values.put(Photos.DATA, photo);
720         values.put(Photos.LOCAL_VERSION, "10");
721         // FIXME this column was unavailable for update in legacy ContactsProvider
722         // values.put(Photos.DOWNLOAD_REQUIRED, 1);
723         values.put(Photos.EXISTS_ON_SERVER, 1);
724         values.put(Photos.SYNC_ERROR, "404 does not exist");
725 
726         Uri photoUri = Uri.withAppendedPath(personUri, Photos.CONTENT_DIRECTORY);
727         mResolver.update(photoUri, values, null, null);
728         values.put(Photos.DATA, thumbnailedPhoto);
729         assertStoredValues(photoUri, values);
730 
731         long photoId = Long.parseLong(getStoredValue(photoUri, Photos._ID));
732 
733         values.put(Photos.LOCAL_VERSION, "11");
734         values.put(Photos.DATA, photo);
735         Uri contentUri = ContentUris.withAppendedId(Photos.CONTENT_URI, photoId);
736         mResolver.update(contentUri, values, null, null);
737         values.put(Photos.DATA, thumbnailedPhoto);
738         assertStoredValues(contentUri, values);
739         assertStoredValues(photoUri, values);
740     }
741 
742     /**
743      * Capturing the search suggestion requirements in test cases as a reference.
744      */
testSearchSuggestionsNotInMyContacts()745     public void testSearchSuggestionsNotInMyContacts() throws Exception {
746         // We don't provide compatibility for search suggestions
747         return;
748     }
749 
750     /**
751      * Capturing the search suggestion requirements in test cases as a reference.
752      */
testSearchSuggestionsByName()753     public void testSearchSuggestionsByName() throws Exception {
754 
755         // We don't provide compatibility for search suggestions
756         return;
757     }
758 
assertSearchSuggestion(boolean name, boolean photo, boolean organization, boolean phone, boolean email, String query, boolean expectIcon1Uri, String expectedIcon2, String expectedText1, String expectedText2)759     private void assertSearchSuggestion(boolean name, boolean photo, boolean organization,
760             boolean phone, boolean email, String query, boolean expectIcon1Uri, String expectedIcon2,
761             String expectedText1, String expectedText2) throws IOException {
762         ContentValues values = new ContentValues();
763 
764         if (name) {
765             values.put(People.NAME, "Deer Dough");
766         }
767 
768         final Uri personUri = mResolver.insert(People.CONTENT_URI, values);
769         long personId = ContentUris.parseId(personUri);
770 
771         People.addToMyContactsGroup(mResolver, personId);
772 
773         if (photo) {
774             values.clear();
775             byte[] photoData = loadTestPhoto();
776             values.put(Photos.DATA, photoData);
777             values.put(Photos.LOCAL_VERSION, "1");
778             values.put(Photos.EXISTS_ON_SERVER, 0);
779             Uri photoUri = Uri.withAppendedPath(personUri, Photos.CONTENT_DIRECTORY);
780             mResolver.update(photoUri, values, null, null);
781         }
782 
783         if (organization) {
784             values.clear();
785             values.put(Organizations.ISPRIMARY, 1);
786             values.put(Organizations.COMPANY, "Google");
787             values.put(Organizations.TYPE, Organizations.TYPE_WORK);
788             values.put(Organizations.PERSON_ID, personId);
789             mResolver.insert(Organizations.CONTENT_URI, values);
790         }
791 
792         if (email) {
793             values.clear();
794             values.put(ContactMethods.PERSON_ID, personId);
795             values.put(ContactMethods.KIND, Contacts.KIND_EMAIL);
796             values.put(ContactMethods.TYPE, ContactMethods.TYPE_HOME);
797             values.put(ContactMethods.DATA, "foo@acme.com");
798             values.put(ContactMethods.ISPRIMARY, 1);
799             mResolver.insert(ContactMethods.CONTENT_URI, values);
800 
801 
802             String protocol = ContactMethods
803                     .encodePredefinedImProtocol(ContactMethods.PROTOCOL_GOOGLE_TALK);
804             values.clear();
805             values.put(Presence.IM_PROTOCOL, protocol);
806             values.put(Presence.IM_HANDLE, "foo@acme.com");
807             values.put(Presence.IM_ACCOUNT, "foo");
808             values.put(Presence.PRESENCE_STATUS, Presence.OFFLINE);
809             values.put(Presence.PRESENCE_CUSTOM_STATUS, "Coding for Android");
810             mResolver.insert(Presence.CONTENT_URI, values);
811         }
812 
813         if (phone) {
814             values.clear();
815             values.put(Phones.PERSON_ID, personId);
816             values.put(Phones.TYPE, Phones.TYPE_HOME);
817             values.put(Phones.NUMBER, "1-800-4664-411");
818             values.put(Phones.ISPRIMARY, 1);
819             mResolver.insert(Phones.CONTENT_URI, values);
820         }
821 
822         Uri searchUri = new Uri.Builder().scheme("content").authority(Contacts.AUTHORITY)
823                 .appendPath(SearchManager.SUGGEST_URI_PATH_QUERY).appendPath(query).build();
824 
825         Cursor c = mResolver.query(searchUri, null, null, null, null);
826         assertEquals(1, c.getCount());
827         c.moveToFirst();
828         values.clear();
829 
830         String icon1 = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1));
831         if (expectIcon1Uri) {
832             assertTrue(icon1.startsWith("content:"));
833         } else {
834             assertEquals(String.valueOf(com.android.internal.R.drawable.ic_contact_picture), icon1);
835         }
836 
837         // SearchManager does not declare a constant for _id
838         values.put("_id", personId);
839         values.put(SearchManager.SUGGEST_COLUMN_ICON_2, expectedIcon2);
840         values.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, personId);
841         values.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, personId);
842         values.put(SearchManager.SUGGEST_COLUMN_TEXT_1, expectedText1);
843         values.put(SearchManager.SUGGEST_COLUMN_TEXT_2, expectedText2);
844         assertCursorValues(c, values);
845         c.close();
846 
847         // Cleanup
848         mResolver.delete(personUri, null, null);
849     }
850 
851     /**
852      * Capturing the search suggestion requirements in test cases as a reference.
853      */
testSearchSuggestionsByPhoneNumber()854     public void testSearchSuggestionsByPhoneNumber() throws Exception {
855         // We don't provide compatibility for search suggestions
856         return;
857     }
858 
testSettings()859     public void testSettings() throws Exception {
860         ContentValues values = new ContentValues();
861         values.put(Settings._SYNC_ACCOUNT, "foo");
862         values.put(Settings._SYNC_ACCOUNT_TYPE, "bar");
863         values.put(Settings.KEY, Settings.SYNC_EVERYTHING);
864         values.put(Settings.VALUE, 7);
865         mResolver.update(Settings.CONTENT_URI, values, null, null);
866 
867         assertStoredValue(Settings.CONTENT_URI, Settings._SYNC_ACCOUNT + "='foo' AND "
868                 + Settings.KEY + "='" + Settings.SYNC_EVERYTHING + "'", null, Settings.VALUE, "7");
869 
870         assertStoredValue(ContactsContract.Settings.CONTENT_URI,
871                 ContactsContract.Settings.ACCOUNT_NAME + "='foo'",
872                 null, ContactsContract.Settings.SHOULD_SYNC, "7");
873 
874         values.clear();
875         values.put(ContactsContract.Settings.SHOULD_SYNC, 8);
876         mResolver.update(ContactsContract.Settings.CONTENT_URI, values,
877                 ContactsContract.Settings.ACCOUNT_NAME + "='foo'", null);
878 
879         assertStoredValue(Settings.CONTENT_URI, Settings._SYNC_ACCOUNT + "='foo' AND "
880                 + Settings.KEY + "='" + Settings.SYNC_EVERYTHING + "'", null, Settings.VALUE, "8");
881     }
882 
insertPerson(String name, ContentValues values)883     private Uri insertPerson(String name, ContentValues values) {
884         values.put(People.NAME, name);
885         return mResolver.insert(People.CONTENT_URI, values);
886     }
887 
insertLegacyGroup(String name, ContentValues values)888     private Uri insertLegacyGroup(String name, ContentValues values) {
889         values.put(Groups.NAME, name);
890         return mResolver.insert(Groups.CONTENT_URI, values);
891     }
892 
insertLegacyGroupMembership(Uri groupUri, Uri personUri, ContentValues values)893     private Uri insertLegacyGroupMembership(Uri groupUri, Uri personUri, ContentValues values) {
894         long groupId = ContentUris.parseId(groupUri);
895         long personId = ContentUris.parseId(personUri);
896 
897         values.clear();
898         values.put(GroupMembership.GROUP_ID, groupId);
899         values.put(GroupMembership.PERSON_ID, personId);
900         Uri membershipUri = mResolver.insert(GroupMembership.CONTENT_URI, values);
901         return membershipUri;
902     }
903 
putContactValues(ContentValues values)904     private void putContactValues(ContentValues values) {
905         putContactValuesExceptName(values);
906         values.put(People.NAME, "Deer Dough");
907     }
908 
putContactValuesExceptName(ContentValues values)909     private void putContactValuesExceptName(ContentValues values) {
910         // Populating only unhidden columns
911         values.put(People.NOTES, "Cash Cow");
912         values.put(People.TIMES_CONTACTED, 3);
913         values.put(People.LAST_TIME_CONTACTED, 10);
914         values.put(People.CUSTOM_RINGTONE, "ringtone");
915         values.put(People.SEND_TO_VOICEMAIL, 1);
916         values.put(People.STARRED, 1);
917     }
918 
putContactValues2(ContentValues values)919     private void putContactValues2(ContentValues values) {
920         // Populating only unhidden columns
921         values.put(People.NAME, "John Doe");
922         values.put(People.PHONETIC_NAME, "jon dawe");
923         values.put(People.NOTES, "Poor Johnny");
924         values.put(People.TIMES_CONTACTED, 4);
925         values.put(People.LAST_TIME_CONTACTED, 11);
926         values.put(People.CUSTOM_RINGTONE, "rangtone");
927         values.put(People.SEND_TO_VOICEMAIL, 0);
928         values.put(People.STARRED, 0);
929     }
930 
assertFilteredContacts(String filter, String... expectedNames)931     private void assertFilteredContacts(String filter, String... expectedNames) {
932         Uri filterUri = Uri.withAppendedPath(People.CONTENT_FILTER_URI, filter);
933         Cursor c = mResolver.query(filterUri, null, null, null, null);
934         try {
935             assertEquals("Record count", expectedNames.length, c.getCount());
936             int column = c.getColumnIndex(People.NAME);
937             for (int i = 0; i < expectedNames.length; i++) {
938                 c.moveToNext();
939                 assertEquals(expectedNames[i], c.getString(column));
940             }
941         } finally {
942             c.close();
943         }
944     }
945 
assertPersonIdConstraint(Uri uri, String typeColumn, int defaultType)946     private void assertPersonIdConstraint(Uri uri, String typeColumn, int defaultType) {
947         ContentValues values = new ContentValues();
948         values.put(typeColumn, defaultType);
949         try {
950             mResolver.insert(uri, values);
951             fail("Inserted row without person ID");
952         } catch (Exception e) {
953             // Exception expected
954         }
955     }
956 
assertTypeAndLabelConstraints(Uri uri, String personIdColumn, long personId, String typeColumn, int defaultType, int otherType, String labelColumn)957     private void assertTypeAndLabelConstraints(Uri uri, String personIdColumn, long personId,
958             String typeColumn, int defaultType, int otherType, String labelColumn) {
959         ContentValues values = new ContentValues();
960         values.put(personIdColumn, personId);
961         values.put(labelColumn, "Foo");
962 
963         try {
964             mResolver.insert(uri, values);
965             fail("Inserted row with label without defining type");
966         } catch (Exception e) {
967             // Exception expected
968         }
969     }
970 
assertSelection(Uri uri, ContentValues values, String legacyTable, String idColumn, long id)971     protected void assertSelection(Uri uri, ContentValues values, String legacyTable,
972             String idColumn, long id) {
973         values.put(idColumn, id);
974         String qualified = legacyTable + "." + idColumn;
975         super.assertSelection(uri, values, qualified, id);
976     }
977 }
978