• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.providers.contacts;
18 
19 import android.accounts.Account;
20 import android.content.ContentValues;
21 import android.content.Context;
22 import android.content.pm.PackageInfo;
23 import android.content.pm.PackageManager;
24 import android.content.pm.PackageManager.NameNotFoundException;
25 import android.content.pm.ProviderInfo;
26 import android.database.Cursor;
27 import android.database.MatrixCursor;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.provider.ContactsContract;
31 import android.provider.ContactsContract.AggregationExceptions;
32 import android.provider.ContactsContract.Contacts;
33 import android.provider.ContactsContract.Directory;
34 import android.provider.ContactsContract.RawContacts;
35 import android.test.mock.MockContentProvider;
36 import android.test.suitebuilder.annotation.MediumTest;
37 import android.util.Log;
38 
39 import com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns;
40 import com.google.android.collect.Lists;
41 
42 /**
43  * Unit tests for {@link ContactDirectoryManager}. Run the test like this:
44  *
45     adb shell am instrument -e class com.android.providers.contacts.ContactDirectoryManagerTest \
46         -w com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
47  *
48  */
49 @MediumTest
50 public class ContactDirectoryManagerTest extends BaseContactsProvider2Test {
51     private static final String TAG = "ContactDirectoryManagerTest";
52 
53     private ContactsMockPackageManager mPackageManager;
54 
55     private ContactsProvider2 mProvider;
56 
57     private ContactDirectoryManager mDirectoryManager;
58 
59     public static class MockContactDirectoryProvider extends MockContentProvider {
60 
61         private String mAuthority;
62 
63         private MatrixCursor mResponse;
64 
65         @Override
attachInfo(Context context, ProviderInfo info)66         public void attachInfo(Context context, ProviderInfo info) {
67             mAuthority = info.authority;
68         }
69 
createResponseCursor()70         public MatrixCursor createResponseCursor() {
71             mResponse = new MatrixCursor(
72                     new String[] { Directory.ACCOUNT_NAME, Directory.ACCOUNT_TYPE,
73                             Directory.DISPLAY_NAME, Directory.TYPE_RESOURCE_ID,
74                             Directory.EXPORT_SUPPORT, Directory.SHORTCUT_SUPPORT,
75                             Directory.PHOTO_SUPPORT });
76 
77             return mResponse;
78         }
79 
80         @Override
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)81         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
82                 String sortOrder) {
83 
84             if (uri.toString().equals("content://" + mAuthority + "/directories")) {
85                 // Should tolerate multiple queries.
86                 mResponse.moveToPosition(-1);
87                 return mResponse;
88             } else if (uri.toString().startsWith("content://" + mAuthority + "/contacts")) {
89                 MatrixCursor cursor = new MatrixCursor(
90                         new String[] { "projection", "selection", "selectionArgs", "sortOrder",
91                                 "accountName", "accountType"});
92                 cursor.addRow(new Object[] {
93                     Lists.newArrayList(projection).toString(),
94                     selection,
95                     Lists.newArrayList(selectionArgs).toString(),
96                     sortOrder,
97                     uri.getQueryParameter(RawContacts.ACCOUNT_NAME),
98                     uri.getQueryParameter(RawContacts.ACCOUNT_TYPE),
99                 });
100                 return cursor;
101             } else if (uri.toString().startsWith(
102                     "content://" + mAuthority + "/aggregation_exceptions")) {
103                 return new MatrixCursor(projection);
104             }
105 
106             fail("Unexpected uri: " + uri);
107             return null;
108         }
109     }
110 
111     @Override
setUp()112     public void setUp() throws Exception {
113         super.setUp();
114 
115         mProvider = (ContactsProvider2) getProvider();
116         mDirectoryManager = mProvider.getContactDirectoryManagerForTest();
117 
118         mPackageManager = (ContactsMockPackageManager) getProvider()
119                 .getContext().getPackageManager();
120     }
121 
testIsDirectoryProvider()122     public void testIsDirectoryProvider() {
123         ProviderInfo provider = new ProviderInfo();
124 
125         // No metadata
126         assertFalse(ContactDirectoryManager.isDirectoryProvider(provider));
127 
128         // No CONTACT_DIRECTORY_META_DATA
129         provider.metaData = new Bundle();
130         assertFalse(ContactDirectoryManager.isDirectoryProvider(provider));
131 
132         // CONTACT_DIRECTORY_META_DATA is a string
133         provider.metaData.putString("android.content.ContactDirectory", "");
134         assertFalse(ContactDirectoryManager.isDirectoryProvider(provider));
135 
136         // CONTACT_DIRECTORY_META_DATA is false
137         provider.metaData.putBoolean("android.content.ContactDirectory", false);
138         assertFalse(ContactDirectoryManager.isDirectoryProvider(provider));
139 
140         // CONTACT_DIRECTORY_META_DATA is true
141         provider.metaData.putBoolean("android.content.ContactDirectory", true);
142         assertTrue(ContactDirectoryManager.isDirectoryProvider(provider));
143     }
144 
testScanAllProviders()145     public void testScanAllProviders() throws Exception {
146         mPackageManager.setInstalledPackages(
147                 Lists.newArrayList(
148                         createProviderPackage("test.package1", "authority1"),
149                         createProviderPackage("test.package2", "authority2"),
150                         createPackage("test.packageX", "authorityX", false)));
151 
152         MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
153                 MockContactDirectoryProvider.class, "authority1");
154 
155         MatrixCursor response1 = provider1.createResponseCursor();
156         addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
157                 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
158                 Directory.PHOTO_SUPPORT_FULL_SIZE_ONLY);
159         addDirectoryRow(response1, "account-name2", "account-type2", "display-name2", 2,
160                 Directory.EXPORT_SUPPORT_ANY_ACCOUNT, Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY,
161                 Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY);
162 
163         MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider(
164                 MockContactDirectoryProvider.class, "authority2");
165 
166         MatrixCursor response2 = provider2.createResponseCursor();
167         addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3,
168                 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL,
169                 Directory.PHOTO_SUPPORT_FULL);
170 
171         mDirectoryManager.scanAllPackages();
172 
173         Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
174         assertEquals(5, cursor.getCount());
175 
176         cursor.moveToPosition(2);
177         assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
178                 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
179                 Directory.PHOTO_SUPPORT_FULL_SIZE_ONLY);
180 
181         cursor.moveToNext();
182         assertDirectoryRow(cursor, "test.package1", "authority1", "account-name2", "account-type2",
183                 "display-name2", 2, Directory.EXPORT_SUPPORT_ANY_ACCOUNT,
184                 Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY, Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY);
185 
186         cursor.moveToNext();
187         assertDirectoryRow(cursor, "test.package2", "authority2", "account-name3", "account-type3",
188                 "display-name3", 3, Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY,
189                 Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL);
190 
191         cursor.close();
192     }
193 
testPackageInstalled()194     public void testPackageInstalled() throws Exception {
195         mPackageManager.setInstalledPackages(
196                 Lists.newArrayList(createProviderPackage("test.package1", "authority1"),
197                         createPackage("test.packageX", "authorityX", false)));
198 
199         MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
200                 MockContactDirectoryProvider.class, "authority1");
201 
202         MatrixCursor response1 = provider1.createResponseCursor();
203         addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
204                 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
205                 Directory.PHOTO_SUPPORT_FULL);
206 
207         mDirectoryManager.scanAllPackages();
208 
209         // At this point the manager has discovered a single directory (plus two
210         // standard ones).
211         Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
212         assertEquals(3, cursor.getCount());
213         cursor.close();
214 
215         // Pretend to install another package
216         MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider(
217                 MockContactDirectoryProvider.class, "authority2");
218 
219         MatrixCursor response2 = provider2.createResponseCursor();
220         addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3,
221                 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL,
222                 Directory.PHOTO_SUPPORT_FULL);
223 
224         mPackageManager.getInstalledPackages(0).add(
225                 createProviderPackage("test.package2", "authority2"));
226 
227         mProvider.onPackageChanged("test.package2");
228 
229         cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
230         assertEquals(4, cursor.getCount());
231 
232         cursor.moveToPosition(2);
233         assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
234                 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
235                 Directory.PHOTO_SUPPORT_FULL);
236 
237         cursor.moveToNext();
238         assertDirectoryRow(cursor, "test.package2", "authority2", "account-name3", "account-type3",
239                 "display-name3", 3, Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY,
240                 Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL);
241 
242         cursor.close();
243     }
244 
testPackageUninstalled()245     public void testPackageUninstalled() throws Exception {
246         mPackageManager.setInstalledPackages(
247                 Lists.newArrayList(
248                         createProviderPackage("test.package1", "authority1"),
249                         createProviderPackage("test.package2", "authority2"),
250                         createPackage("test.packageX", "authorityX", false)));
251 
252         MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
253                 MockContactDirectoryProvider.class, "authority1");
254 
255         MatrixCursor response1 = provider1.createResponseCursor();
256         addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
257                 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
258                 Directory.PHOTO_SUPPORT_NONE);
259 
260         MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider(
261                 MockContactDirectoryProvider.class, "authority2");
262 
263         MatrixCursor response2 = provider2.createResponseCursor();
264         addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3,
265                 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL,
266                 Directory.PHOTO_SUPPORT_FULL);
267 
268         mDirectoryManager.scanAllPackages();
269 
270         // At this point the manager has discovered two custom directories.
271         Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
272         assertEquals(4, cursor.getCount());
273         cursor.close();
274 
275         // Pretend to uninstall one of the packages
276         mPackageManager.getInstalledPackages(0).remove(1);
277 
278         mProvider.onPackageChanged("test.package2");
279 
280         cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
281         assertEquals(3, cursor.getCount());
282 
283         cursor.moveToPosition(2);
284         assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
285                 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
286                 Directory.PHOTO_SUPPORT_NONE);
287 
288         cursor.close();
289     }
290 
testPackageReplaced()291     public void testPackageReplaced() throws Exception {
292         mPackageManager.setInstalledPackages(
293                 Lists.newArrayList(
294                         createProviderPackage("test.package1", "authority1"),
295                         createProviderPackage("test.package2", "authority2"),
296                         createPackage("test.packageX", "authorityX", false)));
297 
298         MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
299                 MockContactDirectoryProvider.class, "authority1");
300 
301         MatrixCursor response1 = provider1.createResponseCursor();
302         addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
303                 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
304                 Directory.PHOTO_SUPPORT_NONE);
305 
306         MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider(
307                 MockContactDirectoryProvider.class, "authority2");
308 
309         MatrixCursor response2 = provider2.createResponseCursor();
310         addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3,
311                 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL,
312                 Directory.PHOTO_SUPPORT_FULL);
313 
314         mDirectoryManager.scanAllPackages();
315 
316         // At this point the manager has discovered two custom directories.
317         Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
318         assertEquals(4, cursor.getCount());
319         cursor.close();
320 
321         // Pretend to replace the package with a different provider inside
322         MatrixCursor response3 = provider2.createResponseCursor();
323         addDirectoryRow(response3, "account-name4", "account-type4", "display-name4", 4,
324                 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
325                 Directory.PHOTO_SUPPORT_NONE);
326 
327         mProvider.onPackageChanged("test.package2");
328 
329         cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
330         assertEquals(4, cursor.getCount());
331 
332         cursor.moveToPosition(2);
333         assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
334                 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
335                 Directory.PHOTO_SUPPORT_NONE);
336 
337         cursor.moveToNext();
338         assertDirectoryRow(cursor, "test.package2", "authority2", "account-name4", "account-type4",
339                 "display-name4", 4, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
340                 Directory.PHOTO_SUPPORT_NONE);
341 
342         cursor.close();
343     }
344 
345     /**
346      * Tests if the manager works correctly when the package name for a directory is changed
347      * (on system update).
348      */
testPackageRenamed()349     public void testPackageRenamed() throws Exception {
350         mPackageManager.setInstalledPackages(
351                 Lists.newArrayList(
352                         createProviderPackage("test.package1", "authority1"),
353                         createProviderPackage("test.package2", "authority2"),
354                         createPackage("test.packageX", "authorityX", false)));
355 
356         MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
357                 MockContactDirectoryProvider.class, "authority1");
358 
359         MatrixCursor response1 = provider1.createResponseCursor();
360         addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
361                 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
362                 Directory.PHOTO_SUPPORT_NONE);
363 
364         MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider(
365                 MockContactDirectoryProvider.class, "authority2");
366 
367         MatrixCursor response2 = provider2.createResponseCursor();
368         addDirectoryRow(response2, "account-name2", "account-type2", "display-name2", 2,
369                 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL,
370                 Directory.PHOTO_SUPPORT_FULL);
371 
372         mDirectoryManager.scanAllPackages();
373 
374         // At this point the manager has discovered two custom directories.
375         Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
376         assertEquals(4, cursor.getCount());
377         cursor.close();
378 
379         // Pretend to rename the package name of a package on system update.
380         PackageInfo info = mPackageManager.getInstalledPackages(0).get(1);
381         info.packageName              = "test.package3";
382         info.providers[0].packageName = "test.package3";
383         MatrixCursor response3 = provider2.createResponseCursor();
384         // Change resource id.
385         addDirectoryRow(response3, "account-name2", "account-type2", "display-name2", 3,
386                 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL,
387                 Directory.PHOTO_SUPPORT_FULL);
388 
389         // When this happens on reboot, scanAllPackages() is called instead of onPackageChanged()
390         // (as part of ContactsProvider2 initialization).
391         // Accounts won't be affected so false should be passed here.
392         mDirectoryManager.scanAllPackages(false);
393 
394         cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
395         // We should have columns for default, local_invisible, test.package1, and test.package3.
396         // The row for test.package2 should not remain.
397         assertEquals(4, cursor.getCount());
398 
399         cursor.moveToPosition(2);
400         assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
401                 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
402                 Directory.PHOTO_SUPPORT_NONE);
403 
404         cursor.moveToNext();
405         assertDirectoryRow(cursor, "test.package3", "authority2", "account-name2", "account-type2",
406                 "display-name2", 3, Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY,
407                 Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL);
408 
409         cursor.close();
410     }
411 
testAccountRemoval()412     public void testAccountRemoval() throws Exception {
413         mPackageManager.setInstalledPackages(
414                 Lists.newArrayList(
415                         createProviderPackage("test.package1", "authority1"),
416                         createProviderPackage("test.package2", "authority2"),
417                         createPackage("test.packageX", "authorityX", false)));
418 
419         MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
420                 MockContactDirectoryProvider.class, "authority1");
421 
422         Account[] accounts = new Account[]{
423                 new Account("account-name1", "account-type1"),
424                 new Account("account-name2", "account-type2")};
425         mActor.setAccounts(accounts);
426         ((ContactsProvider2)getProvider()).onAccountsUpdated(accounts);
427 
428         MatrixCursor response1 = provider1.createResponseCursor();
429         addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
430                 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
431                 Directory.PHOTO_SUPPORT_NONE);
432         addDirectoryRow(response1, "account-name2", "account-type2", "display-name2", 2,
433                 Directory.EXPORT_SUPPORT_ANY_ACCOUNT, Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY,
434                 Directory.PHOTO_SUPPORT_FULL_SIZE_ONLY);
435 
436         mDirectoryManager.scanAllPackages();
437 
438         accounts = new Account[]{new Account("account-name1", "account-type1")};
439         mActor.setAccounts(accounts);
440         ((ContactsProvider2)getProvider()).onAccountsUpdated(accounts);
441 
442         Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
443         assertEquals(3, cursor.getCount());
444 
445         cursor.moveToPosition(2);
446         assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1",
447                 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
448                 Directory.PHOTO_SUPPORT_NONE);
449 
450         cursor.close();
451     }
452 
testNotifyDirectoryChange()453     public void testNotifyDirectoryChange() throws Exception {
454         mPackageManager.setInstalledPackages(
455                 Lists.newArrayList(createProviderPackage("test.package1", "authority1"),
456                         createPackage("test.packageX", "authorityX", false)));
457 
458         MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
459                 MockContactDirectoryProvider.class, "authority1");
460 
461         MatrixCursor response1 = provider1.createResponseCursor();
462         addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
463                 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
464                 Directory.PHOTO_SUPPORT_NONE);
465 
466         mDirectoryManager.scanAllPackages();
467 
468         // Pretend to replace the package with a different provider inside
469         MatrixCursor response2 = provider1.createResponseCursor();
470         addDirectoryRow(response2, "account-name2", "account-type2", "display-name2", 2,
471                 Directory.EXPORT_SUPPORT_ANY_ACCOUNT, Directory.SHORTCUT_SUPPORT_FULL,
472                 Directory.PHOTO_SUPPORT_FULL);
473 
474         ContactsContract.Directory.notifyDirectoryChange(mResolver);
475 
476         Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null);
477         assertEquals(3, cursor.getCount());
478 
479         cursor.moveToPosition(2);
480         assertDirectoryRow(cursor, "test.package1", "authority1", "account-name2", "account-type2",
481                 "display-name2", 2, Directory.EXPORT_SUPPORT_ANY_ACCOUNT,
482                 Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL);
483 
484         cursor.close();
485     }
486 
testForwardingToDirectoryProvider()487     public void testForwardingToDirectoryProvider() throws Exception {
488         mPackageManager.setInstalledPackages(
489                 Lists.newArrayList(createProviderPackage("test.package1", "authority1"),
490                         createPackage("test.packageX", "authorityX", false)));
491 
492         MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
493                 MockContactDirectoryProvider.class, "authority1");
494 
495         MatrixCursor response1 = provider1.createResponseCursor();
496         addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
497                 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
498                 Directory.PHOTO_SUPPORT_NONE);
499 
500         mDirectoryManager.scanAllPackages();
501 
502         Cursor cursor = mResolver.query(
503                 Directory.CONTENT_URI, new String[] { Directory._ID }, null, null, null);
504         cursor.moveToPosition(2);
505         long directoryId = cursor.getLong(0);
506         cursor.close();
507 
508         Uri contentUri = Contacts.CONTENT_URI.buildUpon().appendQueryParameter(
509                 ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
510 
511         // The request should be forwarded to TestProvider, which will simply
512         // package arguments and return them to us for verification
513         cursor = mResolver.query(contentUri,
514                 new String[]{"f1", "f2"}, "query", new String[]{"s1", "s2"}, "so");
515         assertNotNull(cursor);
516         assertEquals(1, cursor.getCount());
517         cursor.moveToFirst();
518         assertEquals("[f1, f2]", cursor.getString(cursor.getColumnIndex("projection")));
519         assertEquals("query", cursor.getString(cursor.getColumnIndex("selection")));
520         assertEquals("[s1, s2]", cursor.getString(cursor.getColumnIndex("selectionArgs")));
521         assertEquals("so", cursor.getString(cursor.getColumnIndex("sortOrder")));
522         assertEquals("account-name1", cursor.getString(cursor.getColumnIndex("accountName")));
523         assertEquals("account-type1", cursor.getString(cursor.getColumnIndex("accountType")));
524         cursor.close();
525     }
526 
testProjectionPopulated()527     public void testProjectionPopulated() throws Exception {
528         mPackageManager.setInstalledPackages(
529                 Lists.newArrayList(createProviderPackage("test.package1", "authority1"),
530                         createPackage("test.packageX", "authorityX", false)));
531 
532         MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider(
533                 MockContactDirectoryProvider.class, "authority1");
534 
535         MatrixCursor response1 = provider1.createResponseCursor();
536         addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1,
537                 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE,
538                 Directory.PHOTO_SUPPORT_NONE);
539 
540         mDirectoryManager.scanAllPackages();
541 
542         Cursor cursor = mResolver.query(
543                 Directory.CONTENT_URI, new String[] { Directory._ID }, null, null, null);
544         cursor.moveToPosition(2);
545         long directoryId = cursor.getLong(0);
546         cursor.close();
547 
548         Uri contentUri = AggregationExceptions.CONTENT_URI.buildUpon().appendQueryParameter(
549                 ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
550 
551         // The request should be forwarded to TestProvider, which will return an empty cursor
552         // but the projection should be correctly populated by ContactProvider
553         assertProjection(contentUri, new String[]{
554                 AggregationExceptionColumns._ID,
555                 AggregationExceptions.TYPE,
556                 AggregationExceptions.RAW_CONTACT_ID1,
557                 AggregationExceptions.RAW_CONTACT_ID2,
558         });
559     }
560 
561     /**
562      * Test {@link ContactDirectoryManager#getDirectoryProviderPackages} with the actual
563      * package manager, and see if it returns the google sync package.
564      */
testGetDirectoryProviderPackages()565     public void testGetDirectoryProviderPackages() {
566         final PackageManager pm = getContext().getPackageManager();
567         final String googleSync = "com.google.android.syncadapters.contacts";
568 
569         // Skip if the package is not installed.
570         try {
571             pm.getPackageInfo(googleSync, 0);
572         } catch (NameNotFoundException e) {
573             Log.w(TAG, googleSync + " not installed.  Skipping...");
574             return;
575         }
576 
577         // If installed, getDirectoryProviderPackages() should return it.
578         assertTrue(ContactDirectoryManager.getDirectoryProviderPackages(pm).contains(googleSync));
579     }
580 
createProviderPackage(String packageName, String authority)581     protected PackageInfo createProviderPackage(String packageName, String authority) {
582         return createPackage(packageName, authority, true);
583     }
584 
createPackage(String packageName, String authority, boolean isDirectoryProvider)585     protected PackageInfo createPackage(String packageName, String authority,
586             boolean isDirectoryProvider) {
587         PackageInfo providerPackage = new PackageInfo();
588         providerPackage.packageName = packageName;
589         ProviderInfo providerInfo = new ProviderInfo();
590         providerInfo.packageName = providerPackage.packageName;
591         providerInfo.authority = authority;
592         if (isDirectoryProvider) {
593             providerInfo.metaData = new Bundle();
594             providerInfo.metaData.putBoolean("android.content.ContactDirectory", true);
595         }
596         providerPackage.providers = new ProviderInfo[] { providerInfo };
597         return providerPackage;
598     }
599 
addDirectoryRow(MatrixCursor cursor, String accountName, String accountType, String displayName, int typeResourceId, int exportSupport, int shortcutSupport, int photoSupport)600     protected void addDirectoryRow(MatrixCursor cursor, String accountName, String accountType,
601             String displayName, int typeResourceId, int exportSupport, int shortcutSupport,
602             int photoSupport) {
603         Object[] row = new Object[cursor.getColumnCount()];
604         row[cursor.getColumnIndex(Directory.ACCOUNT_NAME)] = accountName;
605         row[cursor.getColumnIndex(Directory.ACCOUNT_TYPE)] = accountType;
606         row[cursor.getColumnIndex(Directory.DISPLAY_NAME)] = displayName;
607         row[cursor.getColumnIndex(Directory.TYPE_RESOURCE_ID)] = typeResourceId;
608         row[cursor.getColumnIndex(Directory.EXPORT_SUPPORT)] = exportSupport;
609         row[cursor.getColumnIndex(Directory.SHORTCUT_SUPPORT)] = shortcutSupport;
610         row[cursor.getColumnIndex(Directory.PHOTO_SUPPORT)] = photoSupport;
611         cursor.addRow(row);
612     }
613 
assertDirectoryRow(Cursor cursor, String packageName, String authority, String accountName, String accountType, String displayName, int typeResourceId, int exportSupport, int shortcutSupport, int photoSupport)614     protected void assertDirectoryRow(Cursor cursor, String packageName, String authority,
615             String accountName, String accountType, String displayName, int typeResourceId,
616             int exportSupport, int shortcutSupport, int photoSupport) {
617         ContentValues values = new ContentValues();
618         values.put(Directory.PACKAGE_NAME, packageName);
619         values.put(Directory.DIRECTORY_AUTHORITY, authority);
620         values.put(Directory.ACCOUNT_NAME, accountName);
621         values.put(Directory.ACCOUNT_TYPE, accountType);
622         values.put(Directory.DISPLAY_NAME, displayName);
623         values.put(Directory.TYPE_RESOURCE_ID, typeResourceId);
624         values.put(Directory.EXPORT_SUPPORT, exportSupport);
625         values.put(Directory.SHORTCUT_SUPPORT, shortcutSupport);
626         values.put(Directory.PHOTO_SUPPORT, photoSupport);
627 
628         assertCursorValues(cursor, values);
629     }
630 }
631