Merge "TelecomManager#placeCall needs to support CALL_PRIVILEGED permission" into udc-dev
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 99a8d3d..ca42b57 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -1811,14 +1811,14 @@
                         Binder.getCallingUid(), callingPackage, callingFeatureId, null)
                         == AppOpsManager.MODE_ALLOWED;
 
-                final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==
-                        PackageManager.PERMISSION_GRANTED;
+                final boolean hasCallPermission = mContext.checkCallingOrSelfPermission(CALL_PHONE)
+                        == PackageManager.PERMISSION_GRANTED;
                 // The Emergency Dialer has call privileged permission and uses this to place
                 // emergency calls.  We ensure permission checks in
                 // NewOutgoingCallIntentBroadcaster#process pass by sending this to
                 // Telecom as an ACTION_CALL_PRIVILEGED intent (which makes sense since the
                 // com.android.phone process has that permission).
-                final boolean hasCallPrivilegedPermission = mContext.checkCallingPermission(
+                final boolean hasCallPrivilegedPermission = mContext.checkCallingOrSelfPermission(
                         CALL_PRIVILEGED) == PackageManager.PERMISSION_GRANTED;
 
                 synchronized (mLock) {
@@ -1833,7 +1833,8 @@
                         }
                         mUserCallIntentProcessorFactory.create(mContext, userHandle)
                                 .processIntent(intent, callingPackage, isSelfManagedRequest,
-                                        (hasCallAppOp && hasCallPermission),
+                                        (hasCallAppOp && hasCallPermission)
+                                                || hasCallPrivilegedPermission,
                                         true /* isLocalInvocation */);
                     } finally {
                         Binder.restoreCallingIdentity(token);
@@ -3005,6 +3006,11 @@
             return true;
         }
 
+        if (mContext.checkCallingOrSelfPermission(CALL_PRIVILEGED)
+                == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+
         // Accessing phone state is gated by a special permission.
         mContext.enforceCallingOrSelfPermission(CALL_PHONE, message);
 
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 7b5afe6..8bc1f2a 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -1151,9 +1151,9 @@
                 nullable(String.class), nullable(String.class)))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         doReturn(PackageManager.PERMISSION_GRANTED)
-                .when(mContext).checkCallingPermission(CALL_PHONE);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PHONE);
         doReturn(PackageManager.PERMISSION_DENIED)
-                .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
 
         mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE, null);
         placeCallTestHelper(handle, extras, /*isSelfManagedExpected*/ false,
@@ -1204,9 +1204,9 @@
         doNothing().when(mContext).enforceCallingOrSelfPermission(
                 eq(Manifest.permission.MANAGE_OWN_CALLS), anyString());
         doReturn(PackageManager.PERMISSION_DENIED)
-                .when(mContext).checkCallingPermission(CALL_PHONE);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PHONE);
         doReturn(PackageManager.PERMISSION_DENIED)
-                .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
 
         try {
             mTSIBinder.placeCall(handle, extras, PACKAGE_NAME, null);
@@ -1266,6 +1266,8 @@
         // pass MANAGE_OWN_CALLS check, but do not have CALL PHONE
         doNothing().when(mContext).enforceCallingOrSelfPermission(
                 eq(Manifest.permission.MANAGE_OWN_CALLS), anyString());
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
         doThrow(new SecurityException())
                 .when(mContext).enforceCallingOrSelfPermission(eq(CALL_PHONE), anyString());
 
@@ -1299,6 +1301,8 @@
         doNothing().when(mContext).enforceCallingOrSelfPermission(
                 eq(Manifest.permission.MANAGE_OWN_CALLS), anyString());
         doNothing().when(mContext).enforceCallingOrSelfPermission(eq(CALL_PHONE), anyString());
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
         when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString(),
                 nullable(String.class), nullable(String.class)))
                 .thenReturn(AppOpsManager.MODE_ERRORED);
@@ -1333,9 +1337,9 @@
                 nullable(String.class), nullable(String.class)))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         doReturn(PackageManager.PERMISSION_GRANTED)
-                .when(mContext).checkCallingPermission(CALL_PHONE);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PHONE);
         doReturn(PackageManager.PERMISSION_DENIED)
-                .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
 
         // We expect the call to go through with no PhoneAccount specified, since the request
         // contained a self-managed PhoneAccountHandle that didn't belong to this app.
@@ -1371,6 +1375,8 @@
         doThrow(new SecurityException())
                 .when(mContext).enforceCallingOrSelfPermission(
                         eq(Manifest.permission.MANAGE_OWN_CALLS), anyString());
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
         doThrow(new SecurityException())
                 .when(mContext).enforceCallingOrSelfPermission(eq(CALL_PHONE), anyString());
 
@@ -1403,6 +1409,8 @@
         doThrow(new SecurityException())
                 .when(mContext).enforceCallingOrSelfPermission(
                         eq(Manifest.permission.MANAGE_OWN_CALLS), anyString());
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
         doNothing().when(mContext).enforceCallingOrSelfPermission(eq(CALL_PHONE), anyString());
         when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString(),
                 nullable(String.class), nullable(String.class)))
@@ -1439,9 +1447,9 @@
                 nullable(String.class), nullable(String.class)))
                 .thenReturn(AppOpsManager.MODE_IGNORED);
         doReturn(PackageManager.PERMISSION_DENIED)
-                .when(mContext).checkCallingPermission(CALL_PHONE);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PHONE);
         doReturn(PackageManager.PERMISSION_DENIED)
-                .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
 
         mTSIBinder.placeCall(handle, extras, PACKAGE_NAME, null);
         placeCallTestHelper(handle, extras, /*isSelfManagedExpected*/ true,
@@ -1468,9 +1476,9 @@
                 nullable(String.class), nullable(String.class)))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         doReturn(PackageManager.PERMISSION_GRANTED)
-                .when(mContext).checkCallingPermission(CALL_PHONE);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PHONE);
         doReturn(PackageManager.PERMISSION_DENIED)
-                .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
 
         mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE, null);
         placeCallTestHelper(handle, extras, /*isSelfManagedExpected*/ false,
@@ -1478,6 +1486,42 @@
     }
 
     /**
+     * In the case that there is a managed normal call request and the app has CALL_PRIVILEGED
+     * permission, place call should complete successfully.
+     */
+    @SmallTest
+    @Test
+    public void testPlaceCallPrivileged() throws Exception {
+        doReturn(false).when(mDefaultDialerCache).isDefaultOrSystemDialer(
+                eq(DEFAULT_DIALER_PACKAGE), anyInt());
+        Uri handle = Uri.parse("tel:6505551234");
+
+        // CALL_PHONE is not granted, but CALL_PRIVILEGED is
+        doThrow(new SecurityException())
+                .when(mContext).enforceCallingOrSelfPermission(
+                        eq(Manifest.permission.MANAGE_OWN_CALLS), anyString());
+        doReturn(PackageManager.PERMISSION_GRANTED)
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
+        doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
+                eq(CALL_PHONE), anyString());
+        when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString(),
+                nullable(String.class), nullable(String.class)))
+                .thenReturn(AppOpsManager.MODE_ERRORED);
+
+        try {
+            mTSIBinder.placeCall(handle, null, PACKAGE_NAME + "2", null);
+        } catch(SecurityException e) {
+            fail("Expected no SecurityException - CALL_PRIVILEGED is granted");
+        }
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mUserCallIntentProcessor).processIntent(intentCaptor.capture(), anyString(),
+                eq(false), eq(true), eq(true));
+        Intent capturedIntent = intentCaptor.getValue();
+        assertEquals(Intent.ACTION_CALL_PRIVILEGED, capturedIntent.getAction());
+        assertEquals(handle, capturedIntent.getData());
+    }
+
+    /**
      * The default dialer is requesting to place a call and CALL_PHONE is granted, however
      * OP_CALL_PHONE app op is denied to that app, so non-emergency calls will be denied.
      */
@@ -1493,9 +1537,9 @@
                 nullable(String.class), nullable(String.class)))
                 .thenReturn(AppOpsManager.MODE_IGNORED);
         doReturn(PackageManager.PERMISSION_GRANTED)
-                .when(mContext).checkCallingPermission(CALL_PHONE);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PHONE);
         doReturn(PackageManager.PERMISSION_DENIED)
-                .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
 
         mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE, null);
         placeCallTestHelper(handle, extras, /*isSelfManagedExpected*/ false,
@@ -1517,9 +1561,9 @@
                 nullable(String.class), nullable(String.class)))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         doReturn(PackageManager.PERMISSION_DENIED)
-                .when(mContext).checkCallingPermission(CALL_PHONE);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PHONE);
         doReturn(PackageManager.PERMISSION_DENIED)
-                .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
 
         mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE, null);
         placeCallTestHelper(handle, extras, /*isSelfManagedExpected*/ false,
@@ -1560,6 +1604,8 @@
         // permission.
         doThrow(new SecurityException())
                 .when(mContext).enforceCallingOrSelfPermission(eq(CALL_PHONE), anyString());
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
 
         try {
             mTSIBinder.placeCall(handle, extras, "arbitrary_package_name", null);
@@ -1585,6 +1631,8 @@
         // The app is not considered a privileged dialer and does not have the OP_CALL_PHONE
         // app op.
         doNothing().when(mContext).enforceCallingOrSelfPermission(eq(CALL_PHONE), anyString());
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext).checkCallingOrSelfPermission(CALL_PRIVILEGED);
         when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_CALL_PHONE), anyInt(), anyString(),
                 nullable(String.class), nullable(String.class)))
                 .thenReturn(AppOpsManager.MODE_IGNORED);