diff options
10 files changed, 172 insertions, 98 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2fbc251..4cf0f60 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3,14 +3,6 @@ android:sharedUserId="android.uid.shared" android:sharedUserLabel="@string/sharedUserLabel"> - <permission - android:name="com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL" - android:label="@string/read_write_all_voicemail_label" - android:description="@string/read_write_all_voicemail_description" - android:permissionGroup="android.permission-group.PERSONAL_INFO" - android:protectionLevel="system|signature" - /> - <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> @@ -21,7 +13,8 @@ <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> - <uses-permission android:name="com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL" /> + <uses-permission android:name="com.android.voicemail.permission.READ_ALL_VOICEMAIL" /> + <uses-permission android:name="com.android.voicemail.permission.MANAGE_VOICEMAIL" /> <application android:process="android.process.acore" android:label="@string/app_label" diff --git a/res/values/strings.xml b/res/values/strings.xml index 5291017..c326eee 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -44,14 +44,6 @@ <!-- The name of the invisible local contact directory --> <string name="local_invisible_directory">Other</string> - <!-- Title of an application permission, listed so the user can choose whether they want to - allow the application to do this. [CHAR LIMIT=NONE] --> - <string name="read_write_all_voicemail_label">Access all voicemails</string> - <!-- Description of an application permission, listed so the user can choose whether - they want to allow the application to do this. [CHAR LIMIT=NONE] --> - <string name="read_write_all_voicemail_description">Allows the app to store and retrieve - all voicemails that this device can access.</string> - <!-- The prefix string before the number used for the display name for the voicemail table. Because of the way this is combined in SQL we can't allow a generic format string. The resulting string will be this string with the number appended to the end. diff --git a/src/com/android/providers/contacts/CallLogProvider.java b/src/com/android/providers/contacts/CallLogProvider.java index e3f3520..951555c 100644 --- a/src/com/android/providers/contacts/CallLogProvider.java +++ b/src/com/android/providers/contacts/CallLogProvider.java @@ -230,7 +230,7 @@ public class CallLogProvider extends ContentProvider { // permission and also requires the additional voicemail param set. if (hasVoicemailValue(values)) { checkIsAllowVoicemailRequest(uri); - mVoicemailPermissions.checkCallerHasFullAccess(); + mVoicemailPermissions.checkCallerHasManageAccess(); } if (mCallsInserter == null) { SQLiteDatabase db = mDbHelper.getWritableDatabase(); @@ -331,8 +331,10 @@ public class CallLogProvider extends ContentProvider { private void checkVoicemailPermissionAndAddRestriction(Uri uri, SelectionBuilder selectionBuilder, boolean isQuery) { if (isAllowVoicemailRequest(uri)) { - if (!(isQuery && mVoicemailPermissions.callerHasFullReadAccess())) { - mVoicemailPermissions.checkCallerHasFullAccess(); + if (isQuery) { + mVoicemailPermissions.checkCallerHasFullReadAccess(); + } else { + mVoicemailPermissions.checkCallerHasManageAccess(); } } else { selectionBuilder.addClause(EXCLUDE_VOICEMAIL_SELECTION); diff --git a/src/com/android/providers/contacts/DbModifierWithNotification.java b/src/com/android/providers/contacts/DbModifierWithNotification.java index fda8321..c25e171 100644 --- a/src/com/android/providers/contacts/DbModifierWithNotification.java +++ b/src/com/android/providers/contacts/DbModifierWithNotification.java @@ -18,7 +18,7 @@ package com.android.providers.contacts; import static android.Manifest.permission.ADD_VOICEMAIL; -import static com.android.providers.contacts.Manifest.permission.READ_WRITE_ALL_VOICEMAIL; +import static android.Manifest.permission.READ_ALL_VOICEMAIL; import android.content.ComponentName; import android.content.ContentUris; @@ -210,7 +210,8 @@ public class DbModifierWithNotification implements DatabaseModifier { // Ignore any package that is not affected by the change and don't have full access // either. if (!modifiedPackages.contains(component.getPackageName()) && - !mVoicemailPermissions.packageHasFullAccess(component.getPackageName())) { + !mVoicemailPermissions.packageHasFullReadAccess( + component.getPackageName())) { continue; } @@ -221,7 +222,7 @@ public class DbModifierWithNotification implements DatabaseModifier { callingPackages.contains(component.getPackageName())); } String permissionNeeded = modifiedPackages.contains(component.getPackageName()) ? - ADD_VOICEMAIL : READ_WRITE_ALL_VOICEMAIL; + ADD_VOICEMAIL : READ_ALL_VOICEMAIL; mContext.sendBroadcast(intent, permissionNeeded); Log.v(TAG, String.format("Sent intent. act:%s, url:%s, comp:%s, perm:%s," + " self_change:%s", intent.getAction(), intent.getData(), diff --git a/src/com/android/providers/contacts/VoicemailContentProvider.java b/src/com/android/providers/contacts/VoicemailContentProvider.java index 79e549b..ec5c6ad 100644 --- a/src/com/android/providers/contacts/VoicemailContentProvider.java +++ b/src/com/android/providers/contacts/VoicemailContentProvider.java @@ -99,14 +99,14 @@ public class VoicemailContentProvider extends ContentProvider @Override public Uri insert(Uri uri, ContentValues values) { - UriData uriData = checkPermissionsAndCreateUriData(uri, values); + UriData uriData = checkPermissionsAndCreateUriDataForWrite(uri, values); return getTableDelegate(uriData).insert(uriData, values); } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - UriData uriData = checkPermissionsAndCreateUriDataForReadOperation(uri); + UriData uriData = checkPermissionsAndCreateUriDataForRead(uri); SelectionBuilder selectionBuilder = new SelectionBuilder(selection); selectionBuilder.addClause(getPackageRestrictionClause(true/*isQuery*/)); return getTableDelegate(uriData).query(uriData, projection, selectionBuilder.build(), @@ -115,7 +115,7 @@ public class VoicemailContentProvider extends ContentProvider @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - UriData uriData = checkPermissionsAndCreateUriData(uri, values); + UriData uriData = checkPermissionsAndCreateUriDataForWrite(uri, values); SelectionBuilder selectionBuilder = new SelectionBuilder(selection); selectionBuilder.addClause(getPackageRestrictionClause(false/*isQuery*/)); return getTableDelegate(uriData).update(uriData, values, selectionBuilder.build(), @@ -124,7 +124,7 @@ public class VoicemailContentProvider extends ContentProvider @Override public int delete(Uri uri, String selection, String[] selectionArgs) { - UriData uriData = checkPermissionsAndCreateUriData(uri); + UriData uriData = checkPermissionsAndCreateUriDataForWrite(uri); SelectionBuilder selectionBuilder = new SelectionBuilder(selection); selectionBuilder.addClause(getPackageRestrictionClause(false/*isQuery*/)); return getTableDelegate(uriData).delete(uriData, selectionBuilder.build(), selectionArgs); @@ -134,9 +134,9 @@ public class VoicemailContentProvider extends ContentProvider public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { UriData uriData = null; if (mode.equals("r")) { - uriData = checkPermissionsAndCreateUriDataForReadOperation(uri); + uriData = checkPermissionsAndCreateUriDataForRead(uri); } else { - uriData = checkPermissionsAndCreateUriData(uri); + uriData = checkPermissionsAndCreateUriDataForWrite(uri); } // openFileHelper() relies on "_data" column to be populated with the file path. return getTableDelegate(uriData).openFile(uriData, mode); @@ -247,8 +247,9 @@ public class VoicemailContentProvider extends ContentProvider uriData.getSourcePackage() : getCallingPackage_(); values.put(SOURCE_PACKAGE_FIELD, provider); } + // You must have access to the provider given in values. - if (!mVoicemailPermissions.callerHasFullAccess()) { + if (!mVoicemailPermissions.callerHasManageAccess()) { checkPackagesMatch(getCallingPackage_(), values.getAsString(VoicemailContract.SOURCE_PACKAGE_FIELD), uriData.getUri()); @@ -278,10 +279,10 @@ public class VoicemailContentProvider extends ContentProvider } /** - * Performs necessary voicemail permission checks common to all operations and returns - * the structured representation, {@link UriData}, of the supplied uri. + * Ensures that the caller has the permissions to perform a query/read operation, and + * then returns the structured representation {@link UriData} of the supplied uri. */ - private UriData checkPermissionsAndCreateUriDataForReadOperation(Uri uri) { + private UriData checkPermissionsAndCreateUriDataForRead(Uri uri) { // If the caller has been explicitly granted read permission to this URI then no need to // check further. if (context().checkCallingUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) @@ -293,26 +294,29 @@ public class VoicemailContentProvider extends ContentProvider return UriData.createUriData(uri); } - return checkPermissionsAndCreateUriData(uri); + return checkPermissionsAndCreateUriData(uri, true); } /** * Performs necessary voicemail permission checks common to all operations and returns * the structured representation, {@link UriData}, of the supplied uri. */ - private UriData checkPermissionsAndCreateUriData(Uri uri) { - mVoicemailPermissions.checkCallerHasOwnVoicemailAccess(); + private UriData checkPermissionsAndCreateUriData(Uri uri, boolean read) { UriData uriData = UriData.createUriData(uri); - checkPackagePermission(uriData); + if (!hasReadWritePermission(read)) { + mVoicemailPermissions.checkCallerHasOwnVoicemailAccess(); + checkPackagePermission(uriData); + } return uriData; } /** - * Same as {@link #checkPackagePermission(UriData)}. In addition does permission check - * on the ContentValues. + * Ensures that the caller has the permissions to perform an update/delete operation, and + * then returns the structured representation {@link UriData} of the supplied uri. + * Also does a permission check on the ContentValues. */ - private UriData checkPermissionsAndCreateUriData(Uri uri, ContentValues... valuesArray) { - UriData uriData = checkPermissionsAndCreateUriData(uri); + private UriData checkPermissionsAndCreateUriDataForWrite(Uri uri, ContentValues... valuesArray) { + UriData uriData = checkPermissionsAndCreateUriData(uri, false); for (ContentValues values : valuesArray) { checkSourcePackageSameIfSet(uriData, values); } @@ -329,13 +333,13 @@ public class VoicemailContentProvider extends ContentProvider String errorMsg = String.format("Permission denied for URI: %s\n. " + "Package %s cannot perform this operation for %s. Requires %s permission.", uri, callingPackage, voicemailSourcePackage, - Manifest.permission.READ_WRITE_ALL_VOICEMAIL); + android.Manifest.permission.MANAGE_VOICEMAIL); throw new SecurityException(errorMsg); } } /** - * Checks that either the caller has READ_WRITE_ALL_VOICEMAIL permission, + * Checks that either the caller has the MANAGE_VOICEMAIL permission, * or has the ADD_VOICEMAIL permission and is using a URI that matches * /voicemail/?source_package=[source-package] where [source-package] is the same as the calling * package. @@ -343,13 +347,13 @@ public class VoicemailContentProvider extends ContentProvider * @throws SecurityException if the check fails. */ private void checkPackagePermission(UriData uriData) { - if (!mVoicemailPermissions.callerHasFullAccess()) { + if (!mVoicemailPermissions.callerHasManageAccess()) { if (!uriData.hasSourcePackage()) { // You cannot have a match if this is not a provider URI. throw new SecurityException(String.format( "Provider %s does not have %s permission." + "\nPlease set query parameter '%s' in the URI.\nURI: %s", - getCallingPackage_(), Manifest.permission.READ_WRITE_ALL_VOICEMAIL, + getCallingPackage_(), android.Manifest.permission.MANAGE_VOICEMAIL, VoicemailContract.PARAM_KEY_SOURCE_PACKAGE, uriData.getUri())); } checkPackagesMatch(getCallingPackage_(), uriData.getSourcePackage(), uriData.getUri()); @@ -381,7 +385,7 @@ public class VoicemailContentProvider extends ContentProvider // which one we return. String bestSoFar = callerPackages[0]; for (String callerPackage : callerPackages) { - if (mVoicemailPermissions.packageHasFullAccess(callerPackage)) { + if (mVoicemailPermissions.packageHasManageAccess(callerPackage)) { // Full always wins, we can return early. return callerPackage; } @@ -397,12 +401,21 @@ public class VoicemailContentProvider extends ContentProvider * access to all data. */ private String getPackageRestrictionClause(boolean isQuery) { - if (isQuery && mVoicemailPermissions.callerHasFullReadAccess()) { - return null; - } - if (mVoicemailPermissions.callerHasFullAccess()) { + if (hasReadWritePermission(isQuery)) { return null; } return getEqualityClause(Voicemails.SOURCE_PACKAGE, getCallingPackage_()); } + + /** + * Whether or not the calling package has the appropriate read/write permission + * + * @param read Whether or not this operation is a read + * + * @return True if the package has the permission required to perform the read/write operation + */ + private boolean hasReadWritePermission(boolean read) { + return read ? mVoicemailPermissions.callerHasFullReadAccess() : + mVoicemailPermissions.callerHasManageAccess(); + } } diff --git a/src/com/android/providers/contacts/VoicemailPermissions.java b/src/com/android/providers/contacts/VoicemailPermissions.java index 570399c..b32f79c 100644 --- a/src/com/android/providers/contacts/VoicemailPermissions.java +++ b/src/com/android/providers/contacts/VoicemailPermissions.java @@ -36,16 +36,15 @@ public class VoicemailPermissions { return callerHasPermission(android.Manifest.permission.ADD_VOICEMAIL); } - /** Determine if the calling process has full read access to all voicemails. */ public boolean callerHasFullReadAccess() { return callerHasPermission(android.Manifest.permission.READ_ALL_VOICEMAIL); } - /** Determines if the calling process has access to all voicemails. */ - public boolean callerHasFullAccess() { - return callerHasOwnVoicemailAccess() && - callerHasPermission(Manifest.permission.READ_WRITE_ALL_VOICEMAIL); + /** Determine if the calling process has the permission required to update and remove all + * voicemails */ + public boolean callerHasManageAccess() { + return callerHasPermission(android.Manifest.permission.MANAGE_VOICEMAIL); } /** @@ -72,16 +71,10 @@ public class VoicemailPermissions { } } - /** - * Checks that the caller has permissions to access ALL voicemails. - * - * @throws SecurityException if the caller does not have the voicemail source permission. - */ - public void checkCallerHasFullAccess() { - if (!callerHasFullAccess()) { - throw new SecurityException(String.format("The caller must have permissions %s AND %s", - android.Manifest.permission.ADD_VOICEMAIL, - Manifest.permission.READ_WRITE_ALL_VOICEMAIL)); + public void checkCallerHasManageAccess() { + if (!callerHasManageAccess()) { + throw new SecurityException(String.format("The caller must have %s permission: ", + android.Manifest.permission.MANAGE_VOICEMAIL)); } } @@ -96,26 +89,19 @@ public class VoicemailPermissions { return packageHasPermission(packageName, android.Manifest.permission.READ_ALL_VOICEMAIL); } - /** Determines if the given package has full access. */ - public boolean packageHasFullAccess(String packageName) { - return packageHasOwnVoicemailAccess(packageName) && - packageHasPermission(packageName, Manifest.permission.READ_WRITE_ALL_VOICEMAIL); + /** Determines if the given package has manage access. */ + public boolean packageHasManageAccess(String packageName) { + return packageHasPermission(packageName, android.Manifest.permission.MANAGE_VOICEMAIL); } /** Determines if the given package has the given permission. */ private boolean packageHasPermission(String packageName, String permission) { return mContext.getPackageManager().checkPermission(permission, packageName) - == PackageManager.PERMISSION_GRANTED; + == PackageManager.PERMISSION_GRANTED; } /** Determines if the calling process has the given permission. */ private boolean callerHasPermission(String permission) { - // We need to check against both the calling or self permission in order for the Contacts - // app to be allowed access. - // The reason is that the Contacts app shares its process with the ContactsProvider and - // therefore its requests are not considered to be IPCs, since they are coming from the same - // process, even if, technically, from a different package. - return mContext.checkCallingOrSelfPermission(permission) - == PackageManager.PERMISSION_GRANTED; + return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED; } } diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java index 512455b..45af26c 100644 --- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java +++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java @@ -79,6 +79,19 @@ import java.util.Set; */ public abstract class BaseContactsProvider2Test extends PhotoLoadingTestCase { + static final String ADD_VOICEMAIL_PERMISSION = + "com.android.voicemail.permission.ADD_VOICEMAIL"; + /* + * Permission to allow querying voicemails + */ + static final String READ_ALL_VOICEMAIL_PERMISSION = + "com.android.voicemail.permission.READ_ALL_VOICEMAIL"; + /* + * Permission to allow deleting and updating voicemails + */ + static final String MANAGE_VOICEMAIL_PERMISSION = + "com.android.voicemail.permission.MANAGE_VOICEMAIL"; + protected static final String PACKAGE = "ContactsProvider2Test"; public static final String READ_ONLY_ACCOUNT_TYPE = SynchronousContactsProvider2.READ_ONLY_ACCOUNT_TYPE; diff --git a/tests/src/com/android/providers/contacts/BaseVoicemailProviderTest.java b/tests/src/com/android/providers/contacts/BaseVoicemailProviderTest.java index 5f02e3f..9373dc0 100644 --- a/tests/src/com/android/providers/contacts/BaseVoicemailProviderTest.java +++ b/tests/src/com/android/providers/contacts/BaseVoicemailProviderTest.java @@ -34,10 +34,6 @@ import java.util.List; * Base class for all tests that require interacting with the voicemail content provider. */ public class BaseVoicemailProviderTest extends BaseContactsProvider2Test { - private static final String READ_WRITE_ALL_PERMISSION = - "com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL"; - private static final String ADD_VOICEMAIL_PERMISSION = - "com.android.voicemail.permission.ADD_VOICEMAIL"; protected boolean mUseSourceUri = false; private File mTestDirectory; @@ -66,21 +62,23 @@ public class BaseVoicemailProviderTest extends BaseContactsProvider2Test { } protected void setUpForOwnPermission() { - // Give away full permission, in case it was granted previously. - mActor.removePermissions(READ_WRITE_ALL_PERMISSION); + mActor.removePermissions(READ_ALL_VOICEMAIL_PERMISSION); + mActor.removePermissions(MANAGE_VOICEMAIL_PERMISSION); mActor.addPermissions(ADD_VOICEMAIL_PERMISSION); mUseSourceUri = true; } protected void setUpForFullPermission() { mActor.addPermissions(ADD_VOICEMAIL_PERMISSION); - mActor.addPermissions(READ_WRITE_ALL_PERMISSION); + mActor.addPermissions(READ_ALL_VOICEMAIL_PERMISSION); + mActor.addPermissions(MANAGE_VOICEMAIL_PERMISSION); mUseSourceUri = false; } protected void setUpForNoPermission() { mActor.removePermissions(ADD_VOICEMAIL_PERMISSION); - mActor.removePermissions(READ_WRITE_ALL_PERMISSION); + mActor.removePermissions(READ_ALL_VOICEMAIL_PERMISSION); + mActor.removePermissions(MANAGE_VOICEMAIL_PERMISSION); mUseSourceUri = true; } diff --git a/tests/src/com/android/providers/contacts/CallLogProviderTest.java b/tests/src/com/android/providers/contacts/CallLogProviderTest.java index 072b572..2d11dc4 100644 --- a/tests/src/com/android/providers/contacts/CallLogProviderTest.java +++ b/tests/src/com/android/providers/contacts/CallLogProviderTest.java @@ -52,11 +52,6 @@ import java.util.List; */ @MediumTest public class CallLogProviderTest extends BaseContactsProvider2Test { - private static final String READ_WRITE_ALL_PERMISSION = - "com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL"; - private static final String ADD_VOICEMAIL_PERMISSION = - "com.android.voicemail.permission.ADD_VOICEMAIL"; - /** Fields specific to voicemail provider that should not be exposed by call_log*/ private static final String[] VOICEMAIL_PROVIDER_SPECIFIC_COLUMNS = new String[] { Voicemails._DATA, @@ -101,12 +96,8 @@ public class CallLogProviderTest extends BaseContactsProvider2Test { private void setUpWithVoicemailPermissions() { mActor.addPermissions(ADD_VOICEMAIL_PERMISSION); - mActor.addPermissions(READ_WRITE_ALL_PERMISSION); - } - - private void setUpWithNoVoicemailPermissions() { - mActor.removePermissions(ADD_VOICEMAIL_PERMISSION); - mActor.removePermissions(READ_WRITE_ALL_PERMISSION); + mActor.addPermissions(READ_ALL_VOICEMAIL_PERMISSION); + mActor.addPermissions(MANAGE_VOICEMAIL_PERMISSION); } public void testInsert_VoicemailCallRecord() { @@ -349,7 +340,13 @@ public class CallLogProviderTest extends BaseContactsProvider2Test { null, null); } }); - // Should now succeed with permissions granted. + + // Should succeed with manage permission granted + mActor.addPermissions(MANAGE_VOICEMAIL_PERMISSION); + mResolver.update(Calls.CONTENT_URI_WITH_VOICEMAIL, getDefaultCallValues(), null, null); + mActor.removePermissions(MANAGE_VOICEMAIL_PERMISSION); + + // Should also succeed with full permissions granted. setUpWithVoicemailPermissions(); mResolver.update(Calls.CONTENT_URI_WITH_VOICEMAIL, getDefaultCallValues(), null, null); } @@ -361,7 +358,13 @@ public class CallLogProviderTest extends BaseContactsProvider2Test { mResolver.query(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null, null, null); } }); - // Should now succeed with permissions granted. + + // Should succeed with read_all permission granted + mActor.addPermissions(READ_ALL_VOICEMAIL_PERMISSION); + mResolver.query(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null, null, null); + mActor.removePermissions(READ_ALL_VOICEMAIL_PERMISSION); + + // Should also succeed with full permissions granted. setUpWithVoicemailPermissions(); mResolver.query(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null, null, null); } @@ -373,6 +376,12 @@ public class CallLogProviderTest extends BaseContactsProvider2Test { mResolver.delete(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null); } }); + + // Should succeed with manage permission granted + mActor.addPermissions(MANAGE_VOICEMAIL_PERMISSION); + mResolver.delete(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null); + mActor.removePermissions(MANAGE_VOICEMAIL_PERMISSION); + // Should now succeed with permissions granted. setUpWithVoicemailPermissions(); mResolver.delete(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null); diff --git a/tests/src/com/android/providers/contacts/VoicemailProviderTest.java b/tests/src/com/android/providers/contacts/VoicemailProviderTest.java index 8fdbccf..451d1ac 100644 --- a/tests/src/com/android/providers/contacts/VoicemailProviderTest.java +++ b/tests/src/com/android/providers/contacts/VoicemailProviderTest.java @@ -195,6 +195,20 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest { insertVoicemailForSourcePackage("another-package"); } }); + + setUpForNoPermission(); + mUseSourceUri = false; + // With the READ_ALL_VOICEMAIL permission, we should now be able to read all voicemails + mActor.addPermissions(READ_ALL_VOICEMAIL_PERMISSION); + assertEquals(2, getCount(voicemailUri(), null, null)); + + // An insert for another package should still fail + EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { + @Override + public void run() { + insertVoicemailForSourcePackage("another-package"); + } + }); } public void testPermissions_UpdateAndDelete() { @@ -224,6 +238,25 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest { mResolver.delete(anotherVoicemail, null, null); } }); + + // If we have the manage voicemail permission, we should be able to both update and delete + // voicemails from all packages + setUpForNoPermission(); + mActor.addPermissions(MANAGE_VOICEMAIL_PERMISSION); + mResolver.update(anotherVoicemail, getTestVoicemailValues(), null, null); + + // Now add the read voicemail permission temporarily to verify that the update actually + // worked + mActor.addPermissions(READ_ALL_VOICEMAIL_PERMISSION); + assertStoredValues(anotherVoicemail, getTestVoicemailValues()); + mActor.removePermissions(READ_ALL_VOICEMAIL_PERMISSION); + + mResolver.delete(anotherVoicemail, null, null); + + // Now add the read voicemail permission temporarily to verify that the delete actually + // worked + mActor.addPermissions(READ_ALL_VOICEMAIL_PERMISSION); + assertEquals(0, getCount(anotherVoicemail, null, null)); } private Uri withSourcePackageParam(Uri uri) { @@ -250,6 +283,35 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest { mActor.removeUriPermissions(uri1); } + /* + * Checks that the READ_ALL_VOICEMAIL permission provides read access to a uri. + */ + public void testUriPermissions_ReadAccess() { + setUpForFullPermission(); + final Uri uri1 = insertVoicemail(); + // Give away all permissions before querying. Access should be denied. + setUpForNoPermission(); + mUseSourceUri = false; + checkHasNoAccessToUri(uri1); + + mActor.addPermissions(READ_ALL_VOICEMAIL_PERMISSION); + checkHasReadAccessToUri(uri1); + } + + /* + * Checks that the MANAGE_VOICEMAIL permission provides write access to a uri. + */ + public void testUriPermissions_WriteAccess() { + setUpForFullPermission(); + final Uri uri1 = insertVoicemail(); + // Give away all permissions before querying. Access should be denied. + setUpForNoPermission(); + checkHasNoAccessToUri(uri1); + + mActor.addPermissions(MANAGE_VOICEMAIL_PERMISSION); + checkHasUpdateAndDeleteAccessToUri(uri1); + } + private void checkHasNoAccessToUri(final Uri uri) { checkHasNoReadAccessToUri(uri); checkHasNoWriteAccessToUri(uri); @@ -298,6 +360,11 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest { }); } + private void checkHasUpdateAndDeleteAccessToUri(final Uri uri) { + mResolver.update(uri, getTestVoicemailValues(), null, null); + mResolver.delete(uri, null, null); + } + private void checkHasNoWriteAccessToUri(final Uri uri) { EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { @Override |