SRVCC Conference with Mid Call Enabled

1. Add support for SRVCC with more than 3 participants.

There is a max limit of 7 connections in GsmCallTracker. If RIL
reports call id greater than 7, it will be ignored while polling in
call tracker. Because of this, in case of SRVCC with more than 3
participants, call ids greater than 7 are getting dropped from UI.
Fix this by increasing the max connections limit to accomodate call
ids after SRVCC.

2. Add support for SRVCC Conference with greater than 3 participants

The phantom call mechanism that is used to notify the participants
of conference call during SRVCC, notifies only the last unknown
connection. During SRVCC conference call, all the participants
after the first are using the phantom call mechanism and hence
each unknown connection resulting should have a seperate notify
from frameworks.

3. Add support for using the CS connection address during SRVCC

Updated the values that are migrated from handover connection.
Some fields which have an updated value from the driver call list
are used directly instead of migrating their values from handover
Ims Connection.

4. IMS: Fix for duplicate registrants during SRVCC.

Currently CallManager registers for different phone states
with Gsm and Ims phone. But while handling the UNSOL SRVCC state
change the migrate function in PhoneBase, does no check for the
duplicate registrants and copies all the ImsPhone registrants to
GsmPhone.

Fix: Dont migrate the registrants from ImsPhone to GsmPhone if
CallManager has already registered with default phone for these
registrants.

Change-Id: I67ac7d7156e4d0dec8c66059263f0e29a6337c66
diff --git a/src/java/com/android/internal/telephony/CallManager.java b/src/java/com/android/internal/telephony/CallManager.java
index 3cb00d3..f4e3dca 100644
--- a/src/java/com/android/internal/telephony/CallManager.java
+++ b/src/java/com/android/internal/telephony/CallManager.java
@@ -115,6 +115,8 @@
     // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
     //private boolean mIsEccDialing = false;
 
+    private Object mRegistrantidentifier = new Object();
+
     // state registrants
     protected final RegistrantList mPreciseCallStateRegistrants
     = new RegistrantList();
@@ -592,6 +594,10 @@
         return ((defaultPhone == null) ? null : defaultPhone.getContext());
     }
 
+    public Object getRegistrantIdentifier() {
+        return mRegistrantidentifier;
+    }
+
     private void registerForPhoneStates(Phone phone) {
         // We need to keep a mapping of handler to Phone for proper unregistration.
         // TODO: Clean up this solution as it is just a work around for each Phone instance
@@ -609,21 +615,39 @@
         mHandlerMap.put(phone, handler);
 
         // for common events supported by all phones
-        phone.registerForPreciseCallStateChanged(handler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
-        phone.registerForDisconnect(handler, EVENT_DISCONNECT, null);
-        phone.registerForNewRingingConnection(handler, EVENT_NEW_RINGING_CONNECTION, null);
-        phone.registerForUnknownConnection(handler, EVENT_UNKNOWN_CONNECTION, null);
-        phone.registerForIncomingRing(handler, EVENT_INCOMING_RING, null);
-        phone.registerForRingbackTone(handler, EVENT_RINGBACK_TONE, null);
-        phone.registerForInCallVoicePrivacyOn(handler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
-        phone.registerForInCallVoicePrivacyOff(handler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
-        phone.registerForDisplayInfo(handler, EVENT_DISPLAY_INFO, null);
-        phone.registerForSignalInfo(handler, EVENT_SIGNAL_INFO, null);
-        phone.registerForResendIncallMute(handler, EVENT_RESEND_INCALL_MUTE, null);
-        phone.registerForMmiInitiate(handler, EVENT_MMI_INITIATE, null);
-        phone.registerForMmiComplete(handler, EVENT_MMI_COMPLETE, null);
-        phone.registerForSuppServiceFailed(handler, EVENT_SUPP_SERVICE_FAILED, null);
-        phone.registerForServiceStateChanged(handler, EVENT_SERVICE_STATE_CHANGED, null);
+        // The mRegistrantIdentifier passed here, is to identify in the PhoneBase
+        // that the registrants are coming from the CallManager.
+        phone.registerForPreciseCallStateChanged(handler, EVENT_PRECISE_CALL_STATE_CHANGED,
+                mRegistrantidentifier);
+        phone.registerForDisconnect(handler, EVENT_DISCONNECT,
+                mRegistrantidentifier);
+        phone.registerForNewRingingConnection(handler, EVENT_NEW_RINGING_CONNECTION,
+                mRegistrantidentifier);
+        phone.registerForUnknownConnection(handler, EVENT_UNKNOWN_CONNECTION,
+                mRegistrantidentifier);
+        phone.registerForIncomingRing(handler, EVENT_INCOMING_RING,
+                mRegistrantidentifier);
+        phone.registerForRingbackTone(handler, EVENT_RINGBACK_TONE,
+                mRegistrantidentifier);
+        phone.registerForInCallVoicePrivacyOn(handler, EVENT_IN_CALL_VOICE_PRIVACY_ON,
+                mRegistrantidentifier);
+        phone.registerForInCallVoicePrivacyOff(handler, EVENT_IN_CALL_VOICE_PRIVACY_OFF,
+                mRegistrantidentifier);
+        phone.registerForDisplayInfo(handler, EVENT_DISPLAY_INFO,
+                mRegistrantidentifier);
+        phone.registerForSignalInfo(handler, EVENT_SIGNAL_INFO,
+                mRegistrantidentifier);
+        phone.registerForResendIncallMute(handler, EVENT_RESEND_INCALL_MUTE,
+                mRegistrantidentifier);
+        phone.registerForMmiInitiate(handler, EVENT_MMI_INITIATE,
+                mRegistrantidentifier);
+        phone.registerForMmiComplete(handler, EVENT_MMI_COMPLETE,
+                mRegistrantidentifier);
+        phone.registerForSuppServiceFailed(handler, EVENT_SUPP_SERVICE_FAILED,
+                mRegistrantidentifier);
+        phone.registerForServiceStateChanged(handler, EVENT_SERVICE_STATE_CHANGED,
+                mRegistrantidentifier);
+
         // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
         //phone.registerForRadioOffOrNotAvailable(handler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
 
diff --git a/src/java/com/android/internal/telephony/Connection.java b/src/java/com/android/internal/telephony/Connection.java
index 89d2d97..780b7ef 100644
--- a/src/java/com/android/internal/telephony/Connection.java
+++ b/src/java/com/android/internal/telephony/Connection.java
@@ -477,12 +477,7 @@
     public void migrateFrom(Connection c) {
         if (c == null) return;
         mListeners = c.mListeners;
-        mAddress = c.getAddress();
-        mNumberPresentation = c.getNumberPresentation();
         mDialString = c.getOrigDialString();
-        mCnapName = c.getCnapName();
-        mCnapNamePresentation = c.getCnapNamePresentation();
-        mIsIncoming = c.isIncoming();
         mCreateTime = c.getCreateTime();
         mConnectTime = c.getConnectTime();
         mConnectTimeReal = c.getConnectTimeReal();
diff --git a/src/java/com/android/internal/telephony/PhoneBase.java b/src/java/com/android/internal/telephony/PhoneBase.java
index 2f11f1b..708511d 100644
--- a/src/java/com/android/internal/telephony/PhoneBase.java
+++ b/src/java/com/android/internal/telephony/PhoneBase.java
@@ -797,7 +797,22 @@
     public void migrate(RegistrantList to, RegistrantList from) {
         from.removeCleared();
         for (int i = 0, n = from.size(); i < n; i++) {
-            to.add((Registrant) from.get(i));
+            Registrant r = (Registrant) from.get(i);
+            Message msg = r.messageForRegistrant();
+            // Since CallManager has already registered with both CS and IMS phones,
+            // the migrate should happen only for those registrants which are not
+            // registered with CallManager.Hence the below check is needed to add
+            // only those registrants to the registrant list which are not
+            // coming from the CallManager.
+            if (msg != null) {
+                if (msg.obj == CallManager.getInstance().getRegistrantIdentifier()) {
+                    continue;
+                } else {
+                    to.add((Registrant) from.get(i));
+                }
+            } else {
+                Rlog.d(LOG_TAG, "msg is null");
+            }
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/src/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 0369194..9e0b471 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -47,6 +47,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 
@@ -730,10 +731,12 @@
         }
 
         /* Disconnect any pending Handover connections */
-        for (Connection hoConnection : mHandoverConnections) {
-            log("handlePollCalls - disconnect hoConn= " + hoConnection.toString());
+        for (Iterator<Connection> it = mHandoverConnections.iterator();
+                it.hasNext();) {
+            Connection hoConnection = it.next();
+            log("handlePollCalls - disconnect hoConn= " + hoConnection);
             ((ImsPhoneConnection)hoConnection).onDisconnect(DisconnectCause.NOT_VALID);
-            mHandoverConnections.remove(hoConnection);
+            it.remove();
         }
 
         // Any non-local disconnects: determine cause
diff --git a/src/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/src/java/com/android/internal/telephony/gsm/GsmCallTracker.java
index 19a982b..a9958f5 100755
--- a/src/java/com/android/internal/telephony/gsm/GsmCallTracker.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -68,7 +68,7 @@
 
     //***** Constants
 
-    static final int MAX_CONNECTIONS = 7;   // only 7 connections allowed in GSM
+    static final int MAX_CONNECTIONS = 19;   // 7 allowed in GSM + 12 from IMS for SRVCC
     static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call
 
     //***** Instance Variables
@@ -647,10 +647,12 @@
         }
 
         /* Disconnect any pending Handover connections */
-        for (Connection hoConnection : mHandoverConnections) {
-            log("handlePollCalls - disconnect hoConn= " + hoConnection.toString());
+        for (Iterator<Connection> it = mHandoverConnections.iterator();
+                it.hasNext();) {
+            Connection hoConnection = it.next();
+            log("handlePollCalls - disconnect hoConn= " + hoConnection);
             ((ImsPhoneConnection)hoConnection).onDisconnect(DisconnectCause.NOT_VALID);
-            mHandoverConnections.remove(hoConnection);
+            it.remove();
         }
 
         // Any non-local disconnects: determine cause