IMS Conference fixes related to RemoteConnectionServices.

1. In ImsConferenceController, adding the children of an IMSConference
to the list of conferencable connections.  This is necessary because the
RemoteConnectionService API does not support specifying a list of
Conferenceables for a RemoteConnection.  Where Conferenceables are either
Connections or Conferences.  It only supports specifying a list of
conferenceable connections.  This is problematic because for an IMS
conference call, a standlone Connection is technically conferenceable with
the ImsConference.  As a result, the RemoteConnetionServices API is not
able to support conferencing a standalone Connection into a Conference.
To fix this temporarily, I'm adding the child ImsConference participant
connections to the list of conferenceables for the standalone Conference.

2. In ImsConference, there was an assumption made in "onMerge" that the
Connection merged into the conference was a TelephonyConnection.  Because
of the issues in (1), we can't make this assumption.  Since the cast
was only there to get at the phone, opted to just use the getPHone()
method in the conf host connetion instead.

Bug: 31464792
Change-Id: I5ee13dc71e566831c02d5ced18e0edb0f8b7ac4b
diff --git a/src/com/android/services/telephony/CdmaConnection.java b/src/com/android/services/telephony/CdmaConnection.java
index 8020996..29ccc6c 100644
--- a/src/com/android/services/telephony/CdmaConnection.java
+++ b/src/com/android/services/telephony/CdmaConnection.java
@@ -184,7 +184,7 @@
     }
 
     @Override
-    public void performConference(TelephonyConnection otherConnection) {
+    public void performConference(android.telecom.Connection otherConnection) {
         if (isImsConnection()) {
             super.performConference(otherConnection);
         } else {
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index e33c351..4acb6f8 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -439,7 +439,7 @@
     @Override
     public void onMerge(android.telecom.Connection connection) {
         try {
-            Phone phone = ((TelephonyConnection) connection).getPhone();
+            Phone phone = mConferenceHost.getPhone();
             if (phone != null) {
                 phone.conference();
             }
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 6669482..f7d587d 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -187,6 +187,7 @@
         Log.v(this, "recalculateConferenceable : %d", mTelephonyConnections.size());
         HashSet<Conferenceable> conferenceableSet = new HashSet<>(mTelephonyConnections.size() +
                 mImsConferences.size());
+        HashSet<Conferenceable> conferenceParticipantsSet = new HashSet<>();
 
         // Loop through and collect all calls which are active or holding
         for (TelephonyConnection connection : mTelephonyConnections) {
@@ -240,6 +241,7 @@
                 case Connection.STATE_ACTIVE:
                     //fall through
                 case Connection.STATE_HOLDING:
+                    conferenceParticipantsSet.addAll(conference.getConnections());
                     conferenceableSet.add(conference);
                     continue;
                 default:
@@ -256,6 +258,16 @@
                         .stream()
                         .filter(conferenceable -> c != conferenceable)
                         .collect(Collectors.toList());
+                // TODO: Remove this once RemoteConnection#setConferenceableConnections is fixed.
+                // Add all conference participant connections as conferenceable with a standalone
+                // Connection.  We need to do this to ensure that RemoteConnections work properly.
+                // At the current time, a RemoteConnection will not be conferenceable with a
+                // Conference, so we need to add its children to ensure the user can merge the call
+                // into the conference.
+                // We should add support for RemoteConnection#setConferenceables, which accepts a
+                // list of remote conferences and connections in the future.
+                conferenceables.addAll(conferenceParticipantsSet);
+
                 ((Connection) c).setConferenceables(conferenceables);
             } else if (c instanceof Conference) {
                 // Remove all conferences from the set, since we can not conference a conference
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index ef2b414..078b025 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -683,7 +683,7 @@
         }
     }
 
-    public void performConference(TelephonyConnection otherConnection) {
+    public void performConference(Connection otherConnection) {
         Log.d(this, "performConference - %s", this);
         if (getPhone() != null) {
             try {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 77a7cfb..279f087 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -617,14 +617,35 @@
         }
     }
 
+    /**
+     * Conferences two connections.
+     *
+     * Note: The {@link android.telecom.RemoteConnection#setConferenceableConnections(List)} API has
+     * a limitation in that it can only specify conferenceables which are instances of
+     * {@link android.telecom.RemoteConnection}.  In the case of an {@link ImsConference}, the
+     * regular {@link Connection#setConferenceables(List)} API properly handles being able to merge
+     * a {@link Conference} and a {@link Connection}.  As a result when, merging a
+     * {@link android.telecom.RemoteConnection} into a {@link android.telecom.RemoteConference}
+     * require merging a {@link ConferenceParticipantConnection} which is a child of the
+     * {@link Conference} with a {@link TelephonyConnection}.  The
+     * {@link ConferenceParticipantConnection} class does not have the capability to initiate a
+     * conference merge, so we need to call
+     * {@link TelephonyConnection#performConference(Connection)} on either {@code connection1} or
+     * {@code connection2}, one of which is an instance of {@link TelephonyConnection}.
+     *
+     * @param connection1 A connection to merge into a conference call.
+     * @param connection2 A connection to merge into a conference call.
+     */
     @Override
     public void onConference(Connection connection1, Connection connection2) {
-        if (connection1 instanceof TelephonyConnection &&
-                connection2 instanceof TelephonyConnection) {
-            ((TelephonyConnection) connection1).performConference(
-                (TelephonyConnection) connection2);
+        if (connection1 instanceof TelephonyConnection) {
+            ((TelephonyConnection) connection1).performConference(connection2);
+        } else if (connection2 instanceof TelephonyConnection) {
+            ((TelephonyConnection) connection2).performConference(connection1);
+        } else {
+            Log.w(this, "onConference - cannot merge connections " +
+                    "Connection1: %s, Connection2: %2", connection1, connection2);
         }
-
     }
 
     private boolean isRadioOn() {