Merge "Cdma Outgoing 3way call support." into klp-dev
diff --git a/common/src/com/android/services/telephony/common/Call.java b/common/src/com/android/services/telephony/common/Call.java
index 9973f0d..0aaf12d 100644
--- a/common/src/com/android/services/telephony/common/Call.java
+++ b/common/src/com/android/services/telephony/common/Call.java
@@ -71,16 +71,17 @@
      * TODO: Should some of these be capabilities of the Phone instead of the call?
      */
     public static class Capabilities {
-        public static final int HOLD             = 0x00000001; /* has ability to hold the call */
-        public static final int SUPPORT_HOLD = 0x00000002; /* can show the hold button */
-        public static final int MERGE_CALLS      = 0x00000004; /* has ability to merge calls */
-        public static final int SWAP_CALLS       = 0x00000008; /* swap with a background call */
-        public static final int ADD_CALL         = 0x00000010; /* add another call to this one */
-        public static final int RESPOND_VIA_TEXT = 0x00000020; /* has respond via text option */
-        public static final int MUTE             = 0x00000040; /* can mute the call */
+        public static final int HOLD               = 0x00000001; /* has ability to hold the call */
+        public static final int SUPPORT_HOLD       = 0x00000002; /* can show the hold button */
+        public static final int MERGE_CALLS        = 0x00000004; /* has ability to merge calls */
+        public static final int SWAP_CALLS         = 0x00000008; /* swap with a background call */
+        public static final int ADD_CALL           = 0x00000010; /* add another call to this one */
+        public static final int RESPOND_VIA_TEXT   = 0x00000020; /* has respond via text option */
+        public static final int MUTE               = 0x00000040; /* can mute the call */
+        public static final int GENERIC_CONFERENCE = 0x00000080; /* Generic conference mode */
 
         public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CALLS | SWAP_CALLS | ADD_CALL
-                | RESPOND_VIA_TEXT | MUTE;
+                | RESPOND_VIA_TEXT | MUTE | GENERIC_CONFERENCE;
     }
 
     /**
diff --git a/src/com/android/phone/CallController.java b/src/com/android/phone/CallController.java
index 44de433..2cceed0 100644
--- a/src/com/android/phone/CallController.java
+++ b/src/com/android/phone/CallController.java
@@ -144,8 +144,7 @@
                     // Reset the mThreeWayCallOrigStateDialing state
                     mApp.cdmaPhoneCallState.setThreeWayCallOrigState(false);
 
-                    // Refresh the in-call UI (based on the current ongoing call)
-                    mApp.updateInCallScreen();
+                    mApp.getCallModeler().setCdmaOutgoing3WayCall(null);
                 }
                 break;
 
diff --git a/src/com/android/phone/CallModeler.java b/src/com/android/phone/CallModeler.java
index f3e0d36..7af2416 100644
--- a/src/com/android/phone/CallModeler.java
+++ b/src/com/android/phone/CallModeler.java
@@ -35,13 +35,14 @@
 import com.android.services.telephony.common.Call.Capabilities;
 import com.android.services.telephony.common.Call.State;
 
-import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map.Entry;
@@ -92,6 +93,7 @@
     private final ArrayList<Listener> mListeners = new ArrayList<Listener>();
     private RejectWithTextMessageManager mRejectWithTextMessageManager;
     private Connection mCdmaIncomingConnection;
+    private Connection mCdmaOutgoingConnection;
 
     public CallModeler(CallStateMonitor callStateMonitor, CallManager callManager,
             RejectWithTextMessageManager rejectWithTextMessageManager,
@@ -133,9 +135,11 @@
     }
 
     public List<Call> getFullList() {
-        final List<Call> retval = Lists.newArrayList();
-        doUpdate(true, retval);
-        return retval;
+        final List<Call> calls =
+                Lists.newArrayListWithCapacity(mCallMap.size() + mConfCallMap.size());
+        calls.addAll(mCallMap.values());
+        calls.addAll(mConfCallMap.values());
+        return calls;
     }
 
     public CallResult getCallWithId(int callId) {
@@ -192,6 +196,24 @@
         }
     }
 
+    /**
+     * CDMA Calls have no sense of "dialing" state. For outgoing calls 3way calls we want to
+     * mimick this state so that the the UI can notify the user that there is a "dialing"
+     * call.
+     */
+    public void setCdmaOutgoing3WayCall(Connection connection) {
+        boolean wasSet = mCdmaOutgoingConnection != null;
+
+        mCdmaOutgoingConnection = connection;
+
+        // If we reset the connection, that mean we can now tell the user that the call is actually
+        // part of the conference call and move it out of the dialing state. To do this, issue a
+        // new update completely.
+        if (wasSet && mCdmaOutgoingConnection == null) {
+            onPhoneStateChanged(null);
+        }
+    }
+
     private boolean hasLiveCallInternal(HashMap<Connection, Call> map) {
         for (Call call : map.values()) {
             final int state = call.getState();
@@ -547,7 +569,7 @@
         /**
          * !!! Uses values from connection and call collected above so this part must be last !!!
          */
-        final int newCapabilities = getCapabilitiesFor(connection, call);
+        final int newCapabilities = getCapabilitiesFor(connection, call, isForConference);
         if (call.getCapabilities() != newCapabilities) {
             call.setCapabilities(newCapabilities);
             changed = true;
@@ -559,7 +581,7 @@
     /**
      * Returns a mask of capabilities for the connection such as merge, hold, etc.
      */
-    private int getCapabilitiesFor(Connection connection, Call call) {
+    private int getCapabilitiesFor(Connection connection, Call call, boolean isForConference) {
         final boolean callIsActive = (call.getState() == Call.State.ACTIVE);
         final Phone phone = connection.getCall().getPhone();
 
@@ -571,6 +593,8 @@
 
         final boolean supportHold = PhoneUtils.okToSupportHold(mCallManager);
         final boolean canHold = PhoneUtils.okToHoldCall(mCallManager);
+        final boolean genericConf = isForConference &&
+                (connection.getCall().getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA);
 
         // only applies to active calls
         if (callIsActive) {
@@ -627,6 +651,9 @@
         if (canMute) {
             retval |= Capabilities.MUTE;
         }
+        if (genericConf) {
+            retval |= Capabilities.GENERIC_CONFERENCE;
+        }
 
         return retval;
     }
@@ -640,7 +667,10 @@
         if (connection.getCall() != null && connection.getCall().isMultiparty()) {
             int count = 0;
             for (Connection currConn : connection.getCall().getConnections()) {
-                if (currConn.isAlive()) {
+
+                // Only count connections which are alive and never cound the special
+                // "dialing" 3way call for CDMA calls.
+                if (currConn.isAlive() && currConn != mCdmaOutgoingConnection) {
                     count++;
                     if (count >= 2) {
                         return true;
@@ -653,6 +683,11 @@
 
     private int translateStateFromTelephony(Connection connection, boolean isForConference) {
 
+        // For the "fake" outgoing CDMA call, we need to always treat it as an outgoing call.
+        if (mCdmaOutgoingConnection == connection) {
+            return State.DIALING;
+        }
+
         int retval = State.IDLE;
         switch (connection.getState()) {
             case ACTIVE:
@@ -680,7 +715,6 @@
         // If we are dealing with a potential child call (not the parent conference call),
         // the check to see if we have to set the state to CONFERENCED.
         if (!isForConference) {
-
             // if the connection is part of a multiparty call, and it is live,
             // annotate it with CONFERENCED state instead.
             if (isPartOfLiveConferenceCall(connection) && connection.isAlive()) {
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 214402d..49a3427 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -677,6 +677,10 @@
         return audioRouter;
     }
 
+    /* package */ CallModeler getCallModeler() {
+        return callModeler;
+    }
+
     /**
      * Returns an Intent that can be used to go to the "Call log"
      * UI (aka CallLogActivity) in the Contacts app.
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index bb858b0..c3abd9f 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -548,7 +548,8 @@
      * </pre>
      * @param app The phone instance.
      */
-    private static void updateCdmaCallStateOnNewOutgoingCall(PhoneGlobals app) {
+    private static void updateCdmaCallStateOnNewOutgoingCall(PhoneGlobals app,
+            Connection connection) {
         if (app.cdmaPhoneCallState.getCurrentCallState() ==
             CdmaPhoneCallState.PhoneCallState.IDLE) {
             // This is the first outgoing call. Set the Phone Call State to ACTIVE
@@ -558,6 +559,8 @@
             // This is the second outgoing call. Set the Phone Call State to 3WAY
             app.cdmaPhoneCallState.setCurrentCallState(
                 CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE);
+
+            app.getCallModeler().setCdmaOutgoing3WayCall(connection);
         }
     }
 
@@ -671,7 +674,7 @@
             }
         } else {
             if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                updateCdmaCallStateOnNewOutgoingCall(app);
+                updateCdmaCallStateOnNewOutgoingCall(app, connection);
             }
 
             // Clean up the number to be displayed.