ContactDirectoryManagerTest.java revision 994c32a995a85937faf59e37a9fc88b526470d7d
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.providers.contacts;
18
19import com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns;
20import com.google.android.collect.Lists;
21
22import android.accounts.Account;
23import android.content.ContentValues;
24import android.content.Context;
25import android.content.pm.PackageInfo;
26import android.content.pm.ProviderInfo;
27import android.database.Cursor;
28import android.database.MatrixCursor;
29import android.net.Uri;
30import android.os.Bundle;
31import android.provider.ContactsContract;
32import android.provider.ContactsContract.AggregationExceptions;
33import android.provider.ContactsContract.Contacts;
34import android.provider.ContactsContract.Directory;
35import android.provider.ContactsContract.RawContacts;
36import android.test.mock.MockContentProvider;
37import android.test.suitebuilder.annotation.LargeTest;
38
39/**
40 * Unit tests for {@link ContactDirectoryManager}. Run the test like this:
41 * <code>
42 *   adb shell am instrument -e class com.android.providers.contacts.ContactDirectoryManagerTest
43 *       -w com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
44 * </code>
45 */
46@LargeTest
47public class ContactDirectoryManagerTest extends BaseContactsProvider2Test {
48
49    private ContactsMockPackageManager mPackageManager;
50
51    private ContactsProvider2 mProvider;
52
53    private ContactDirectoryManager mDirectoryManager;
54
55    public static class MockContactDirectoryProvider extends MockContentProvider {
56
57        private String mAuthority;
58
59        private MatrixCursor mResponse;
60
61        @Override
62        public void attachInfo(Context context, ProviderInfo info) {
63            mAuthority = info.authority;
64        }
65
66        public MatrixCursor createResponseCursor() {
67            mResponse = new MatrixCursor(
68                    new String[] { Directory.ACCOUNT_NAME, Directory.ACCOUNT_TYPE,
69                            Directory.DISPLAY_NAME, Directory.TYPE_RESOURCE_ID,
70                            Directory.EXPORT_SUPPORT, Directory.SHORTCUT_SUPPORT,
71                            Directory.PHOTO_SUPPORT });
72
73            return mResponse;
74        }
75
76        @Override
77        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
78                String sortOrder) {
79
80            if (uri.toString().equals("content://" + mAuthority + "/directories")) {
81                return mResponse;
82            } else if (uri.toString().startsWith("content://" + mAuthority + "/contacts")) {
83                MatrixCursor cursor = new MatrixCursor(
84                        new String[] { "projection", "selection", "selectionArgs", "sortOrder",
85                                "accountName", "accountType"});
86                cursor.addRow(new Object[] {
87                    Lists.newArrayList(projection).toString(),
88                    selection,
89                    Lists.newArrayList(selectionArgs).toString(),
90                    sortOrder,
91                    uri.getQueryParameter(RawContacts.ACCOUNT_NAME),
92                    uri.getQueryParameter(RawContacts.ACCOUNT_TYPE),
93                });
94                return cursor;
95            } else if (uri.toString().startsWith(
96                    "content://" + mAuthority + "/aggregation_exceptions")) {
97                return new MatrixCursor(projection);
98            }
99
100            fail("Unexpected uri: " + uri);
101            return null;
102        }
103    }
104
105    @Override
106    public void setUp() throws Exception {
107        super.setUp();
108
109        mProvider = (ContactsProvider2) getProvider();
110        mDirectoryManager = mProvider.getContactDirectoryManager();
111
112        mPackageManager = (ContactsMockPackageManager) getProvider()
113                .getContext().getPackageManager();
114    }
115
116    public void testScanAllProviders() throws Exception {
117        mPackageManager.setInstalledPackages(
118                Lists.newArrayList(
119                        createProviderPackage("test.package1", "authority1"),
120                        createProviderPackage("test.package2", "authority2")));
121
122        MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
123                MockContactDirectoryProvider.class, "authority1");
124
125        MatrixCursor response1 = provider1.createResponseCursor();
126        addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
127                Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
128                Directory.PHOTO_SUPPORT_FULL_SIZE_ONLY);
129        addDirectoryRow(response1, "account-name2", "account-type2", "display-name2", 2,
130                Directory.EXPORT_SUPPORT_ANY_ACCOUNT, Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY,
131                Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY);
132
133        MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider(
134                MockContactDirectoryProvider.class, "authority2");
135
136        MatrixCursor response2 = provider2.createResponseCursor();
137        addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3,
138                Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL,
139                Directory.PHOTO_SUPPORT_FULL);
140
141        mDirectoryManager.scanAllPackages();
142
143        Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
144        assertEquals(5, cursor.getCount());
145
146        cursor.moveToPosition(2);
147        assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
148                "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
149                Directory.PHOTO_SUPPORT_FULL_SIZE_ONLY);
150
151        cursor.moveToNext();
152        assertDirectoryRow(cursor, "test.package1", "authority1", "account-name2", "account-type2",
153                "display-name2", 2, Directory.EXPORT_SUPPORT_ANY_ACCOUNT,
154                Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY, Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY);
155
156        cursor.moveToNext();
157        assertDirectoryRow(cursor, "test.package2", "authority2", "account-name3", "account-type3",
158                "display-name3", 3, Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY,
159                Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL);
160
161        cursor.close();
162    }
163
164    public void testPackageInstalled() throws Exception {
165        mPackageManager.setInstalledPackages(
166                Lists.newArrayList(createProviderPackage("test.package1", "authority1")));
167
168        MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
169                MockContactDirectoryProvider.class, "authority1");
170
171        MatrixCursor response1 = provider1.createResponseCursor();
172        addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
173                Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
174                Directory.PHOTO_SUPPORT_FULL);
175
176        mDirectoryManager.scanAllPackages();
177
178        // At this point the manager has discovered a single directory (plus two
179        // standard ones).
180        Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
181        assertEquals(3, cursor.getCount());
182        cursor.close();
183
184        // Pretend to install another package
185        MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider(
186                MockContactDirectoryProvider.class, "authority2");
187
188        MatrixCursor response2 = provider2.createResponseCursor();
189        addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3,
190                Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL,
191                Directory.PHOTO_SUPPORT_FULL);
192
193        mPackageManager.getInstalledPackages(0).add(
194                createProviderPackage("test.package2", "authority2"));
195
196        mProvider.onPackageChanged("test.package2");
197
198        cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
199        assertEquals(4, cursor.getCount());
200
201        cursor.moveToPosition(2);
202        assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
203                "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
204                Directory.PHOTO_SUPPORT_FULL);
205
206        cursor.moveToNext();
207        assertDirectoryRow(cursor, "test.package2", "authority2", "account-name3", "account-type3",
208                "display-name3", 3, Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY,
209                Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL);
210
211        cursor.close();
212    }
213
214    public void testPackageUninstalled() throws Exception {
215        mPackageManager.setInstalledPackages(
216                Lists.newArrayList(
217                        createProviderPackage("test.package1", "authority1"),
218                        createProviderPackage("test.package2", "authority2")));
219
220        MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
221                MockContactDirectoryProvider.class, "authority1");
222
223        MatrixCursor response1 = provider1.createResponseCursor();
224        addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
225                Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
226                Directory.PHOTO_SUPPORT_NONE);
227
228        MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider(
229                MockContactDirectoryProvider.class, "authority2");
230
231        MatrixCursor response2 = provider2.createResponseCursor();
232        addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3,
233                Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL,
234                Directory.PHOTO_SUPPORT_FULL);
235
236        mDirectoryManager.scanAllPackages();
237
238        // At this point the manager has discovered two custom directories.
239        Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
240        assertEquals(4, cursor.getCount());
241        cursor.close();
242
243        // Pretend to uninstall one of the packages
244        mPackageManager.getInstalledPackages(0).remove(1);
245
246        mProvider.onPackageChanged("test.package2");
247
248        cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
249        assertEquals(3, cursor.getCount());
250
251        cursor.moveToPosition(2);
252        assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
253                "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
254                Directory.PHOTO_SUPPORT_NONE);
255
256        cursor.close();
257    }
258
259    public void testPackageReplaced() throws Exception {
260        mPackageManager.setInstalledPackages(
261                Lists.newArrayList(
262                        createProviderPackage("test.package1", "authority1"),
263                        createProviderPackage("test.package2", "authority2")));
264
265        MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
266                MockContactDirectoryProvider.class, "authority1");
267
268        MatrixCursor response1 = provider1.createResponseCursor();
269        addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
270                Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
271                Directory.PHOTO_SUPPORT_NONE);
272
273        MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider(
274                MockContactDirectoryProvider.class, "authority2");
275
276        MatrixCursor response2 = provider2.createResponseCursor();
277        addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3,
278                Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL,
279                Directory.PHOTO_SUPPORT_FULL);
280
281        mDirectoryManager.scanAllPackages();
282
283        // At this point the manager has discovered two custom directories.
284        Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
285        assertEquals(4, cursor.getCount());
286        cursor.close();
287
288        // Pretend to replace the package with a different provider inside
289        MatrixCursor response3 = provider2.createResponseCursor();
290        addDirectoryRow(response3, "account-name4", "account-type4", "display-name4", 4,
291                Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
292                Directory.PHOTO_SUPPORT_NONE);
293
294        mProvider.onPackageChanged("test.package2");
295
296        cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
297        assertEquals(4, cursor.getCount());
298
299        cursor.moveToPosition(2);
300        assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
301                "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
302                Directory.PHOTO_SUPPORT_NONE);
303
304        cursor.moveToNext();
305        assertDirectoryRow(cursor, "test.package2", "authority2", "account-name4", "account-type4",
306                "display-name4", 4, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
307                Directory.PHOTO_SUPPORT_NONE);
308
309        cursor.close();
310    }
311
312    public void testAccountRemoval() throws Exception {
313        mPackageManager.setInstalledPackages(
314                Lists.newArrayList(
315                        createProviderPackage("test.package1", "authority1"),
316                        createProviderPackage("test.package2", "authority2")));
317
318        MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
319                MockContactDirectoryProvider.class, "authority1");
320
321        ((ContactsProvider2)getProvider()).onAccountsUpdated(
322                new Account[]{
323                        new Account("account-name1", "account-type1"),
324                        new Account("account-name2", "account-type2")});
325
326        MatrixCursor response1 = provider1.createResponseCursor();
327        addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
328                Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
329                Directory.PHOTO_SUPPORT_NONE);
330        addDirectoryRow(response1, "account-name2", "account-type2", "display-name2", 2,
331                Directory.EXPORT_SUPPORT_ANY_ACCOUNT, Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY,
332                Directory.PHOTO_SUPPORT_FULL_SIZE_ONLY);
333
334        mDirectoryManager.scanAllPackages();
335
336        ((ContactsProvider2)getProvider()).onAccountsUpdated(
337                new Account[]{new Account("account-name1", "account-type1")});
338
339        Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
340        assertEquals(3, cursor.getCount());
341
342        cursor.moveToPosition(2);
343        assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
344                "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
345                Directory.PHOTO_SUPPORT_NONE);
346
347        cursor.close();
348    }
349
350    public void testNotifyDirectoryChange() throws Exception {
351        mPackageManager.setInstalledPackages(
352                Lists.newArrayList(createProviderPackage("test.package1", "authority1")));
353
354        MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
355                MockContactDirectoryProvider.class, "authority1");
356
357        MatrixCursor response1 = provider1.createResponseCursor();
358        addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
359                Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
360                Directory.PHOTO_SUPPORT_NONE);
361
362        mDirectoryManager.scanAllPackages();
363
364        // Pretend to replace the package with a different provider inside
365        MatrixCursor response2 = provider1.createResponseCursor();
366        addDirectoryRow(response2, "account-name2", "account-type2", "display-name2", 2,
367                Directory.EXPORT_SUPPORT_ANY_ACCOUNT, Directory.SHORTCUT_SUPPORT_FULL,
368                Directory.PHOTO_SUPPORT_FULL);
369
370        ContactsContract.Directory.notifyDirectoryChange(mResolver);
371
372        Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
373        assertEquals(3, cursor.getCount());
374
375        cursor.moveToPosition(2);
376        assertDirectoryRow(cursor, "test.package1", "authority1", "account-name2", "account-type2",
377                "display-name2", 2, Directory.EXPORT_SUPPORT_ANY_ACCOUNT,
378                Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL);
379
380        cursor.close();
381    }
382
383    public void testForwardingToDirectoryProvider() throws Exception {
384        mPackageManager.setInstalledPackages(
385                Lists.newArrayList(createProviderPackage("test.package1", "authority1")));
386
387        MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
388                MockContactDirectoryProvider.class, "authority1");
389
390        MatrixCursor response1 = provider1.createResponseCursor();
391        addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
392                Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
393                Directory.PHOTO_SUPPORT_NONE);
394
395        mDirectoryManager.scanAllPackages();
396
397        Cursor cursor = mResolver.query(
398                Directory.CONTENT_URI, new String[] { Directory._ID }, null, null, null);
399        cursor.moveToPosition(2);
400        long directoryId = cursor.getLong(0);
401        cursor.close();
402
403        Uri contentUri = Contacts.CONTENT_URI.buildUpon().appendQueryParameter(
404                ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
405
406        // The request should be forwarded to TestProvider, which will simply
407        // package arguments and return them to us for verification
408        cursor = mResolver.query(contentUri,
409                new String[]{"f1", "f2"}, "query", new String[]{"s1", "s2"}, "so");
410        assertNotNull(cursor);
411        assertEquals(1, cursor.getCount());
412        cursor.moveToFirst();
413        assertEquals("[f1, f2]", cursor.getString(cursor.getColumnIndex("projection")));
414        assertEquals("query", cursor.getString(cursor.getColumnIndex("selection")));
415        assertEquals("[s1, s2]", cursor.getString(cursor.getColumnIndex("selectionArgs")));
416        assertEquals("so", cursor.getString(cursor.getColumnIndex("sortOrder")));
417        assertEquals("account-name1", cursor.getString(cursor.getColumnIndex("accountName")));
418        assertEquals("account-type1", cursor.getString(cursor.getColumnIndex("accountType")));
419        cursor.close();
420    }
421
422    public void testProjectionPopulated() throws Exception {
423        mPackageManager.setInstalledPackages(
424                Lists.newArrayList(createProviderPackage("test.package1", "authority1")));
425
426        MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
427                MockContactDirectoryProvider.class, "authority1");
428
429        MatrixCursor response1 = provider1.createResponseCursor();
430        addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
431                Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
432                Directory.PHOTO_SUPPORT_NONE);
433
434        mDirectoryManager.scanAllPackages();
435
436        Cursor cursor = mResolver.query(
437                Directory.CONTENT_URI, new String[] { Directory._ID }, null, null, null);
438        cursor.moveToPosition(2);
439        long directoryId = cursor.getLong(0);
440        cursor.close();
441
442        Uri contentUri = AggregationExceptions.CONTENT_URI.buildUpon().appendQueryParameter(
443                ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
444
445        // The request should be forwarded to TestProvider, which will return an empty cursor
446        // but the projection should be correctly populated by ContactProvider
447        assertProjection(contentUri, new String[]{
448                AggregationExceptionColumns._ID,
449                AggregationExceptions.TYPE,
450                AggregationExceptions.RAW_CONTACT_ID1,
451                AggregationExceptions.RAW_CONTACT_ID2,
452        });
453    }
454
455    protected PackageInfo createProviderPackage(String packageName, String authority) {
456        PackageInfo providerPackage = new PackageInfo();
457        providerPackage.packageName = packageName;
458        ProviderInfo providerInfo = new ProviderInfo();
459        providerInfo.packageName = providerPackage.packageName;
460        providerInfo.authority = authority;
461        providerInfo.metaData = new Bundle();
462        providerInfo.metaData.putBoolean("android.content.ContactDirectory", true);
463        providerPackage.providers = new ProviderInfo[] { providerInfo };
464        return providerPackage;
465    }
466
467    protected void addDirectoryRow(MatrixCursor cursor, String accountName, String accountType,
468            String displayName, int typeResourceId, int exportSupport, int shortcutSupport,
469            int photoSupport) {
470        Object[] row = new Object[cursor.getColumnCount()];
471        row[cursor.getColumnIndex(Directory.ACCOUNT_NAME)] = accountName;
472        row[cursor.getColumnIndex(Directory.ACCOUNT_TYPE)] = accountType;
473        row[cursor.getColumnIndex(Directory.DISPLAY_NAME)] = displayName;
474        row[cursor.getColumnIndex(Directory.TYPE_RESOURCE_ID)] = typeResourceId;
475        row[cursor.getColumnIndex(Directory.EXPORT_SUPPORT)] = exportSupport;
476        row[cursor.getColumnIndex(Directory.SHORTCUT_SUPPORT)] = shortcutSupport;
477        row[cursor.getColumnIndex(Directory.PHOTO_SUPPORT)] = photoSupport;
478        cursor.addRow(row);
479    }
480
481    protected void assertDirectoryRow(Cursor cursor, String packageName, String authority,
482            String accountName, String accountType, String displayName, int typeResourceId,
483            int exportSupport, int shortcutSupport, int photoSupport) {
484        ContentValues values = new ContentValues();
485        values.put(Directory.PACKAGE_NAME, packageName);
486        values.put(Directory.DIRECTORY_AUTHORITY, authority);
487        values.put(Directory.ACCOUNT_NAME, accountName);
488        values.put(Directory.ACCOUNT_TYPE, accountType);
489        values.put(Directory.DISPLAY_NAME, displayName);
490        values.put(Directory.TYPE_RESOURCE_ID, typeResourceId);
491        values.put(Directory.EXPORT_SUPPORT, exportSupport);
492        values.put(Directory.SHORTCUT_SUPPORT, shortcutSupport);
493        values.put(Directory.PHOTO_SUPPORT, photoSupport);
494
495        assertCursorValues(cursor, values);
496    }
497}
498