Home | History | Annotate | Download | only in contacts
      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 com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns;
     20 import com.google.android.collect.Lists;
     21 
     22 import android.accounts.Account;
     23 import android.content.ContentValues;
     24 import android.content.Context;
     25 import android.content.pm.PackageInfo;
     26 import android.content.pm.PackageManager;
     27 import android.content.pm.PackageManager.NameNotFoundException;
     28 import android.content.pm.ProviderInfo;
     29 import android.database.Cursor;
     30 import android.database.MatrixCursor;
     31 import android.net.Uri;
     32 import android.os.Bundle;
     33 import android.provider.ContactsContract;
     34 import android.provider.ContactsContract.AggregationExceptions;
     35 import android.provider.ContactsContract.Contacts;
     36 import android.provider.ContactsContract.Directory;
     37 import android.provider.ContactsContract.RawContacts;
     38 import android.test.mock.MockContentProvider;
     39 import android.test.suitebuilder.annotation.MediumTest;
     40 import android.util.Log;
     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
     66         public void attachInfo(Context context, ProviderInfo info) {
     67             mAuthority = info.authority;
     68         }
     69 
     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
     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
    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 
    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 
    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 
    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 
    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 
    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      */
    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 
    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 
    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 
    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 
    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      */
    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 
    581     protected PackageInfo createProviderPackage(String packageName, String authority) {
    582         return createPackage(packageName, authority, true);
    583     }
    584 
    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 
    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 
    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