Merge "Add the enterprise caller-id API"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e335e40..58eab25 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" />
@@ -22,7 +14,8 @@
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <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 7295dc4..a4e642c 100644
--- a/src/com/android/providers/contacts/CallLogProvider.java
+++ b/src/com/android/providers/contacts/CallLogProvider.java
@@ -230,7 +230,7 @@
         // 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 @@
     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 @@
                 // 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 @@
                             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 @@
 
     @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 @@
 
     @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 @@
 
     @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 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 @@
                     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 @@
     }
 
     /**
-     * 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 @@
             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 @@
             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 @@
      * @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 @@
         // 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 @@
      * 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..5a26443 100644
--- a/src/com/android/providers/contacts/VoicemailPermissions.java
+++ b/src/com/android/providers/contacts/VoicemailPermissions.java
@@ -36,16 +36,15 @@
         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 @@
         }
     }
 
-     /**
-     * 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,25 +89,19 @@
         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;
     }
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 @@
  */
 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 @@
  * 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 @@
     }
 
     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 f0540ee..6a9410f 100644
--- a/tests/src/com/android/providers/contacts/CallLogProviderTest.java
+++ b/tests/src/com/android/providers/contacts/CallLogProviderTest.java
@@ -51,11 +51,6 @@
  */
 @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,
@@ -100,12 +95,8 @@
 
     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() {
@@ -348,7 +339,13 @@
                         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);
     }
@@ -360,7 +357,13 @@
                 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);
     }
@@ -372,6 +375,12 @@
                 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 @@
                 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 @@
                 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 @@
         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 @@
         });
     }
 
+    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