Fix canCurrentUserBlockUsers API for secondary users.

canCurrentUserBlockUsers should return gracefully for privileged apps instead of throwing UnsupportedOperationException.

BUG: 27596508

Change-Id: I74310c7aeb4e2b3247014438b3e457777871a50c
diff --git a/src/com/android/providers/blockednumber/BlockedNumberProvider.java b/src/com/android/providers/blockednumber/BlockedNumberProvider.java
index 69337cd..837a35a 100644
--- a/src/com/android/providers/blockednumber/BlockedNumberProvider.java
+++ b/src/com/android/providers/blockednumber/BlockedNumberProvider.java
@@ -109,7 +109,7 @@
 
     @Override
     public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
-        enforceWritePermission();
+        enforceWritePermissionAndPrimaryUser();
 
         final int match = sUriMatcher.match(uri);
         switch (match) {
@@ -161,7 +161,7 @@
     @Override
     public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
             @Nullable String[] selectionArgs) {
-        enforceWritePermission();
+        enforceWritePermissionAndPrimaryUser();
 
         throw new UnsupportedOperationException(
                 "Update is not supported.  Use delete + insert instead");
@@ -170,7 +170,7 @@
     @Override
     public int delete(@NonNull Uri uri, @Nullable String selection,
             @Nullable String[] selectionArgs) {
-        enforceWritePermission();
+        enforceWritePermissionAndPrimaryUser();
 
         final int match = sUriMatcher.match(uri);
         int numRows;
@@ -218,7 +218,7 @@
     @Override
     public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
             @Nullable String[] selectionArgs, @Nullable String sortOrder) {
-        enforceReadPermission();
+        enforceReadPermissionAndPrimaryUser();
 
         return query(uri, projection, selection, selectionArgs, sortOrder, null);
     }
@@ -227,7 +227,7 @@
     public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
             @Nullable String[] selectionArgs, @Nullable String sortOrder,
             @Nullable CancellationSignal cancellationSignal) {
-        enforceReadPermission();
+        enforceReadPermissionAndPrimaryUser();
 
         final int match = sUriMatcher.match(uri);
         Cursor cursor;
@@ -286,7 +286,7 @@
         final Bundle res = new Bundle();
         switch (method) {
             case BlockedNumberContract.METHOD_IS_BLOCKED:
-                enforceReadPermission();
+                enforceReadPermissionAndPrimaryUser();
 
                 res.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, isBlocked(arg));
                 break;
@@ -297,17 +297,17 @@
                         BlockedNumberContract.RES_CAN_BLOCK_NUMBERS, canCurrentUserBlockUsers());
                 break;
             case SystemContract.METHOD_NOTIFY_EMERGENCY_CONTACT:
-                enforceSystemWritePermission();
+                enforceSystemWritePermissionAndPrimaryUser();
 
                 notifyEmergencyContact();
                 break;
             case SystemContract.METHOD_END_BLOCK_SUPPRESSION:
-                enforceSystemWritePermission();
+                enforceSystemWritePermissionAndPrimaryUser();
 
                 endBlockSuppression();
                 break;
             case SystemContract.METHOD_GET_BLOCK_SUPPRESSION_STATUS:
-                enforceSystemReadPermission();
+                enforceSystemReadPermissionAndPrimaryUser();
 
                 SystemContract.BlockSuppressionStatus status = getBlockSuppressionStatus();
                 res.putBoolean(SystemContract.RES_IS_BLOCKING_SUPPRESSED, status.isSuppressed);
@@ -315,12 +315,12 @@
                         status.untilTimestampMillis);
                 break;
             case SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER:
-                enforceSystemReadPermission();
+                enforceSystemReadPermissionAndPrimaryUser();
                 res.putBoolean(
                         BlockedNumberContract.RES_NUMBER_IS_BLOCKED, shouldSystemBlockNumber(arg));
                 break;
             default:
-                enforceReadPermission();
+                enforceReadPermissionAndPrimaryUser();
 
                 throw new IllegalArgumentException("Unsupported method " + method);
         }
@@ -471,15 +471,22 @@
         checkForPermission(android.Manifest.permission.READ_BLOCKED_NUMBERS);
     }
 
-    private void enforceWritePermission() {
-        checkForPermission(android.Manifest.permission.WRITE_BLOCKED_NUMBERS);
+    private void enforceReadPermissionAndPrimaryUser() {
+        checkForPermissionAndPrimaryUser(android.Manifest.permission.READ_BLOCKED_NUMBERS);
     }
 
-    private void checkForPermission(String permission) {
+    private void enforceWritePermissionAndPrimaryUser() {
+        checkForPermissionAndPrimaryUser(android.Manifest.permission.WRITE_BLOCKED_NUMBERS);
+    }
+
+    private void checkForPermissionAndPrimaryUser(String permission) {
+        checkForPermission(permission);
         if (!canCurrentUserBlockUsers()) {
             throw new UnsupportedOperationException();
         }
+    }
 
+    private void checkForPermission(String permission) {
         boolean permitted = passesSystemPermissionCheck(permission)
                 || checkForPrivilegedApplications();
         if (!permitted) {
@@ -487,15 +494,15 @@
         }
     }
 
-    private void enforceSystemReadPermission() {
-        enforceSystemPermission(android.Manifest.permission.READ_BLOCKED_NUMBERS);
+    private void enforceSystemReadPermissionAndPrimaryUser() {
+        enforceSystemPermissionAndUser(android.Manifest.permission.READ_BLOCKED_NUMBERS);
     }
 
-    private void enforceSystemWritePermission() {
-        enforceSystemPermission(android.Manifest.permission.WRITE_BLOCKED_NUMBERS);
+    private void enforceSystemWritePermissionAndPrimaryUser() {
+        enforceSystemPermissionAndUser(android.Manifest.permission.WRITE_BLOCKED_NUMBERS);
     }
 
-    private void enforceSystemPermission(String permission) {
+    private void enforceSystemPermissionAndUser(String permission) {
         if (!canCurrentUserBlockUsers()) {
             throw new UnsupportedOperationException();
         }
diff --git a/tests/src/com/android/providers/blockednumber/BlockedNumberProviderTest.java b/tests/src/com/android/providers/blockednumber/BlockedNumberProviderTest.java
index 6839925..de6a096 100644
--- a/tests/src/com/android/providers/blockednumber/BlockedNumberProviderTest.java
+++ b/tests/src/com/android/providers/blockednumber/BlockedNumberProviderTest.java
@@ -447,6 +447,8 @@
     }
 
     public void testIsBlocked() {
+        assertTrue(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
+
         // Prepare test data
         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1.2-3"));
@@ -487,6 +489,73 @@
         assertFalse(SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber));
     }
 
+    public void testPrivilegedAppAccessingApisAsSecondaryUser() {
+        when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(false);
+
+        assertFalse(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
+
+        try {
+            insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
+            fail("UnsupportedOperationException expected");
+        } catch (UnsupportedOperationException expected) {
+        }
+
+        try {
+            mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
+            fail("UnsupportedOperationException expected");
+        } catch (UnsupportedOperationException expected) {
+        }
+
+        try {
+            mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
+            fail("UnsupportedOperationException expected");
+        } catch (UnsupportedOperationException expected) {
+        }
+
+        try {
+            BlockedNumberContract.isBlocked(mMockContext, "123");
+            fail("UnsupportedOperationException expected");
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    public void testRegularAppAccessingApisAsSecondaryUser() {
+        when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(false);
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mMockContext).checkCallingPermission(anyString());
+
+        try {
+            BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext);
+            fail("SecurityException expected");
+        } catch (SecurityException expected) {
+        }
+
+
+        try {
+            insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
+            fail("SecurityException expected");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
+            fail("SecurityException expected");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
+            fail("SecurityException expected");
+        } catch (SecurityException expected) {
+        }
+
+        try {
+            BlockedNumberContract.isBlocked(mMockContext, "123");
+            fail("SecurityException expected");
+        } catch (SecurityException expected) {
+        }
+    }
+
     private void assertIsBlocked(boolean expected, String phoneNumber) {
         assertEquals(expected, BlockedNumberContract.isBlocked(mMockContext, phoneNumber));
     }