Plumbing for newIncomingThirdPartyCall() DO NOT MERGE

Handles the new newIncomingThirdPartyCall() API. Passes it to the
first matching third party phone.

Change-Id: I06b206d0710c0e966106d7cc17748c18935aa680
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 82b5e9f..2834c9a 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
@@ -37,14 +38,17 @@
 import android.telephony.ServiceState;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.telephony.DefaultPhoneNotifier;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.IThirdPartyCallProvider;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.CallManager;
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.thirdpartyphone.ThirdPartyPhone;
 
 import java.util.List;
 import java.util.ArrayList;
@@ -64,6 +68,7 @@
     private static final int CMD_ANSWER_RINGING_CALL = 4;
     private static final int CMD_END_CALL = 5;  // not used yet
     private static final int CMD_SILENCE_RINGER = 6;
+    private static final int CMD_NEW_INCOMING_THIRD_PARTY_CALL = 7;
 
     /** The singleton instance. */
     private static PhoneInterfaceManager sInstance;
@@ -171,6 +176,22 @@
                         request.notifyAll();
                     }
                     break;
+                case CMD_NEW_INCOMING_THIRD_PARTY_CALL: {
+                    request = (MainThreadRequest) msg.obj;
+                    Pair<ComponentName, String> pair =
+                            (Pair<ComponentName, String>) request.argument;
+                    for (Phone phone : CallManager.getInstance().getAllPhones()) {
+                        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_THIRD_PARTY) {
+                            ThirdPartyPhone thirdPartyPhone = (ThirdPartyPhone) phone;
+                            if (thirdPartyPhone.getCallProviderComponent().equals(pair.first) &&
+                                    thirdPartyPhone.takeIncomingCall(pair.first, pair.second)) {
+                                if (DBG) log("newIncomingThirdPartyCall: call taken");
+                                return;
+                            }
+                        }
+                    }
+                    break;
+                }
 
                 default:
                     Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
@@ -217,6 +238,16 @@
     }
 
     /**
+     * Same as {@link #sendRequestAsync(int)} except it takes an argument.
+     * @see {@link #sendRequest(int,Object)}
+     */
+    private void sendRequestAsync(int command, Object argument) {
+        MainThreadRequest request = new MainThreadRequest(argument);
+        Message msg = mMainThreadHandler.obtainMessage(command, request);
+        msg.sendToTarget();
+    }
+
+    /**
      * Initialize the singleton PhoneInterfaceManager instance.
      * This is only done once, at startup, from PhoneApp.onCreate().
      */
@@ -726,10 +757,21 @@
         }
     }
 
+    @Override
     public void setCellInfoListRate(int rateInMillis) {
         mPhone.setCellInfoListRate(rateInMillis);
     }
 
+    @Override
+    public void newIncomingThirdPartyCall(ComponentName component, String callId) {
+        // TODO(sail): Enforce that the component belongs to the calling package.
+        if (DBG) {
+            log("newIncomingThirdPartyCall: component: " + component + " callId: " + callId);
+        }
+        enforceCallPermission();
+        sendRequestAsync(CMD_NEW_INCOMING_THIRD_PARTY_CALL, Pair.create(component, callId));
+    }
+
     //
     // Internal helper methods.
     //
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 2d44977..596426b 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -879,7 +879,8 @@
                 shouldMute = sConnectionMuteTable.get(
                         phone.getForegroundCall().getLatestConnection());
             } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
-                    || (phoneType == PhoneConstants.PHONE_TYPE_SIP)) {
+                    || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
+                    || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
                 shouldMute = sConnectionMuteTable.get(c);
             }
             if (shouldMute == null) {
@@ -1430,7 +1431,8 @@
         if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
             conn = call.getLatestConnection();
         } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
-                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)) {
+                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
+                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
             conn = call.getEarliestConnection();
         } else {
             throw new IllegalStateException("Unexpected phone type: " + phoneType);
@@ -1534,6 +1536,9 @@
                     case PhoneConstants.PHONE_TYPE_GSM: log("  ==> PHONE_TYPE_GSM"); break;
                     case PhoneConstants.PHONE_TYPE_CDMA: log("  ==> PHONE_TYPE_CDMA"); break;
                     case PhoneConstants.PHONE_TYPE_SIP: log("  ==> PHONE_TYPE_SIP"); break;
+                    case PhoneConstants.PHONE_TYPE_THIRD_PARTY:
+                        log("  ==> PHONE_TYPE_THIRD_PARTY");
+                        break;
                     default: log("  ==> Unknown phone type"); break;
                 }
             }
@@ -2154,7 +2159,8 @@
             if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                 answerCall(phone.getRingingCall());
             } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
-                    || (phoneType == PhoneConstants.PHONE_TYPE_SIP)) {
+                    || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
+                    || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
                 if (hasActiveCall && hasHoldingCall) {
                     if (DBG) log("handleHeadsetHook: ringing (both lines in use) ==> answer!");
                     answerAndEndActive(app.mCM, phone.getRingingCall());
@@ -2298,7 +2304,8 @@
             return (app.cdmaPhoneCallState.getCurrentCallState()
                     == CdmaPhoneCallState.PhoneCallState.CONF_CALL);
         } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
-                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)) {
+                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
+                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
             // GSM: "Swap" is available if both lines are in use and there's no
             // incoming call.  (Actually we need to verify that the active
             // call really is in the ACTIVE state and the holding call really
@@ -2357,7 +2364,8 @@
             return ((fgCallState == Call.State.ACTIVE)
                     && (app.cdmaPhoneCallState.getAddCallMenuStateAfterCallWaiting()));
         } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
-                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)) {
+                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
+                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
             // GSM: "Add call" is available only if ALL of the following are true:
             // - There's no incoming ringing call
             // - There's < 2 lines in use