Merge "Add uses-sdk to Telecom test APK manifests"
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 91f7c4f..f18ff47 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -1091,7 +1091,7 @@
             // Ensure video state history tracks video state at time of rejection.
             mVideoStateHistory |= mVideoState;
 
-            mConnectionService.reject(this);
+            mConnectionService.reject(this, rejectWithMessage, textMessage);
             Log.event(this, Log.Events.REQUEST_REJECT);
         }
     }
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index d5ab5cf..b80134e 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -774,12 +774,18 @@
     }
 
     /** @see IConnectionService#reject(String) */
-    void reject(Call call) {
+    void reject(Call call, boolean rejectWithMessage, String message) {
         final String callId = mCallIdMapper.getCallId(call);
         if (callId != null && isServiceValid("reject")) {
             try {
                 logOutgoing("reject %s", callId);
-                mServiceInterface.reject(callId);
+
+                if (rejectWithMessage && call.can(
+                        android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
+                    mServiceInterface.rejectWithMessage(callId, message);
+                } else {
+                    mServiceInterface.reject(callId);
+                }
             } catch (RemoteException e) {
             }
         }
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 8a8e4f4..9562ea7 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -32,7 +32,6 @@
 import android.os.RemoteException;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.telecom.AudioState;
 import android.telecom.CallAudioState;
 import android.telecom.Connection;
 import android.telecom.DefaultDialerManager;
@@ -770,7 +769,10 @@
         android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
 
         Connection.CAPABILITY_CAN_PAUSE_VIDEO,
-        android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO
+        android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO,
+
+        Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
+        android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION
     };
 
     private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
diff --git a/src/com/android/server/telecom/RespondViaSmsManager.java b/src/com/android/server/telecom/RespondViaSmsManager.java
index e5a2042..ab410f1 100644
--- a/src/com/android/server/telecom/RespondViaSmsManager.java
+++ b/src/com/android/server/telecom/RespondViaSmsManager.java
@@ -126,7 +126,10 @@
 
     @Override
     public void onIncomingCallRejected(Call call, boolean rejectWithMessage, String textMessage) {
-        if (rejectWithMessage && call.getHandle() != null) {
+        if (rejectWithMessage
+                && call.getHandle() != null
+                && !call.can(
+                        android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
             int subId = mCallsManager.getPhoneAccountRegistrar().getSubscriptionIdForPhoneAccount(
                     call.getTargetPhoneAccount());
             rejectCallWithMessage(call.getContext(), call.getHandle().getSchemeSpecificPart(),
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 36db517..fc8977b 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -808,9 +808,19 @@
                         + " is not allowed to place phone calls");
             }
 
+            // Note: we can still get here for the default/system dialer, even if the Phone
+            // permission is turned off. This is because the default/system dialer is always
+            // allowed to attempt to place a call (regardless of permission state), in case
+            // it turns out to be an emergency call. If the permission is denied and the
+            // call is being made to a non-emergency number, the call will be denied later on
+            // by {@link UserCallIntentProcessor}.
+
             final boolean hasCallAppOp = mAppOpsManager.noteOp(AppOpsManager.OP_CALL_PHONE,
                     Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
 
+            final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==
+                    PackageManager.PERMISSION_GRANTED;
+
             synchronized (mLock) {
                 final UserHandle userHandle = Binder.getCallingUserHandle();
                 long token = Binder.clearCallingIdentity();
@@ -818,7 +828,7 @@
                     final Intent intent = new Intent(Intent.ACTION_CALL, handle);
                     intent.putExtras(extras);
                     new UserCallIntentProcessor(mContext, userHandle).processIntent(intent,
-                            callingPackage, hasCallAppOp);
+                            callingPackage, hasCallAppOp && hasCallPermission);
                 } finally {
                     Binder.restoreCallingIdentity(token);
                 }
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
index 1374d3b..8f451b5 100644
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -70,7 +70,8 @@
      *
      * @param intent The intent.
      */
-    public void processIntent(Intent intent, String callingPackageName, boolean hasCallAppOp) {
+    public void processIntent(Intent intent, String callingPackageName,
+            boolean canCallNonEmergency) {
         // Ensure call intents are not processed on devices that are not capable of calling.
         if (!isVoiceCapable()) {
             return;
@@ -81,12 +82,12 @@
         if (Intent.ACTION_CALL.equals(action) ||
                 Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
                 Intent.ACTION_CALL_EMERGENCY.equals(action)) {
-            processOutgoingCallIntent(intent, callingPackageName, hasCallAppOp);
+            processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);
         }
     }
 
     private void processOutgoingCallIntent(Intent intent, String callingPackageName,
-            boolean hasCallAppOp) {
+            boolean canCallNonEmergency) {
         Uri handle = intent.getData();
         String scheme = handle.getScheme();
         String uriString = handle.getSchemeSpecificPart();
@@ -109,7 +110,7 @@
             return;
         }
 
-        if (!hasCallAppOp && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
+        if (!canCallNonEmergency && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
             showErrorDialogForRestrictedOutgoingCall(mContext,
                     R.string.outgoing_call_not_allowed_no_permission);
             Log.w(this, "Rejecting non-emergency phone call because "
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 964f014..903028c 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -107,6 +107,9 @@
         public void reject(String callId) throws RemoteException { }
 
         @Override
+        public void rejectWithMessage(String callId, String message) throws RemoteException { }
+
+        @Override
         public void disconnect(String callId) throws RemoteException { }
 
         @Override