diff options
-rw-r--r-- | src/com/android/providers/contacts/ContactDirectoryManager.java | 41 | ||||
-rw-r--r-- | tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java | 68 |
2 files changed, 105 insertions, 4 deletions
diff --git a/src/com/android/providers/contacts/ContactDirectoryManager.java b/src/com/android/providers/contacts/ContactDirectoryManager.java index c014105..f2c8422 100644 --- a/src/com/android/providers/contacts/ContactDirectoryManager.java +++ b/src/com/android/providers/contacts/ContactDirectoryManager.java @@ -195,12 +195,44 @@ public class ContactDirectoryManager { List<PackageInfo> packages = pm.getInstalledPackages( PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA); if (packages != null) { + // Prepare query strings for removing stale rows which don't correspond to existing + // directories. + StringBuilder deleteWhereBuilder = new StringBuilder(); + ArrayList<String> deleteWhereArgs = new ArrayList<String>(); + deleteWhereBuilder.append("NOT (" + Directory._ID + "=? OR " + Directory._ID + "=?"); + deleteWhereArgs.add(String.valueOf(Directory.DEFAULT)); + deleteWhereArgs.add(String.valueOf(Directory.LOCAL_INVISIBLE)); + final String wherePart = "(" + Directory.PACKAGE_NAME + "=? AND " + + Directory.DIRECTORY_AUTHORITY + "=? AND " + + Directory.ACCOUNT_NAME + "=? AND " + + Directory.ACCOUNT_TYPE + "=?)"; + for (PackageInfo packageInfo : packages) { // Check all packages except the one containing ContactsProvider itself if (!packageInfo.packageName.equals(mContext.getPackageName())) { - count += updateDirectoriesForPackage(packageInfo, true); + List<DirectoryInfo> directories = + updateDirectoriesForPackage(packageInfo, true); + if (directories != null && !directories.isEmpty()) { + count += directories.size(); + + // We shouldn't delete rows for existing directories. + for (DirectoryInfo info : directories) { + deleteWhereBuilder.append(" OR "); + deleteWhereBuilder.append(wherePart); + deleteWhereArgs.add(info.packageName); + deleteWhereArgs.add(info.authority); + deleteWhereArgs.add(info.accountName); + deleteWhereArgs.add(info.accountType); + } + } } } + + deleteWhereBuilder.append(")"); // Close "NOT (" + int deletedRows = db.delete(Tables.DIRECTORIES, deleteWhereBuilder.toString(), + deleteWhereArgs.toArray(new String[0])); + Log.i(TAG, "deleted " + deletedRows + + " stale rows which don't have any relevant directory"); } return count; } @@ -258,7 +290,8 @@ public class ContactDirectoryManager { * Scans the specified package for content directories and updates the {@link Directory} * table accordingly. */ - private int updateDirectoriesForPackage(PackageInfo packageInfo, boolean initialScan) { + private List<DirectoryInfo> updateDirectoriesForPackage( + PackageInfo packageInfo, boolean initialScan) { ArrayList<DirectoryInfo> directories = Lists.newArrayList(); ProviderInfo[] providers = packageInfo.providers; @@ -275,7 +308,7 @@ public class ContactDirectoryManager { } if (directories.size() == 0 && initialScan) { - return 0; + return null; } SQLiteDatabase db = getDbHelper().getWritableDatabase(); @@ -299,7 +332,7 @@ public class ContactDirectoryManager { } mContactsProvider.resetDirectoryCache(); - return directories.size(); + return directories; } /** diff --git a/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java b/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java index 9ebc3d9..a0941a3 100644 --- a/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java +++ b/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java @@ -78,6 +78,8 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { String sortOrder) { if (uri.toString().equals("content://" + mAuthority + "/directories")) { + // Should tolerate multiple queries. + mResponse.moveToPosition(-1); return mResponse; } else if (uri.toString().startsWith("content://" + mAuthority + "/contacts")) { MatrixCursor cursor = new MatrixCursor( @@ -309,6 +311,72 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + /** + * Tests if the manager works correctly when the package name for a directory is changed + * (on system update). + */ + public void testPackageRenamed() throws Exception { + mPackageManager.setInstalledPackages( + Lists.newArrayList( + createProviderPackage("test.package1", "authority1"), + createProviderPackage("test.package2", "authority2"))); + + MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( + MockContactDirectoryProvider.class, "authority1"); + + MatrixCursor response1 = provider1.createResponseCursor(); + addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, + Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, + Directory.PHOTO_SUPPORT_NONE); + + MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider( + MockContactDirectoryProvider.class, "authority2"); + + MatrixCursor response2 = provider2.createResponseCursor(); + addDirectoryRow(response2, "account-name2", "account-type2", "display-name2", 2, + Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL, + Directory.PHOTO_SUPPORT_FULL); + + mDirectoryManager.scanAllPackages(); + + // At this point the manager has discovered two custom directories. + Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); + assertEquals(4, cursor.getCount()); + cursor.close(); + + // Pretend to rename the package name of a package on system update. + PackageInfo info = mPackageManager.getInstalledPackages(0).get(1); + info.packageName = "test.package3"; + info.providers[0].packageName = "test.package3"; + MatrixCursor response3 = provider2.createResponseCursor(); + // Change resource id. + addDirectoryRow(response3, "account-name2", "account-type2", "display-name2", 3, + Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL, + Directory.PHOTO_SUPPORT_FULL); + + // When this happens on reboot, scanAllPackages() is called instead of onPackageChanged() + // (as part of ContactsProvider2 initialization). + // Accounts won't be affected so false should be passed here. + mDirectoryManager.scanAllPackages(false); + + cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); + // We should have columns for default, local_invisible, test.package1, and test.package3. + // The row for test.package2 should not remain. + assertEquals(4, cursor.getCount()); + + cursor.moveToPosition(2); + assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1", + "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, + Directory.PHOTO_SUPPORT_NONE); + + cursor.moveToNext(); + assertDirectoryRow(cursor, "test.package3", "authority2", "account-name2", "account-type2", + "display-name2", 3, Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, + Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); + + cursor.close(); + } + public void testAccountRemoval() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( |