Merge "IMS: Add support for call deflection feature" am: 9109db707a
am: a592642f64

Change-Id: Ica93b39aa551c7f39b08a1e9a3dde6a9517227e3
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index ff06005..714ac18 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -37,6 +37,7 @@
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsCallProfile;
+import android.text.TextUtils;
 import android.util.Pair;
 
 import com.android.ims.ImsCall;
@@ -637,6 +638,45 @@
     }
 
     @Override
+    public void onDeflect(Uri address) {
+        Log.v(this, "onDeflect");
+        if (mOriginalConnection != null && isValidRingingCall()) {
+            if (address == null) {
+                Log.w(this, "call deflect address uri is null");
+                return;
+            }
+            String scheme = address.getScheme();
+            String deflectNumber = "";
+            String uriString = address.getSchemeSpecificPart();
+            if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
+                if (!PhoneAccount.SCHEME_TEL.equals(scheme)) {
+                    Log.w(this, "onDeflect, address scheme is not of type tel instead: " +
+                            scheme);
+                    return;
+                }
+                if (PhoneNumberUtils.isUriNumber(uriString)) {
+                    Log.w(this, "Invalid deflect address. Not a legal PSTN number.");
+                    return;
+                }
+                deflectNumber = PhoneNumberUtils.convertAndStrip(uriString);
+                if (TextUtils.isEmpty(deflectNumber)) {
+                    Log.w(this, "Empty deflect number obtained from address uri");
+                    return;
+                }
+            } else {
+                Log.w(this, "Cannot deflect to voicemail uri");
+                return;
+            }
+
+            try {
+                mOriginalConnection.deflect(deflectNumber);
+            } catch (CallStateException e) {
+                Log.e(this, e, "Failed to deflect call.");
+            }
+        }
+    }
+
+    @Override
     public void onReject() {
         Log.v(this, "onReject");
         if (isValidRingingCall()) {
@@ -808,6 +848,8 @@
         newCapabilities = changeBitmask(newCapabilities, CAPABILITY_CAN_PULL_CALL,
                 isExternalConnection() && isPullable());
         newCapabilities = applyConferenceTerminationCapabilities(newCapabilities);
+        newCapabilities = changeBitmask(newCapabilities, CAPABILITY_SUPPORT_DEFLECT,
+                isImsConnection() && canDeflectImsCalls());
 
         if (getConnectionCapabilities() != newCapabilities) {
             setConnectionCapabilities(newCapabilities);
@@ -1085,6 +1127,17 @@
         return PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
     }
 
+    private boolean canDeflectImsCalls() {
+        PersistableBundle b = getCarrierConfig();
+        // Return false if the CarrierConfig is unavailable
+        if (b != null) {
+            return b.getBoolean(
+                    CarrierConfigManager.KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL) &&
+                    isValidRingingCall();
+        }
+        return false;
+    }
+
     /**
      * Determines if the device will respect the value of the
      * {@link CarrierConfigManager#KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} configuration option.