ContactsProvider2Test.java revision 627152453c692915ac79191acd1d2d2a4dd6fb0d
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
17package com.android.providers.contacts;
18
19import com.android.internal.util.ArrayUtils;
20import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns;
21
22import android.accounts.Account;
23import android.content.ContentUris;
24import android.content.ContentValues;
25import android.content.Entity;
26import android.content.EntityIterator;
27import android.database.Cursor;
28import android.net.Uri;
29import android.os.RemoteException;
30import android.provider.ContactsContract;
31import android.provider.LiveFolders;
32import android.provider.ContactsContract.AggregationExceptions;
33import android.provider.ContactsContract.Contacts;
34import android.provider.ContactsContract.Data;
35import android.provider.ContactsContract.Groups;
36import android.provider.ContactsContract.PhoneLookup;
37import android.provider.ContactsContract.RawContacts;
38import android.provider.ContactsContract.Settings;
39import android.provider.ContactsContract.StatusUpdates;
40import android.provider.ContactsContract.CommonDataKinds.Email;
41import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
42import android.provider.ContactsContract.CommonDataKinds.Im;
43import android.provider.ContactsContract.CommonDataKinds.Organization;
44import android.provider.ContactsContract.CommonDataKinds.Phone;
45import android.provider.ContactsContract.CommonDataKinds.Photo;
46import android.provider.ContactsContract.CommonDataKinds.StructuredName;
47import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
48import android.test.MoreAsserts;
49import android.test.suitebuilder.annotation.LargeTest;
50
51
52/**
53 * Unit tests for {@link ContactsProvider2}.
54 *
55 * Run the test like this:
56 * <code>
57 * adb shell am instrument -e class com.android.providers.contacts.ContactsProvider2Test -w \
58 *         com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
59 * </code>
60 */
61@LargeTest
62public class ContactsProvider2Test extends BaseContactsProvider2Test {
63
64    public void testRawContactsInsert() {
65        ContentValues values = new ContentValues();
66
67        values.put(RawContacts.ACCOUNT_NAME, "a");
68        values.put(RawContacts.ACCOUNT_TYPE, "b");
69        values.put(RawContacts.SOURCE_ID, "c");
70        values.put(RawContacts.VERSION, 42);
71        values.put(RawContacts.DIRTY, 1);
72        values.put(RawContacts.DELETED, 1);
73        values.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
74        values.put(RawContacts.CUSTOM_RINGTONE, "d");
75        values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
76        values.put(RawContacts.LAST_TIME_CONTACTED, 12345);
77        values.put(RawContacts.STARRED, 1);
78        values.put(RawContacts.SYNC1, "e");
79        values.put(RawContacts.SYNC2, "f");
80        values.put(RawContacts.SYNC3, "g");
81        values.put(RawContacts.SYNC4, "h");
82
83        Uri rowUri = mResolver.insert(RawContacts.CONTENT_URI, values);
84        long rawContactId = ContentUris.parseId(rowUri);
85
86        assertStoredValues(rowUri, values);
87        assertSelection(RawContacts.CONTENT_URI, values, RawContacts._ID, rawContactId);
88        assertNetworkNotified(true);
89    }
90
91    public void testDataInsert() {
92        long rawContactId = createRawContactWithName("John", "Doe");
93
94        ContentValues values = new ContentValues();
95        putDataValues(values, rawContactId);
96        Uri dataUri = mResolver.insert(Data.CONTENT_URI, values);
97        long dataId = ContentUris.parseId(dataUri);
98
99        long contactId = queryContactId(rawContactId);
100        values.put(RawContacts.CONTACT_ID, contactId);
101        assertStoredValues(dataUri, values);
102
103        assertSelection(Data.CONTENT_URI, values, Data._ID, dataId);
104
105        // Access the same data through the directory under RawContacts
106        Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
107        Uri rawContactDataUri =
108                Uri.withAppendedPath(rawContactUri, RawContacts.Data.CONTENT_DIRECTORY);
109        assertSelection(rawContactDataUri, values, Data._ID, dataId);
110
111        // Access the same data through the directory under Contacts
112        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
113        Uri contactDataUri = Uri.withAppendedPath(contactUri, Contacts.Data.CONTENT_DIRECTORY);
114        assertSelection(contactDataUri, values, Data._ID, dataId);
115        assertNetworkNotified(true);
116    }
117
118    public void testRawContactDataQuery() {
119        Account account1 = new Account("a", "b");
120        Account account2 = new Account("c", "d");
121        long rawContactId1 = createRawContact(account1);
122        Uri dataUri1 = insertStructuredName(rawContactId1, "John", "Doe");
123        long rawContactId2 = createRawContact(account2);
124        Uri dataUri2 = insertStructuredName(rawContactId2, "Jane", "Doe");
125
126        Uri uri1 = maybeAddAccountQueryParameters(dataUri1, account1);
127        Uri uri2 = maybeAddAccountQueryParameters(dataUri2, account2);
128        assertStoredValue(uri1, Data._ID, ContentUris.parseId(dataUri1)) ;
129        assertStoredValue(uri2, Data._ID, ContentUris.parseId(dataUri2)) ;
130    }
131
132    public void testPhonesQuery() {
133
134        ContentValues values = new ContentValues();
135        values.put(RawContacts.CUSTOM_RINGTONE, "d");
136        values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
137        values.put(RawContacts.LAST_TIME_CONTACTED, 12345);
138        values.put(RawContacts.TIMES_CONTACTED, 54321);
139        values.put(RawContacts.STARRED, 1);
140
141        Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
142        long rawContactId = ContentUris.parseId(rawContactUri);
143
144        insertStructuredName(rawContactId, "Meghan", "Knox");
145        Uri uri = insertPhoneNumber(rawContactId, "18004664411");
146        long phoneId = ContentUris.parseId(uri);
147
148
149        long contactId = queryContactId(rawContactId);
150        values.clear();
151        values.put(Data._ID, phoneId);
152        values.put(Data.RAW_CONTACT_ID, rawContactId);
153        values.put(RawContacts.CONTACT_ID, contactId);
154        values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
155        values.put(Phone.NUMBER, "18004664411");
156        values.put(Phone.TYPE, Phone.TYPE_HOME);
157        values.putNull(Phone.LABEL);
158        values.put(Contacts.DISPLAY_NAME, "Meghan Knox");
159        values.put(Contacts.CUSTOM_RINGTONE, "d");
160        values.put(Contacts.SEND_TO_VOICEMAIL, 1);
161        values.put(Contacts.LAST_TIME_CONTACTED, 12345);
162        values.put(Contacts.TIMES_CONTACTED, 54321);
163        values.put(Contacts.STARRED, 1);
164
165        assertStoredValues(ContentUris.withAppendedId(Phone.CONTENT_URI, phoneId), values);
166        assertSelection(Phone.CONTENT_URI, values, Data._ID, phoneId);
167    }
168
169    public void testPhonesFilterQuery() {
170        long rawContactId1 = createRawContactWithName("Hot", "Tamale");
171        insertPhoneNumber(rawContactId1, "18004664411");
172        insertPhoneNumber(rawContactId1, "1-800-466-4411");
173
174        long rawContactId2 = createRawContactWithName("Hot", "Tamale");
175        insertPhoneNumber(rawContactId2, "1-800-466-4411");
176
177        forceAggregation();
178
179        Uri filterUri1 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "tamale");
180        ContentValues values = new ContentValues();
181        values.put(Contacts.DISPLAY_NAME, "Hot Tamale");
182        values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
183        values.put(Phone.NUMBER, "1-800-466-4411");
184        values.put(Phone.TYPE, Phone.TYPE_HOME);
185        values.putNull(Phone.LABEL);
186        assertStoredValuesWithProjection(filterUri1, values);
187
188        Uri filterUri2 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "1-800-GOOG-411");
189        assertStoredValues(filterUri2, values);
190
191        Uri filterUri3 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "18004664");
192        assertStoredValues(filterUri3, values);
193
194        Uri filterUri4 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "encilada");
195        assertEquals(0, getCount(filterUri4, null, null));
196    }
197
198    public void testPhoneLookup() {
199        ContentValues values = new ContentValues();
200        values.put(RawContacts.CUSTOM_RINGTONE, "d");
201        values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
202
203        Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
204        long rawContactId = ContentUris.parseId(rawContactUri);
205
206        insertStructuredName(rawContactId, "Hot", "Tamale");
207        insertPhoneNumber(rawContactId, "18004664411");
208
209        Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411");
210
211        values.clear();
212        values.put(PhoneLookup._ID, queryContactId(rawContactId));
213        values.put(PhoneLookup.DISPLAY_NAME, "Hot Tamale");
214        values.put(PhoneLookup.NUMBER, "18004664411");
215        values.put(PhoneLookup.TYPE, Phone.TYPE_HOME);
216        values.putNull(PhoneLookup.LABEL);
217        values.put(PhoneLookup.CUSTOM_RINGTONE, "d");
218        values.put(PhoneLookup.SEND_TO_VOICEMAIL, 1);
219        assertStoredValues(lookupUri1, values);
220
221        // The strict comparation, adopted in Donut, does not allow the behavior like
222        // "8004664411 == 4664411", while the loose comparation, which had been used in Cupcake
223        // and reverted back into the default in Eclair, allows it. Hmm...
224        final boolean useStrictComparation =
225            mContext.getResources().getBoolean(
226                    com.android.internal.R.bool.config_use_strict_phone_number_comparation);
227        final int expectedResult = (useStrictComparation ? 0 : 1);
228
229        Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "4664411");
230        assertEquals(expectedResult, getCount(lookupUri2, null, null));
231    }
232
233    public void testPhoneUpdate() {
234        ContentValues values = new ContentValues();
235        Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
236        long rawContactId = ContentUris.parseId(rawContactUri);
237
238        insertStructuredName(rawContactId, "Hot", "Tamale");
239        Uri phoneUri = insertPhoneNumber(rawContactId, "18004664411");
240
241        Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411");
242        assertStoredValue(lookupUri1, PhoneLookup.DISPLAY_NAME, "Hot Tamale");
243
244        values.clear();
245        values.put(Phone.NUMBER, "18004664422");
246        mResolver.update(phoneUri, values, null, null);
247
248        Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664422");
249        assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale");
250
251        // Setting number to null will remove the phone lookup record
252        values.clear();
253        values.putNull(Phone.NUMBER);
254        mResolver.update(phoneUri, values, null, null);
255
256        assertEquals(0, getCount(lookupUri2, null, null));
257
258        // Let's restore that phone lookup record
259        values.clear();
260        values.put(Phone.NUMBER, "18004664422");
261        mResolver.update(phoneUri, values, null, null);
262        assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale");
263        assertNetworkNotified(true);
264    }
265
266    public void testEmailsQuery() {
267        ContentValues values = new ContentValues();
268        values.put(RawContacts.CUSTOM_RINGTONE, "d");
269        values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
270        values.put(RawContacts.LAST_TIME_CONTACTED, 12345);
271        values.put(RawContacts.TIMES_CONTACTED, 54321);
272        values.put(RawContacts.STARRED, 1);
273
274        Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
275        long rawContactId = ContentUris.parseId(rawContactUri);
276
277        insertStructuredName(rawContactId, "Meghan", "Knox");
278        Uri uri = insertEmail(rawContactId, "meghan@acme.com");
279        long emailId = ContentUris.parseId(uri);
280
281        long contactId = queryContactId(rawContactId);
282        values.clear();
283        values.put(Data._ID, emailId);
284        values.put(Data.RAW_CONTACT_ID, rawContactId);
285        values.put(RawContacts.CONTACT_ID, contactId);
286        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
287        values.put(Email.DATA, "meghan@acme.com");
288        values.put(Email.TYPE, Email.TYPE_HOME);
289        values.putNull(Email.LABEL);
290        values.put(Contacts.DISPLAY_NAME, "Meghan Knox");
291        values.put(Contacts.CUSTOM_RINGTONE, "d");
292        values.put(Contacts.SEND_TO_VOICEMAIL, 1);
293        values.put(Contacts.LAST_TIME_CONTACTED, 12345);
294        values.put(Contacts.TIMES_CONTACTED, 54321);
295        values.put(Contacts.STARRED, 1);
296
297        assertStoredValues(ContentUris.withAppendedId(Email.CONTENT_URI, emailId), values);
298        assertSelection(Email.CONTENT_URI, values, Data._ID, emailId);
299    }
300
301    public void testEmailsLookupQuery() {
302        long rawContactId = createRawContactWithName("Hot", "Tamale");
303        insertEmail(rawContactId, "tamale@acme.com");
304
305        Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "tamale@acme.com");
306        ContentValues values = new ContentValues();
307        values.put(Contacts.DISPLAY_NAME, "Hot Tamale");
308        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
309        values.put(Email.DATA, "tamale@acme.com");
310        values.put(Email.TYPE, Email.TYPE_HOME);
311        values.putNull(Email.LABEL);
312        assertStoredValues(filterUri1, values);
313
314        Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "encilada@acme.com");
315        assertEquals(0, getCount(filterUri2, null, null));
316    }
317
318    public void testEmailsFilterQuery() {
319        long rawContactId1 = createRawContactWithName("Hot", "Tamale");
320        insertEmail(rawContactId1, "tamale@acme.com");
321        insertEmail(rawContactId1, "tamale@acme.com");
322
323        long rawContactId2 = createRawContactWithName("Hot", "Tamale");
324        insertEmail(rawContactId2, "tamale@acme.com");
325        forceAggregation();
326
327        Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tam");
328        ContentValues values = new ContentValues();
329        values.put(Contacts.DISPLAY_NAME, "Hot Tamale");
330        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
331        values.put(Email.DATA, "tamale@acme.com");
332        values.put(Email.TYPE, Email.TYPE_HOME);
333        values.putNull(Email.LABEL);
334        assertStoredValuesWithProjection(filterUri1, values);
335
336        Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hot");
337        assertStoredValuesWithProjection(filterUri2, values);
338
339        Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hottamale");
340        assertStoredValuesWithProjection(filterUri3, values);
341
342        Uri filterUri4 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tamale@acme");
343        assertStoredValuesWithProjection(filterUri4, values);
344
345        Uri filterUri5 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "encilada");
346        assertEquals(0, getCount(filterUri5, null, null));
347    }
348
349    public void testPostalsQuery() {
350        long rawContactId = createRawContactWithName("Alice", "Nextore");
351        Uri dataUri = insertPostalAddress(rawContactId, "1600 Amphiteatre Ave, Mountain View");
352        long dataId = ContentUris.parseId(dataUri);
353
354        long contactId = queryContactId(rawContactId);
355        ContentValues values = new ContentValues();
356        values.put(Data._ID, dataId);
357        values.put(Data.RAW_CONTACT_ID, rawContactId);
358        values.put(RawContacts.CONTACT_ID, contactId);
359        values.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
360        values.put(StructuredPostal.FORMATTED_ADDRESS, "1600 Amphiteatre Ave, Mountain View");
361        values.put(Contacts.DISPLAY_NAME, "Alice Nextore");
362
363        assertStoredValues(ContentUris.withAppendedId(StructuredPostal.CONTENT_URI, dataId),
364                values);
365        assertSelection(StructuredPostal.CONTENT_URI, values, Data._ID, dataId);
366    }
367
368    public void testQueryContactData() {
369        ContentValues values = new ContentValues();
370        long contactId = createContact(values, "John", "Doe",
371                "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0);
372        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
373
374        assertStoredValues(contactUri, values);
375        assertSelection(Contacts.CONTENT_URI, values, Contacts._ID, contactId);
376    }
377
378    public void testQueryContactWithStatusUpdate() {
379        ContentValues values = new ContentValues();
380        long contactId = createContact(values, "John", "Doe",
381                "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0);
382        values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
383        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
384        assertStoredValuesWithProjection(contactUri, values);
385        assertSelectionWithProjection(Contacts.CONTENT_URI, values, Contacts._ID, contactId);
386    }
387
388    public void testQueryContactFilterData() {
389        ContentValues values = new ContentValues();
390        createContact(values, "Stu", "Goulash", "18004664411",
391                "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0);
392        values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
393        Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goulash");
394        assertStoredValuesWithProjection(filterUri1, values);
395
396        Uri filterUri2 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goolish");
397        assertEquals(0, getCount(filterUri2, null, null));
398    }
399
400    public void testQueryContactStrequent() {
401        ContentValues values1 = new ContentValues();
402        createContact(values1, "Noah", "Tever", "18004664411",
403                "a@acme.com", StatusUpdates.OFFLINE, 0, 0, 0);
404        ContentValues values2 = new ContentValues();
405        createContact(values2, "Sam", "Times", "18004664412",
406                "b@acme.com", StatusUpdates.INVISIBLE, 3, 0, 0);
407        ContentValues values3 = new ContentValues();
408        createContact(values3, "Lotta", "Calling", "18004664413",
409                "c@acme.com", StatusUpdates.AWAY, 5, 0, 0);
410        ContentValues values4 = new ContentValues();
411        createContact(values4, "Fay", "Veritt", "18004664414",
412                "d@acme.com", StatusUpdates.AVAILABLE, 0, 1, 0);
413
414        Cursor c = mResolver.query(Contacts.CONTENT_STREQUENT_URI, null, null, null,
415                Contacts._ID);
416        assertEquals(3, c.getCount());
417        c.moveToFirst();
418        assertCursorValues(c, values4);
419        c.moveToNext();
420        assertCursorValues(c, values3);
421        c.moveToNext();
422        assertCursorValues(c, values2);
423        c.close();
424
425        Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_STREQUENT_FILTER_URI, "fay");
426        c = mResolver.query(filterUri, null, null, null, Contacts._ID);
427        assertEquals(1, c.getCount());
428        c.moveToFirst();
429        assertCursorValues(c, values4);
430        c.close();
431    }
432
433    public void testQueryContactGroup() {
434        long groupId = createGroup(null, "testGroup", "Test Group");
435
436        ContentValues values1 = new ContentValues();
437        createContact(values1, "Best", "West", "18004664411",
438                "west@acme.com", StatusUpdates.OFFLINE, 0, 0, groupId);
439
440        ContentValues values2 = new ContentValues();
441        createContact(values2, "Rest", "East", "18004664422",
442                "east@acme.com", StatusUpdates.AVAILABLE, 0, 0, 0);
443
444        Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group");
445        Cursor c = mResolver.query(filterUri1, null, null, null, Contacts._ID);
446        assertEquals(1, c.getCount());
447        c.moveToFirst();
448        assertCursorValues(c, values1);
449        c.close();
450
451        Uri filterUri2 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group");
452        c = mResolver.query(filterUri2, null, Contacts.DISPLAY_NAME + "=?",
453                new String[] { "Best West" }, Contacts._ID);
454        assertEquals(1, c.getCount());
455        c.close();
456
457        Uri filterUri3 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Next Group");
458        c = mResolver.query(filterUri3, null, null, null, Contacts._ID);
459        assertEquals(0, c.getCount());
460        c.close();
461    }
462
463    public void testPhonesWithStatusUpdate() {
464
465        ContentValues values = new ContentValues();
466        Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
467        long rawContactId = ContentUris.parseId(rawContactUri);
468        insertStructuredName(rawContactId, "John", "Doe");
469        Uri photoUri = insertPhoto(rawContactId);
470        long photoId = ContentUris.parseId(photoUri);
471        values.put(Contacts.PHOTO_ID, photoId);
472        insertPhoneNumber(rawContactId, "18004664411");
473        insertPhoneNumber(rawContactId, "18004664412");
474        insertEmail(rawContactId, "goog411@acme.com");
475        insertEmail(rawContactId, "goog412@acme.com");
476
477        insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog411@acme.com",
478                StatusUpdates.INVISIBLE, "Bad");
479        insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog412@acme.com",
480                StatusUpdates.AVAILABLE, "Good");
481        long contactId = queryContactId(rawContactId);
482
483        Uri uri = Data.CONTENT_URI;
484
485        Cursor c = mResolver.query(uri, null, RawContacts.CONTACT_ID + "=" + contactId + " AND "
486                + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'", null, Phone.NUMBER);
487        assertEquals(2, c.getCount());
488
489        c.moveToFirst();
490
491        values.clear();
492        values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE);
493        values.put(Contacts.CONTACT_STATUS, "Bad");
494        values.put(Contacts.DISPLAY_NAME, "John Doe");
495        values.put(Phone.NUMBER, "18004664411");
496        values.putNull(Phone.LABEL);
497        values.put(RawContacts.CONTACT_ID, contactId);
498        assertCursorValues(c, values);
499
500        c.moveToNext();
501
502        values.clear();
503        values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE);
504        values.put(Contacts.CONTACT_STATUS, "Bad");
505        values.put(Contacts.DISPLAY_NAME, "John Doe");
506        values.put(Phone.NUMBER, "18004664412");
507        values.putNull(Phone.LABEL);
508        values.put(RawContacts.CONTACT_ID, contactId);
509        assertCursorValues(c, values);
510
511        c.close();
512    }
513
514    public void testGroupQuery() {
515        Account account1 = new Account("a", "b");
516        Account account2 = new Account("c", "d");
517        long groupId1 = createGroup(account1, "e", "f");
518        long groupId2 = createGroup(account2, "g", "h");
519        Uri uri1 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account1);
520        Uri uri2 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account2);
521        assertEquals(1, getCount(uri1, null, null));
522        assertEquals(1, getCount(uri2, null, null));
523        assertStoredValue(uri1, Groups._ID + "=" + groupId1, null, Groups._ID, groupId1) ;
524        assertStoredValue(uri2, Groups._ID + "=" + groupId2, null, Groups._ID, groupId2) ;
525    }
526
527    public void testGroupInsert() {
528        ContentValues values = new ContentValues();
529
530        values.put(Groups.ACCOUNT_NAME, "a");
531        values.put(Groups.ACCOUNT_TYPE, "b");
532        values.put(Groups.SOURCE_ID, "c");
533        values.put(Groups.VERSION, 42);
534        values.put(Groups.GROUP_VISIBLE, 1);
535        values.put(Groups.TITLE, "d");
536        values.put(Groups.TITLE_RES, 1234);
537        values.put(Groups.NOTES, "e");
538        values.put(Groups.RES_PACKAGE, "f");
539        values.put(Groups.SYSTEM_ID, "g");
540        values.put(Groups.DELETED, 1);
541        values.put(Groups.SYNC1, "h");
542        values.put(Groups.SYNC2, "i");
543        values.put(Groups.SYNC3, "j");
544        values.put(Groups.SYNC4, "k");
545
546        Uri rowUri = mResolver.insert(Groups.CONTENT_URI, values);
547
548        values.put(Groups.DIRTY, 1);
549        assertStoredValues(rowUri, values);
550    }
551
552    public void testSettingsQuery() {
553        Account account1 = new Account("a", "b");
554        Account account2 = new Account("c", "d");
555        createSettings(account1, "0", "0");
556        createSettings(account2, "1", "1");
557        Uri uri1 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account1);
558        Uri uri2 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account2);
559        assertEquals(1, getCount(uri1, null, null));
560        assertEquals(1, getCount(uri2, null, null));
561        assertStoredValue(uri1, Settings.SHOULD_SYNC, "0") ;
562        assertStoredValue(uri1, Settings.UNGROUPED_VISIBLE, "0") ;
563        assertStoredValue(uri2, Settings.SHOULD_SYNC, "1") ;
564        assertStoredValue(uri2, Settings.UNGROUPED_VISIBLE, "1") ;
565    }
566
567    public void testDisplayNameParsingWhenPartsUnspecified() {
568        long rawContactId = createRawContact();
569        ContentValues values = new ContentValues();
570        values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr.");
571        insertStructuredName(rawContactId, values);
572
573        assertStructuredName(rawContactId, "Mr", "John", "Kevin", "von Smith", "Jr");
574    }
575
576    public void testDisplayNameParsingWhenPartsAreNull() {
577        long rawContactId = createRawContact();
578        ContentValues values = new ContentValues();
579        values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr.");
580        values.putNull(StructuredName.GIVEN_NAME);
581        values.putNull(StructuredName.FAMILY_NAME);
582        insertStructuredName(rawContactId, values);
583        assertStructuredName(rawContactId, "Mr", "John", "Kevin", "von Smith", "Jr");
584    }
585
586    public void testDisplayNameParsingWhenPartsSpecified() {
587        long rawContactId = createRawContact();
588        ContentValues values = new ContentValues();
589        values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr.");
590        values.put(StructuredName.FAMILY_NAME, "Johnson");
591        insertStructuredName(rawContactId, values);
592
593        assertStructuredName(rawContactId, null, null, null, "Johnson", null);
594    }
595
596    public void testDisplayNameUpdate() {
597        long rawContactId1 = createRawContact();
598        insertEmail(rawContactId1, "potato@acme.com", true);
599
600        long rawContactId2 = createRawContact();
601        insertPhoneNumber(rawContactId2, "123456789", true);
602
603        setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
604                rawContactId1, rawContactId2);
605
606        assertAggregated(rawContactId1, rawContactId2, "123456789");
607
608        insertStructuredName(rawContactId2, "Potato", "Head");
609
610        assertAggregated(rawContactId1, rawContactId2, "Potato Head");
611        assertNetworkNotified(true);
612    }
613
614    public void testDisplayNameFromData() {
615        long rawContactId = createRawContact();
616        long contactId = queryContactId(rawContactId);
617        ContentValues values = new ContentValues();
618
619        Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
620
621        assertStoredValue(uri, Contacts.DISPLAY_NAME, null);
622        insertEmail(rawContactId, "mike@monstersinc.com");
623        assertStoredValue(uri, Contacts.DISPLAY_NAME, "mike@monstersinc.com");
624
625        insertEmail(rawContactId, "james@monstersinc.com", true);
626        assertStoredValue(uri, Contacts.DISPLAY_NAME, "james@monstersinc.com");
627
628        insertPhoneNumber(rawContactId, "1-800-466-4411");
629        assertStoredValue(uri, Contacts.DISPLAY_NAME, "1-800-466-4411");
630
631        // If there is title without company, the title is display name.
632        values.clear();
633        values.put(Organization.TITLE, "Protagonist");
634        Uri organizationUri = insertOrganization(rawContactId, values);
635        assertStoredValue(uri, Contacts.DISPLAY_NAME, "Protagonist");
636
637        // If there are title and company, the company is display name.
638        values.clear();
639        values.put(Organization.COMPANY, "Monsters Inc");
640        mResolver.update(organizationUri, values, null, null);
641        assertStoredValue(uri, Contacts.DISPLAY_NAME, "Monsters Inc");
642
643        // If there is nickname, that is display name.
644        insertNickname(rawContactId, "Sully");
645        assertStoredValue(uri, Contacts.DISPLAY_NAME, "Sully");
646
647        // If there is structured name, that is display name.
648        values.clear();
649        values.put(StructuredName.GIVEN_NAME, "James");
650        values.put(StructuredName.MIDDLE_NAME, "P.");
651        values.put(StructuredName.FAMILY_NAME, "Sullivan");
652        insertStructuredName(rawContactId, values);
653        assertStoredValue(uri, Contacts.DISPLAY_NAME, "James Sullivan");
654    }
655
656    public void testDisplayNameUpdateFromStructuredNameUpdate() {
657        long rawContactId = createRawContact();
658        Uri nameUri = insertStructuredName(rawContactId, "Slinky", "Dog");
659
660        long contactId = queryContactId(rawContactId);
661
662        Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
663        assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky Dog");
664
665        ContentValues values = new ContentValues();
666        values.putNull(StructuredName.FAMILY_NAME);
667
668        mResolver.update(nameUri, values, null, null);
669        assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky");
670
671        values.putNull(StructuredName.GIVEN_NAME);
672
673        mResolver.update(nameUri, values, null, null);
674        assertStoredValue(uri, Contacts.DISPLAY_NAME, null);
675
676        values.put(StructuredName.FAMILY_NAME, "Dog");
677        mResolver.update(nameUri, values, null, null);
678
679        assertStoredValue(uri, Contacts.DISPLAY_NAME, "Dog");
680    }
681
682    public void testSendToVoicemailDefault() {
683        long rawContactId = createRawContactWithName();
684        long contactId = queryContactId(rawContactId);
685
686        Cursor c = queryContact(contactId);
687        assertTrue(c.moveToNext());
688        int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL));
689        assertEquals(0, sendToVoicemail);
690        c.close();
691    }
692
693    public void testSetSendToVoicemailAndRingtone() {
694        long rawContactId = createRawContactWithName();
695        long contactId = queryContactId(rawContactId);
696
697        updateSendToVoicemailAndRingtone(contactId, true, "foo");
698        assertSendToVoicemailAndRingtone(contactId, true, "foo");
699        assertNetworkNotified(false);
700
701        updateSendToVoicemailAndRingtoneWithSelection(contactId, false, "bar");
702        assertSendToVoicemailAndRingtone(contactId, false, "bar");
703        assertNetworkNotified(false);
704    }
705
706    public void testSendToVoicemailAndRingtoneAfterAggregation() {
707        long rawContactId1 = createRawContactWithName("a", "b");
708        long contactId1 = queryContactId(rawContactId1);
709        updateSendToVoicemailAndRingtone(contactId1, true, "foo");
710
711        long rawContactId2 = createRawContactWithName("c", "d");
712        long contactId2 = queryContactId(rawContactId2);
713        updateSendToVoicemailAndRingtone(contactId2, true, "bar");
714
715        // Aggregate them
716        setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
717                rawContactId1, rawContactId2);
718
719        // Both contacts had "send to VM", the contact now has the same value
720        assertSendToVoicemailAndRingtone(contactId1, true, "foo,bar"); // Either foo or bar
721    }
722
723    public void testDoNotSendToVoicemailAfterAggregation() {
724        long rawContactId1 = createRawContactWithName("e", "f");
725        long contactId1 = queryContactId(rawContactId1);
726        updateSendToVoicemailAndRingtone(contactId1, true, null);
727
728        long rawContactId2 = createRawContactWithName("g", "h");
729        long contactId2 = queryContactId(rawContactId2);
730        updateSendToVoicemailAndRingtone(contactId2, false, null);
731
732        // Aggregate them
733        setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
734                rawContactId1, rawContactId2);
735
736        // Since one of the contacts had "don't send to VM" that setting wins for the aggregate
737        assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), false, null);
738    }
739
740    public void testSetSendToVoicemailAndRingtonePreservedAfterJoinAndSplit() {
741        long rawContactId1 = createRawContactWithName("i", "j");
742        long contactId1 = queryContactId(rawContactId1);
743        updateSendToVoicemailAndRingtone(contactId1, true, "foo");
744
745        long rawContactId2 = createRawContactWithName("k", "l");
746        long contactId2 = queryContactId(rawContactId2);
747        updateSendToVoicemailAndRingtone(contactId2, false, "bar");
748
749        // Aggregate them
750        setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
751                rawContactId1, rawContactId2);
752
753        // Split them
754        setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
755                rawContactId1, rawContactId2);
756
757        assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), true, "foo");
758        assertSendToVoicemailAndRingtone(queryContactId(rawContactId2), false, "bar");
759    }
760
761    public void testStatusUpdateInsert() {
762        long rawContactId = createRawContact();
763        Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
764        long dataId = ContentUris.parseId(imUri);
765
766        ContentValues values = new ContentValues();
767        values.put(StatusUpdates.DATA_ID, dataId);
768        values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM);
769        values.putNull(StatusUpdates.CUSTOM_PROTOCOL);
770        values.put(StatusUpdates.IM_HANDLE, "aim");
771        values.put(StatusUpdates.PRESENCE, StatusUpdates.INVISIBLE);
772        values.put(StatusUpdates.STATUS, "Hiding");
773        values.put(StatusUpdates.STATUS_TIMESTAMP, 100);
774        values.put(StatusUpdates.STATUS_RES_PACKAGE, "a.b.c");
775        values.put(StatusUpdates.STATUS_ICON, 1234);
776        values.put(StatusUpdates.STATUS_LABEL, 2345);
777
778        Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values);
779
780        assertStoredValues(resultUri, values);
781
782        long contactId = queryContactId(rawContactId);
783        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
784
785        values.clear();
786        values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
787        values.put(Contacts.CONTACT_STATUS, "Hiding");
788        values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100);
789        values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "a.b.c");
790        values.put(Contacts.CONTACT_STATUS_ICON, 1234);
791        values.put(Contacts.CONTACT_STATUS_LABEL, 2345);
792
793        assertStoredValues(contactUri, values);
794
795        values.clear();
796        values.put(StatusUpdates.DATA_ID, dataId);
797        values.put(StatusUpdates.STATUS, "Cloaked");
798        values.put(StatusUpdates.STATUS_TIMESTAMP, 200);
799        values.put(StatusUpdates.STATUS_RES_PACKAGE, "d.e.f");
800        values.put(StatusUpdates.STATUS_ICON, 4321);
801        values.put(StatusUpdates.STATUS_LABEL, 5432);
802        mResolver.insert(StatusUpdates.CONTENT_URI, values);
803
804        values.clear();
805        values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
806        values.put(Contacts.CONTACT_STATUS, "Cloaked");
807        values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 200);
808        values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "d.e.f");
809        values.put(Contacts.CONTACT_STATUS_ICON, 4321);
810        values.put(Contacts.CONTACT_STATUS_LABEL, 5432);
811        assertStoredValues(contactUri, values);
812    }
813
814    public void testStatusUpdateInferAttribution() {
815        long rawContactId = createRawContact();
816        Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
817        long dataId = ContentUris.parseId(imUri);
818
819        ContentValues values = new ContentValues();
820        values.put(StatusUpdates.DATA_ID, dataId);
821        values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM);
822        values.put(StatusUpdates.IM_HANDLE, "aim");
823        values.put(StatusUpdates.STATUS, "Hiding");
824
825        Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values);
826
827        values.clear();
828        values.put(StatusUpdates.DATA_ID, dataId);
829        values.put(StatusUpdates.STATUS_LABEL, com.android.internal.R.string.imProtocolAim);
830        values.put(StatusUpdates.STATUS, "Hiding");
831
832        assertStoredValues(resultUri, values);
833    }
834
835    public void testStatusUpdateMatchingImOrEmail() {
836        long rawContactId = createRawContact();
837        insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
838        insertImHandle(rawContactId, Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im");
839        insertEmail(rawContactId, "m@acme.com");
840
841        // Match on IM (standard)
842        insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available");
843
844        // Match on IM (custom)
845        insertStatusUpdate(Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im", StatusUpdates.IDLE, "Idle");
846
847        // Match on Email
848        insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "m@acme.com", StatusUpdates.AWAY, "Away");
849
850        // No match
851        insertStatusUpdate(Im.PROTOCOL_ICQ, null, "12345", StatusUpdates.DO_NOT_DISTURB, "Go away");
852
853        Cursor c = mResolver.query(StatusUpdates.CONTENT_URI, new String[] {
854                StatusUpdates.DATA_ID, StatusUpdates.PROTOCOL, StatusUpdates.CUSTOM_PROTOCOL,
855                StatusUpdates.PRESENCE, StatusUpdates.STATUS},
856                PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null, StatusUpdates.DATA_ID);
857        assertTrue(c.moveToNext());
858        assertStatusUpdate(c, Im.PROTOCOL_AIM, null, StatusUpdates.AVAILABLE, "Available");
859        assertTrue(c.moveToNext());
860        assertStatusUpdate(c, Im.PROTOCOL_CUSTOM, "my_im_proto", StatusUpdates.IDLE, "Idle");
861        assertTrue(c.moveToNext());
862        assertStatusUpdate(c, Im.PROTOCOL_GOOGLE_TALK, null, StatusUpdates.AWAY, "Away");
863        assertFalse(c.moveToNext());
864        c.close();
865
866        long contactId = queryContactId(rawContactId);
867        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
868
869        ContentValues values = new ContentValues();
870        values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE);
871        values.put(Contacts.CONTACT_STATUS, "Available");
872        assertStoredValuesWithProjection(contactUri, values);
873    }
874
875    public void testStatusUpdateUpdateAndDelete() {
876        long rawContactId = createRawContact();
877        insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
878
879        long contactId = queryContactId(rawContactId);
880        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
881
882        ContentValues values = new ContentValues();
883        values.putNull(Contacts.CONTACT_PRESENCE);
884        values.putNull(Contacts.CONTACT_STATUS);
885        assertStoredValuesWithProjection(contactUri, values);
886
887        insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AWAY, "BUSY");
888        insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.DO_NOT_DISTURB, "GO AWAY");
889        Uri statusUri =
890            insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available");
891        long statusId = ContentUris.parseId(statusUri);
892
893        values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE);
894        values.put(Contacts.CONTACT_STATUS, "Available");
895        assertStoredValuesWithProjection(contactUri, values);
896
897        mResolver.delete(StatusUpdates.CONTENT_URI, StatusUpdates.DATA_ID + "=" + statusId, null);
898        values.putNull(Contacts.CONTACT_PRESENCE);
899
900        // Latest custom status update stays on the phone
901        values.put(Contacts.CONTACT_STATUS, "Available");
902        assertStoredValuesWithProjection(contactUri, values);
903    }
904
905    public void testStatusUpdateWithTimestamp() {
906        long rawContactId = createRawContact();
907        insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim");
908        insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk");
909
910        long contactId = queryContactId(rawContactId);
911        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
912        insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Offline", 80);
913        insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Available", 100);
914        insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", 0, "Busy", 90);
915
916        // Should return the latest status
917        ContentValues values = new ContentValues();
918        values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100);
919        values.put(Contacts.CONTACT_STATUS, "Available");
920        assertStoredValuesWithProjection(contactUri, values);
921    }
922
923    private void assertStatusUpdate(Cursor c, int protocol, String customProtocol, int presence,
924            String status) {
925        ContentValues values = new ContentValues();
926        values.put(StatusUpdates.PROTOCOL, protocol);
927        values.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol);
928        values.put(StatusUpdates.PRESENCE_STATUS, presence);
929        values.put(StatusUpdates.STATUS, status);
930        assertCursorValues(c, values);
931    }
932
933    public void testSingleStatusUpdateRowPerContact() {
934        int protocol1 = Im.PROTOCOL_GOOGLE_TALK;
935        String handle1 = "test@gmail.com";
936
937        long rawContactId1 = createRawContact();
938        insertImHandle(rawContactId1, protocol1, null, handle1);
939
940        insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AVAILABLE, "Green");
941        insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AWAY, "Yellow");
942        insertStatusUpdate(protocol1, null, handle1, StatusUpdates.INVISIBLE, "Red");
943
944        Cursor c = queryContact(queryContactId(rawContactId1),
945                new String[] {Contacts.CONTACT_PRESENCE, Contacts.CONTACT_STATUS});
946        assertEquals(1, c.getCount());
947
948        c.moveToFirst();
949        assertEquals(StatusUpdates.INVISIBLE, c.getInt(0));
950        assertEquals("Red", c.getString(1));
951    }
952
953    private void updateSendToVoicemailAndRingtone(long contactId, boolean sendToVoicemail,
954            String ringtone) {
955        ContentValues values = new ContentValues();
956        values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail);
957        if (ringtone != null) {
958            values.put(Contacts.CUSTOM_RINGTONE, ringtone);
959        }
960
961        final Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
962        int count = mResolver.update(uri, values, null, null);
963        assertEquals(1, count);
964    }
965
966    private void updateSendToVoicemailAndRingtoneWithSelection(long contactId,
967            boolean sendToVoicemail, String ringtone) {
968        ContentValues values = new ContentValues();
969        values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail);
970        if (ringtone != null) {
971            values.put(Contacts.CUSTOM_RINGTONE, ringtone);
972        }
973
974        int count = mResolver.update(Contacts.CONTENT_URI, values, Contacts._ID + "=" + contactId,
975                null);
976        assertEquals(1, count);
977    }
978
979    private void assertSendToVoicemailAndRingtone(long contactId, boolean expectedSendToVoicemail,
980            String expectedRingtone) {
981        Cursor c = queryContact(contactId);
982        assertTrue(c.moveToNext());
983        int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL));
984        assertEquals(expectedSendToVoicemail ? 1 : 0, sendToVoicemail);
985        String ringtone = c.getString(c.getColumnIndex(Contacts.CUSTOM_RINGTONE));
986        if (expectedRingtone == null) {
987            assertNull(ringtone);
988        } else {
989            assertTrue(ArrayUtils.contains(expectedRingtone.split(","), ringtone));
990        }
991        c.close();
992    }
993
994    public void testGroupCreationAfterMembershipInsert() {
995        long rawContactId1 = createRawContact(mAccount);
996        Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1");
997
998        long groupId = assertSingleGroup(NO_LONG, mAccount, "gsid1", null);
999        assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri),
1000                rawContactId1, groupId, "gsid1");
1001    }
1002
1003    public void testGroupReuseAfterMembershipInsert() {
1004        long rawContactId1 = createRawContact(mAccount);
1005        long groupId1 = createGroup(mAccount, "gsid1", "title1");
1006        Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1");
1007
1008        assertSingleGroup(groupId1, mAccount, "gsid1", "title1");
1009        assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri),
1010                rawContactId1, groupId1, "gsid1");
1011    }
1012
1013    public void testGroupInsertFailureOnGroupIdConflict() {
1014        long rawContactId1 = createRawContact(mAccount);
1015        long groupId1 = createGroup(mAccount, "gsid1", "title1");
1016
1017        ContentValues values = new ContentValues();
1018        values.put(GroupMembership.RAW_CONTACT_ID, rawContactId1);
1019        values.put(GroupMembership.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
1020        values.put(GroupMembership.GROUP_SOURCE_ID, "gsid1");
1021        values.put(GroupMembership.GROUP_ROW_ID, groupId1);
1022        try {
1023            mResolver.insert(Data.CONTENT_URI, values);
1024            fail("the insert was expected to fail, but it succeeded");
1025        } catch (IllegalArgumentException e) {
1026            // this was expected
1027        }
1028    }
1029
1030    public void testContactVisibilityUpdateOnMembershipChange() {
1031        long rawContactId = createRawContact(mAccount);
1032        assertVisibility(rawContactId, "0");
1033
1034        long visibleGroupId = createGroup(mAccount, "123", "Visible", 1);
1035        long invisibleGroupId = createGroup(mAccount, "567", "Invisible", 0);
1036
1037        Uri membership1 = insertGroupMembership(rawContactId, visibleGroupId);
1038        assertVisibility(rawContactId, "1");
1039
1040        Uri membership2 = insertGroupMembership(rawContactId, invisibleGroupId);
1041        assertVisibility(rawContactId, "1");
1042
1043        mResolver.delete(membership1, null, null);
1044        assertVisibility(rawContactId, "0");
1045
1046        ContentValues values = new ContentValues();
1047        values.put(GroupMembership.GROUP_ROW_ID, visibleGroupId);
1048
1049        mResolver.update(membership2, values, null, null);
1050        assertVisibility(rawContactId, "1");
1051    }
1052
1053    private void assertVisibility(long rawContactId, String expectedValue) {
1054        assertStoredValue(Contacts.CONTENT_URI, Contacts._ID + "=" + queryContactId(rawContactId),
1055                null, Contacts.IN_VISIBLE_GROUP, expectedValue);
1056    }
1057
1058    public void testContentEntityIterator() throws RemoteException {
1059        // create multiple contacts and check that the selected ones are returned
1060        long id;
1061
1062        long groupId1 = createGroup(mAccount, "gsid1", "title1");
1063        long groupId2 = createGroup(mAccount, "gsid2", "title2");
1064
1065        id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c0");
1066        insertGroupMembership(id, "gsid1");
1067        insertEmail(id, "c0@email.com");
1068        insertPhoneNumber(id, "5551212c0");
1069
1070        long c1 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c1");
1071        Uri id_1_0 = insertGroupMembership(id, "gsid1");
1072        Uri id_1_1 = insertGroupMembership(id, "gsid2");
1073        Uri id_1_2 = insertEmail(id, "c1@email.com");
1074        Uri id_1_3 = insertPhoneNumber(id, "5551212c1");
1075
1076        long c2 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c2");
1077        Uri id_2_0 = insertGroupMembership(id, "gsid1");
1078        Uri id_2_1 = insertEmail(id, "c2@email.com");
1079        Uri id_2_2 = insertPhoneNumber(id, "5551212c2");
1080
1081        long c3 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c3");
1082        Uri id_3_0 = insertGroupMembership(id, groupId2);
1083        Uri id_3_1 = insertEmail(id, "c3@email.com");
1084        Uri id_3_2 = insertPhoneNumber(id, "5551212c3");
1085
1086        EntityIterator iterator = mResolver.queryEntities(
1087                maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, mAccount),
1088                RawContacts.SOURCE_ID + " in ('c1', 'c2', 'c3')", null, null);
1089        Entity entity;
1090        ContentValues[] subValues;
1091        entity = iterator.next();
1092        assertEquals(c1, (long) entity.getEntityValues().getAsLong(RawContacts._ID));
1093        subValues = asSortedContentValuesArray(entity.getSubValues());
1094        assertEquals(4, subValues.length);
1095        assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE,
1096                Data._ID, id_1_0,
1097                GroupMembership.GROUP_ROW_ID, groupId1,
1098                GroupMembership.GROUP_SOURCE_ID, "gsid1");
1099        assertDataRow(subValues[1], GroupMembership.CONTENT_ITEM_TYPE,
1100                Data._ID, id_1_1,
1101                GroupMembership.GROUP_ROW_ID, groupId2,
1102                GroupMembership.GROUP_SOURCE_ID, "gsid2");
1103        assertDataRow(subValues[2], Email.CONTENT_ITEM_TYPE,
1104                Data._ID, id_1_2,
1105                Email.DATA, "c1@email.com");
1106        assertDataRow(subValues[3], Phone.CONTENT_ITEM_TYPE,
1107                Data._ID, id_1_3,
1108                Email.DATA, "5551212c1");
1109
1110        entity = iterator.next();
1111        assertEquals(c2, (long) entity.getEntityValues().getAsLong(RawContacts._ID));
1112        subValues = asSortedContentValuesArray(entity.getSubValues());
1113        assertEquals(3, subValues.length);
1114        assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE,
1115                Data._ID, id_2_0,
1116                GroupMembership.GROUP_ROW_ID, groupId1,
1117                GroupMembership.GROUP_SOURCE_ID, "gsid1");
1118        assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE,
1119                Data._ID, id_2_1,
1120                Email.DATA, "c2@email.com");
1121        assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE,
1122                Data._ID, id_2_2,
1123                Email.DATA, "5551212c2");
1124
1125        entity = iterator.next();
1126        assertEquals(c3, (long) entity.getEntityValues().getAsLong(RawContacts._ID));
1127        subValues = asSortedContentValuesArray(entity.getSubValues());
1128        assertEquals(3, subValues.length);
1129        assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE,
1130                Data._ID, id_3_0,
1131                GroupMembership.GROUP_ROW_ID, groupId2,
1132                GroupMembership.GROUP_SOURCE_ID, "gsid2");
1133        assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE,
1134                Data._ID, id_3_1,
1135                Email.DATA, "c3@email.com");
1136        assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE,
1137                Data._ID, id_3_2,
1138                Email.DATA, "5551212c3");
1139
1140        assertFalse(iterator.hasNext());
1141        iterator.close();
1142    }
1143
1144    public void testDataCreateUpdateDeleteByMimeType() throws Exception {
1145        long rawContactId = createRawContact();
1146
1147        ContentValues values = new ContentValues();
1148        values.put(Data.RAW_CONTACT_ID, rawContactId);
1149        values.put(Data.MIMETYPE, "testmimetype");
1150        values.put(Data.RES_PACKAGE, "oldpackage");
1151        values.put(Data.IS_PRIMARY, 1);
1152        values.put(Data.IS_SUPER_PRIMARY, 1);
1153        values.put(Data.DATA1, "old1");
1154        values.put(Data.DATA2, "old2");
1155        values.put(Data.DATA3, "old3");
1156        values.put(Data.DATA4, "old4");
1157        values.put(Data.DATA5, "old5");
1158        values.put(Data.DATA6, "old6");
1159        values.put(Data.DATA7, "old7");
1160        values.put(Data.DATA8, "old8");
1161        values.put(Data.DATA9, "old9");
1162        values.put(Data.DATA10, "old10");
1163        values.put(Data.DATA11, "old11");
1164        values.put(Data.DATA12, "old12");
1165        values.put(Data.DATA13, "old13");
1166        values.put(Data.DATA14, "old14");
1167        values.put(Data.DATA15, "old15");
1168        Uri uri = mResolver.insert(Data.CONTENT_URI, values);
1169        assertStoredValues(uri, values);
1170        assertNetworkNotified(true);
1171
1172        values.clear();
1173        values.put(Data.RES_PACKAGE, "newpackage");
1174        values.put(Data.IS_PRIMARY, 0);
1175        values.put(Data.IS_SUPER_PRIMARY, 0);
1176        values.put(Data.DATA1, "new1");
1177        values.put(Data.DATA2, "new2");
1178        values.put(Data.DATA3, "new3");
1179        values.put(Data.DATA4, "new4");
1180        values.put(Data.DATA5, "new5");
1181        values.put(Data.DATA6, "new6");
1182        values.put(Data.DATA7, "new7");
1183        values.put(Data.DATA8, "new8");
1184        values.put(Data.DATA9, "new9");
1185        values.put(Data.DATA10, "new10");
1186        values.put(Data.DATA11, "new11");
1187        values.put(Data.DATA12, "new12");
1188        values.put(Data.DATA13, "new13");
1189        values.put(Data.DATA14, "new14");
1190        values.put(Data.DATA15, "new15");
1191        mResolver.update(Data.CONTENT_URI, values, Data.RAW_CONTACT_ID + "=" + rawContactId +
1192                " AND " + Data.MIMETYPE + "='testmimetype'", null);
1193        assertNetworkNotified(true);
1194
1195        // Should not be able to change IS_PRIMARY and IS_SUPER_PRIMARY by the above update
1196        values.put(Data.IS_PRIMARY, 1);
1197        values.put(Data.IS_SUPER_PRIMARY, 1);
1198        assertStoredValues(uri, values);
1199
1200        int count = mResolver.delete(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId
1201                + " AND " + Data.MIMETYPE + "='testmimetype'", null);
1202        assertEquals(1, count);
1203        assertEquals(0, getCount(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId
1204                        + " AND " + Data.MIMETYPE + "='testmimetype'", null));
1205        assertNetworkNotified(true);
1206    }
1207
1208    public void testRawContactQuery() {
1209        Account account1 = new Account("a", "b");
1210        Account account2 = new Account("c", "d");
1211        long rawContactId1 = createRawContact(account1);
1212        long rawContactId2 = createRawContact(account2);
1213
1214        Uri uri1 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account1);
1215        Uri uri2 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account2);
1216        assertEquals(1, getCount(uri1, null, null));
1217        assertEquals(1, getCount(uri2, null, null));
1218        assertStoredValue(uri1, RawContacts._ID, rawContactId1) ;
1219        assertStoredValue(uri2, RawContacts._ID, rawContactId2) ;
1220
1221        Uri rowUri1 = ContentUris.withAppendedId(uri1, rawContactId1);
1222        Uri rowUri2 = ContentUris.withAppendedId(uri2, rawContactId2);
1223        assertStoredValue(rowUri1, RawContacts._ID, rawContactId1) ;
1224        assertStoredValue(rowUri2, RawContacts._ID, rawContactId2) ;
1225    }
1226
1227    public void testRawContactDeletion() {
1228        long rawContactId = createRawContact();
1229        Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
1230
1231        insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com");
1232        insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com",
1233                StatusUpdates.AVAILABLE, null);
1234        long contactId = queryContactId(rawContactId);
1235
1236        assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY),
1237                null, null));
1238        assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "="
1239                + rawContactId, null));
1240
1241        mResolver.delete(uri, null, null);
1242
1243        assertStoredValue(uri, RawContacts.DELETED, "1");
1244        assertNetworkNotified(true);
1245
1246        Uri permanentDeletionUri = uri.buildUpon().appendQueryParameter(
1247                ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();
1248        mResolver.delete(permanentDeletionUri, null, null);
1249        assertEquals(0, getCount(uri, null, null));
1250        assertEquals(0, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY),
1251                null, null));
1252        assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "="
1253                + rawContactId, null));
1254        assertEquals(0, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null));
1255        assertNetworkNotified(false);
1256    }
1257
1258    public void testRawContactDeletionKeepingAggregateContact() {
1259        long rawContactId1 = createRawContactWithName();
1260        long rawContactId2 = createRawContactWithName();
1261
1262        // Same name - should be aggregated
1263        assertAggregated(rawContactId1, rawContactId2);
1264
1265        long contactId = queryContactId(rawContactId1);
1266
1267        Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1);
1268        Uri permanentDeletionUri = uri.buildUpon().appendQueryParameter(
1269                ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();
1270        mResolver.delete(permanentDeletionUri, null, null);
1271        assertEquals(0, getCount(uri, null, null));
1272        assertEquals(1, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null));
1273    }
1274
1275    public void testRawContactDeletionWithAccounts() {
1276        long rawContactId = createRawContact(mAccount);
1277        Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
1278
1279        insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com");
1280        insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com",
1281                StatusUpdates.AVAILABLE, null);
1282        assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY),
1283                null, null));
1284        assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "="
1285                + rawContactId, null));
1286
1287        // Do not delete if we are deleting with wrong account.
1288        Uri deleteWithWrongAccountUri =
1289            RawContacts.CONTENT_URI.buildUpon()
1290                .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccountTwo.name)
1291                .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccountTwo.type)
1292                .build();
1293        mResolver.delete(deleteWithWrongAccountUri, null, null);
1294
1295        assertStoredValue(uri, RawContacts.DELETED, "0");
1296
1297        // Delete if we are deleting with correct account.
1298        Uri deleteWithCorrectAccountUri =
1299            RawContacts.CONTENT_URI.buildUpon()
1300                .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccount.name)
1301                .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccount.type)
1302                .build();
1303        mResolver.delete(deleteWithCorrectAccountUri, null, null);
1304
1305        assertStoredValue(uri, RawContacts.DELETED, "1");
1306    }
1307
1308    public void testAccountsUpdated() {
1309        long rawContactId1 = createRawContact(mAccount);
1310        insertEmail(rawContactId1, "account1@email.com");
1311        long rawContactId2 = createRawContact(mAccountTwo);
1312        insertEmail(rawContactId2, "account2@email.com");
1313        insertImHandle(rawContactId2, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com");
1314        insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com",
1315                StatusUpdates.AVAILABLE, null);
1316
1317        // This is to ensure we do not delete contacts with null, null (account name, type)
1318        // accidentally.
1319        long rawContactId3 = createRawContactWithName("James", "Sullivan");
1320        insertPhoneNumber(rawContactId3, "5234567890");
1321        Uri rawContact3 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId3);
1322
1323        ContactsProvider2 cp = (ContactsProvider2) getProvider();
1324
1325        Account accountRemaining = new Account("account1", "account type1");
1326        cp.onAccountsUpdated(new Account[]{accountRemaining});
1327        assertEquals(2, getCount(RawContacts.CONTENT_URI, null, null));
1328        assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "="
1329                + rawContactId2, null));
1330        assertStoredValue(rawContact3, RawContacts.ACCOUNT_NAME, "account1");
1331        assertStoredValue(rawContact3, RawContacts.ACCOUNT_TYPE, "account type1");
1332    }
1333
1334    public void testContactDeletion() {
1335        long rawContactId1 = createRawContactWithName("John", "Doe");
1336        long rawContactId2 = createRawContactWithName("John", "Doe");
1337        forceAggregation();
1338
1339        long contactId = queryContactId(rawContactId1);
1340
1341        mResolver.delete(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), null, null);
1342
1343        assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1),
1344                RawContacts.DELETED, "1");
1345        assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2),
1346                RawContacts.DELETED, "1");
1347    }
1348
1349    public void testMarkAsDirtyParameter() {
1350        long rawContactId = createRawContact(mAccount);
1351        Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
1352
1353        Uri uri = insertStructuredName(rawContactId, "John", "Doe");
1354        clearDirty(rawContactUri);
1355        Uri updateUri = uri.buildUpon()
1356                .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();
1357
1358        ContentValues values = new ContentValues();
1359        values.put(StructuredName.FAMILY_NAME, "Dough");
1360        mResolver.update(updateUri, values, null, null);
1361        assertStoredValue(uri, StructuredName.FAMILY_NAME, "Dough");
1362        assertDirty(rawContactUri, false);
1363        assertNetworkNotified(false);
1364    }
1365
1366    public void testRawContactDirtyAndVersion() {
1367        final long rawContactId = createRawContact(mAccount);
1368        Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId);
1369        assertDirty(uri, false);
1370        long version = getVersion(uri);
1371
1372        ContentValues values = new ContentValues();
1373        values.put(ContactsContract.RawContacts.DIRTY, 0);
1374        values.put(ContactsContract.RawContacts.SEND_TO_VOICEMAIL, 1);
1375        values.put(ContactsContract.RawContacts.AGGREGATION_MODE,
1376                RawContacts.AGGREGATION_MODE_IMMEDIATE);
1377        values.put(ContactsContract.RawContacts.STARRED, 1);
1378        assertEquals(1, mResolver.update(uri, values, null, null));
1379        assertEquals(version, getVersion(uri));
1380
1381        assertDirty(uri, false);
1382        assertNetworkNotified(false);
1383
1384        Uri emailUri = insertEmail(rawContactId, "goo@woo.com");
1385        assertDirty(uri, true);
1386        assertNetworkNotified(true);
1387        ++version;
1388        assertEquals(version, getVersion(uri));
1389        clearDirty(uri);
1390
1391        values = new ContentValues();
1392        values.put(Email.DATA, "goo@hoo.com");
1393        mResolver.update(emailUri, values, null, null);
1394        assertDirty(uri, true);
1395        assertNetworkNotified(true);
1396        ++version;
1397        assertEquals(version, getVersion(uri));
1398        clearDirty(uri);
1399
1400        mResolver.delete(emailUri, null, null);
1401        assertDirty(uri, true);
1402        assertNetworkNotified(true);
1403        ++version;
1404        assertEquals(version, getVersion(uri));
1405    }
1406
1407    public void testRawContactClearDirty() {
1408        final long rawContactId = createRawContact(mAccount);
1409        Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
1410                rawContactId);
1411        long version = getVersion(uri);
1412        insertEmail(rawContactId, "goo@woo.com");
1413        assertDirty(uri, true);
1414        version++;
1415        assertEquals(version, getVersion(uri));
1416
1417        clearDirty(uri);
1418        assertDirty(uri, false);
1419        assertEquals(version, getVersion(uri));
1420    }
1421
1422    public void testRawContactDeletionSetsDirty() {
1423        final long rawContactId = createRawContact(mAccount);
1424        Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI,
1425                rawContactId);
1426        long version = getVersion(uri);
1427        clearDirty(uri);
1428        assertDirty(uri, false);
1429
1430        mResolver.delete(uri, null, null);
1431        assertStoredValue(uri, RawContacts.DELETED, "1");
1432        assertDirty(uri, true);
1433        assertNetworkNotified(true);
1434        version++;
1435        assertEquals(version, getVersion(uri));
1436    }
1437
1438    public void testGetPhotoUri() {
1439        ContentValues values = new ContentValues();
1440        Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
1441        long rawContactId = ContentUris.parseId(rawContactUri);
1442        insertStructuredName(rawContactId, "John", "Doe");
1443        Uri photoUri = insertPhoto(rawContactId);
1444
1445        Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI,
1446                queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY);
1447
1448        long twigId = Long.parseLong(getStoredValue(twigUri, Data._ID));
1449        assertEquals(ContentUris.parseId(photoUri), twigId);
1450    }
1451
1452    public void testSuperPrimaryPhoto() {
1453        long rawContactId1 = createRawContact(new Account("a", "a"));
1454        Uri photoUri1 = insertPhoto(rawContactId1);
1455        long photoId1 = ContentUris.parseId(photoUri1);
1456
1457        long rawContactId2 = createRawContact(new Account("b", "b"));
1458        Uri photoUri2 = insertPhoto(rawContactId2);
1459        long photoId2 = ContentUris.parseId(photoUri2);
1460
1461        setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
1462                rawContactId1, rawContactId2);
1463
1464        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
1465                queryContactId(rawContactId1));
1466        assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1);
1467
1468        setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE,
1469                rawContactId1, rawContactId2);
1470
1471        ContentValues values = new ContentValues();
1472        values.put(Data.IS_SUPER_PRIMARY, 1);
1473        mResolver.update(photoUri2, values, null, null);
1474
1475        setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER,
1476                rawContactId1, rawContactId2);
1477        contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
1478                queryContactId(rawContactId1));
1479        assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId2);
1480
1481        mResolver.update(photoUri1, values, null, null);
1482        assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1);
1483    }
1484
1485    public void testUpdatePhoto() {
1486        ContentValues values = new ContentValues();
1487        Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
1488        long rawContactId = ContentUris.parseId(rawContactUri);
1489        insertStructuredName(rawContactId, "John", "Doe");
1490
1491        Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI,
1492                queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY);
1493
1494        values.clear();
1495        values.put(Data.RAW_CONTACT_ID, rawContactId);
1496        values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
1497        values.putNull(Photo.PHOTO);
1498        Uri dataUri = mResolver.insert(Data.CONTENT_URI, values);
1499        long photoId = ContentUris.parseId(dataUri);
1500
1501        assertNull(getStoredValue(twigUri, Data._ID));
1502
1503        values.clear();
1504        values.put(Photo.PHOTO, loadTestPhoto());
1505        mResolver.update(dataUri, values, null, null);
1506        assertNetworkNotified(true);
1507
1508        long twigId = Long.parseLong(getStoredValue(twigUri, Data._ID));
1509        assertEquals(photoId, twigId);
1510    }
1511
1512    public void testUpdateRawContactDataPhoto() {
1513        // setup a contact with a null photo
1514        ContentValues values = new ContentValues();
1515        Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
1516        long rawContactId = ContentUris.parseId(rawContactUri);
1517
1518        // setup a photo
1519        values.put(Data.RAW_CONTACT_ID, rawContactId);
1520        values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
1521        values.putNull(Photo.PHOTO);
1522
1523        // try to do an update before insert should return count == 0
1524        Uri dataUri = Uri.withAppendedPath(
1525                ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
1526                RawContacts.Data.CONTENT_DIRECTORY);
1527        assertEquals(0, mResolver.update(dataUri, values, Data.MIMETYPE + "=?",
1528                new String[] {Photo.CONTENT_ITEM_TYPE}));
1529
1530        mResolver.insert(Data.CONTENT_URI, values);
1531
1532        // save a photo to the db
1533        values.clear();
1534        values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
1535        values.put(Photo.PHOTO, loadTestPhoto());
1536        assertEquals(1, mResolver.update(dataUri, values, Data.MIMETYPE + "=?",
1537                new String[] {Photo.CONTENT_ITEM_TYPE}));
1538
1539        // verify the photo
1540        Cursor storedPhoto = mResolver.query(dataUri, new String[] {Photo.PHOTO},
1541                Data.MIMETYPE + "=?", new String[] {Photo.CONTENT_ITEM_TYPE}, null);
1542        storedPhoto.moveToFirst();
1543        MoreAsserts.assertEquals(loadTestPhoto(), storedPhoto.getBlob(0));
1544    }
1545
1546    public void testUpdateRawContactSetStarred() {
1547        long rawContactId1 = createRawContactWithName();
1548        Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1);
1549        long rawContactId2 = createRawContactWithName();
1550        Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2);
1551
1552        assertAggregated(rawContactId1, rawContactId2);
1553
1554        long contactId = queryContactId(rawContactId1);
1555        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
1556        assertStoredValue(contactUri, Contacts.STARRED, "0");
1557
1558        ContentValues values = new ContentValues();
1559        values.put(RawContacts.STARRED, "1");
1560
1561        mResolver.update(rawContactUri1, values, null, null);
1562
1563        assertStoredValue(rawContactUri1, RawContacts.STARRED, "1");
1564        assertStoredValue(rawContactUri2, RawContacts.STARRED, "0");
1565        assertStoredValue(contactUri, Contacts.STARRED, "1");
1566
1567        values.put(RawContacts.STARRED, "0");
1568        mResolver.update(rawContactUri1, values, null, null);
1569
1570        assertStoredValue(rawContactUri1, RawContacts.STARRED, "0");
1571        assertStoredValue(rawContactUri2, RawContacts.STARRED, "0");
1572        assertStoredValue(contactUri, Contacts.STARRED, "0");
1573
1574        values.put(Contacts.STARRED, "1");
1575        mResolver.update(contactUri, values, null, null);
1576
1577        assertStoredValue(rawContactUri1, RawContacts.STARRED, "1");
1578        assertStoredValue(rawContactUri2, RawContacts.STARRED, "1");
1579        assertStoredValue(contactUri, Contacts.STARRED, "1");
1580    }
1581
1582    public void testLiveFolders() {
1583        long rawContactId1 = createRawContactWithName("James", "Sullivan");
1584        insertPhoneNumber(rawContactId1, "5234567890");
1585        long contactId1 = queryContactId(rawContactId1);
1586
1587        long rawContactId2 = createRawContactWithName("Mike", "Wazowski");
1588        long contactId2 = queryContactId(rawContactId2);
1589        storeValue(Contacts.CONTENT_URI, contactId2, Contacts.STARRED, "1");
1590
1591        long rawContactId3 = createRawContactWithName("Randall", "Boggs");
1592        long contactId3 = queryContactId(rawContactId3);
1593        long groupId = createGroup(NO_ACCOUNT, "src1", "VIP");
1594        insertGroupMembership(rawContactId3, groupId);
1595
1596        assertLiveFolderContents(
1597                Uri.withAppendedPath(ContactsContract.AUTHORITY_URI,
1598                        "live_folders/contacts"),
1599                contactId1, "James Sullivan",
1600                contactId2, "Mike Wazowski",
1601                contactId3, "Randall Boggs");
1602
1603        assertLiveFolderContents(
1604                Uri.withAppendedPath(ContactsContract.AUTHORITY_URI,
1605                        "live_folders/contacts_with_phones"),
1606                contactId1, "James Sullivan");
1607
1608        assertLiveFolderContents(
1609                Uri.withAppendedPath(ContactsContract.AUTHORITY_URI,
1610                        "live_folders/favorites"),
1611                contactId2, "Mike Wazowski");
1612
1613        assertLiveFolderContents(
1614                Uri.withAppendedPath(Uri.withAppendedPath(ContactsContract.AUTHORITY_URI,
1615                        "live_folders/contacts"), Uri.encode("VIP")),
1616                contactId3, "Randall Boggs");
1617    }
1618
1619    private void assertLiveFolderContents(Uri uri, Object... expected) {
1620        Cursor c = mResolver.query(uri, new String[]{LiveFolders._ID, LiveFolders.NAME},
1621                null, null, LiveFolders._ID);
1622        assertEquals(expected.length/2, c.getCount());
1623        for (int i = 0; i < expected.length/2; i++) {
1624            assertTrue(c.moveToNext());
1625            assertEquals(((Long)expected[i * 2]).longValue(), c.getLong(0));
1626            assertEquals(expected[i * 2 + 1], c.getString(1));
1627        }
1628        c.close();
1629    }
1630
1631    private long createContact(ContentValues values, String firstName, String givenName,
1632            String phoneNumber, String email, int presenceStatus, int timesContacted, int starred,
1633            long groupId) {
1634        values.put(RawContacts.STARRED, starred);
1635        values.put(RawContacts.SEND_TO_VOICEMAIL, 1);
1636        values.put(RawContacts.CUSTOM_RINGTONE, "beethoven5");
1637        values.put(RawContacts.LAST_TIME_CONTACTED, 12345);
1638        values.put(RawContacts.TIMES_CONTACTED, timesContacted);
1639        Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values);
1640        long rawContactId = ContentUris.parseId(rawContactUri);
1641        insertStructuredName(rawContactId, firstName, givenName);
1642        Uri photoUri = insertPhoto(rawContactId);
1643        long photoId = ContentUris.parseId(photoUri);
1644        values.put(Contacts.PHOTO_ID, photoId);
1645        insertPhoneNumber(rawContactId, phoneNumber);
1646        insertEmail(rawContactId, email);
1647
1648        insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, email, presenceStatus, "hacking");
1649
1650        if (groupId != 0) {
1651            insertGroupMembership(rawContactId, groupId);
1652        }
1653
1654        return queryContactId(rawContactId);
1655    }
1656
1657    private void putDataValues(ContentValues values, long rawContactId) {
1658        values.put(Data.RAW_CONTACT_ID, rawContactId);
1659        values.put(Data.MIMETYPE, "testmimetype");
1660        values.put(Data.RES_PACKAGE, "oldpackage");
1661        values.put(Data.IS_PRIMARY, 1);
1662        values.put(Data.IS_SUPER_PRIMARY, 1);
1663        values.put(Data.DATA1, "one");
1664        values.put(Data.DATA2, "two");
1665        values.put(Data.DATA3, "three");
1666        values.put(Data.DATA4, "four");
1667        values.put(Data.DATA5, "five");
1668        values.put(Data.DATA6, "six");
1669        values.put(Data.DATA7, "seven");
1670        values.put(Data.DATA8, "eight");
1671        values.put(Data.DATA9, "nine");
1672        values.put(Data.DATA10, "ten");
1673        values.put(Data.DATA11, "eleven");
1674        values.put(Data.DATA12, "twelve");
1675        values.put(Data.DATA13, "thirteen");
1676        values.put(Data.DATA14, "fourteen");
1677        values.put(Data.DATA15, "fifteen");
1678        values.put(Data.SYNC1, "sync1");
1679        values.put(Data.SYNC2, "sync2");
1680        values.put(Data.SYNC3, "sync3");
1681        values.put(Data.SYNC4, "sync4");
1682    }
1683}
1684
1685