Creating connections for conference event package participants.

- Add "addExistingConnection" method to connection service which provides
a way for a connection service to notify telecom of a pre-existing
connection (connections are normally created through telecom).
- Modify TelephonyConferenceController to retrieve its state from a
multiparty connection in the conference (in the case of IMS calls, this
would be the ImsCall that manages the conference) instead of just taking
the first one.

Bug: 18057361
Change-Id: I26993aec54ecb0ce90ae6983fd3eed9d8d0a5773
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 15cb786..003d5cd 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -334,6 +334,19 @@
     }
 
     /**
+     * Retrieves the primary connection associated with the conference.  The primary connection is
+     * the connection from which the conference will retrieve its current state.
+     *
+     * @return The primary connection.
+     */
+    public Connection getPrimaryConnection() {
+        if (mUnmodifiableChildConnections == null || mUnmodifiableChildConnections.isEmpty()) {
+            return null;
+        }
+        return mUnmodifiableChildConnections.get(0);
+    }
+
+    /**
      * Inform this Conference that the state of its audio output has been changed externally.
      *
      * @param state The new audio state.
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 649533e..6e41c33 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -822,6 +822,40 @@
     }
 
     /**
+     * Adds a connection created by the {@link ConnectionService} and informs telecom of the new
+     * connection.
+     *
+     * @param phoneAccountHandle The phone account handle for the connection.
+     * @param connection The connection to add.
+     */
+    public final void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
+            Connection connection) {
+
+        String id = addExistingConnectionInternal(connection);
+        if (id != null) {
+            List<String> emptyList = new ArrayList<>(0);
+
+            ParcelableConnection parcelableConnection = new ParcelableConnection(
+                    phoneAccountHandle,
+                    connection.getState(),
+                    connection.getCallCapabilities(),
+                    connection.getAddress(),
+                    connection.getAddressPresentation(),
+                    connection.getCallerDisplayName(),
+                    connection.getCallerDisplayNamePresentation(),
+                    connection.getVideoProvider() == null ?
+                            null : connection.getVideoProvider().getInterface(),
+                    connection.getVideoState(),
+                    connection.isRingbackRequested(),
+                    connection.getAudioModeIsVoip(),
+                    connection.getStatusHints(),
+                    connection.getDisconnectCause(),
+                    emptyList);
+            mAdapter.addExistingConnection(id, parcelableConnection);
+        }
+    }
+
+    /**
      * Returns all the active {@code Connection}s for which this {@code ConnectionService}
      * has taken responsibility.
      *
@@ -906,6 +940,12 @@
     public void onRemoteConferenceAdded(RemoteConference conference) {}
 
     /**
+     * Called when an existing connection is added remotely.
+     * @param connection The existing connection which was added.
+     */
+    public void onRemoteExistingConnectionAdded(RemoteConnection connection) {}
+
+    /**
      * @hide
      */
     public boolean containsConference(Conference conference) {
@@ -917,6 +957,11 @@
         onRemoteConferenceAdded(remoteConference);
     }
 
+    /** {@hide} */
+    void addRemoteExistingConnection(RemoteConnection remoteConnection) {
+        onRemoteExistingConnectionAdded(remoteConnection);
+    }
+
     private void onAccountsInitialized() {
         mAreAccountsInitialized = true;
         for (Runnable r : mPreInitializationConnectionRequests) {
@@ -925,6 +970,18 @@
         mPreInitializationConnectionRequests.clear();
     }
 
+    /**
+     * Adds an existing connection to the list of connections, identified by a new UUID.
+     *
+     * @param connection The connection.
+     * @return The UUID of the connection (e.g. the call-id).
+     */
+    private String addExistingConnectionInternal(Connection connection) {
+        String id = UUID.randomUUID().toString();
+        addConnection(id, connection);
+        return id;
+    }
+
     private void addConnection(String callId, Connection connection) {
         mConnectionById.put(callId, connection);
         mIdByConnection.put(connection, callId);
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index c676172..e67af8c 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -344,4 +344,20 @@
             }
         }
     }
+
+    /**
+     * Informs telecom of an existing connection which was added by the {@link ConnectionService}.
+     *
+     * @param callId The unique ID of the call being added.
+     * @param connection The connection.
+     */
+    void addExistingConnection(String callId, ParcelableConnection connection) {
+        Log.v(this, "addExistingConnection: %s", callId);
+        for (IConnectionServiceAdapter adapter : mAdapters) {
+            try {
+                adapter.addExistingConnection(callId, connection);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 217dbc3..519a400 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -57,6 +57,7 @@
     private static final int MSG_SET_ADDRESS = 18;
     private static final int MSG_SET_CALLER_DISPLAY_NAME = 19;
     private static final int MSG_SET_CONFERENCEABLE_CONNECTIONS = 20;
+    private static final int MSG_ADD_EXISTING_CONNECTION = 21;
 
     private final IConnectionServiceAdapter mDelegate;
 
@@ -199,6 +200,16 @@
                     }
                     break;
                 }
+                case MSG_ADD_EXISTING_CONNECTION: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        mDelegate.addExistingConnection(
+                                (String) args.arg1, (ParcelableConnection) args.arg2);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
             }
         }
     };
@@ -345,6 +356,15 @@
             args.arg2 = conferenceableConnectionIds;
             mHandler.obtainMessage(MSG_SET_CONFERENCEABLE_CONNECTIONS, args).sendToTarget();
         }
+
+        @Override
+        public final void addExistingConnection(
+                String connectionId, ParcelableConnection connection) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = connectionId;
+            args.arg2 = connection;
+            mHandler.obtainMessage(MSG_ADD_EXISTING_CONNECTION, args).sendToTarget();
+        }
     };
 
     public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) {
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 9a094df..816e2bf 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -407,6 +407,29 @@
     }
 
     /**
+     * @hide
+     */
+    RemoteConnection(String callId, IConnectionService connectionService,
+            ParcelableConnection connection) {
+        mConnectionId = callId;
+        mConnectionService = connectionService;
+        mConnected = true;
+        mState = connection.getState();
+        mDisconnectCause = connection.getDisconnectCause();
+        mRingbackRequested = connection.isRingbackRequested();
+        mCallCapabilities = connection.getCapabilities();
+        mVideoState = connection.getVideoState();
+        mVideoProvider = new RemoteConnection.VideoProvider(connection.getVideoProvider());
+        mIsVoipAudioMode = connection.getIsVoipAudioMode();
+        mStatusHints = connection.getStatusHints();
+        mAddress = connection.getHandle();
+        mAddressPresentation = connection.getHandlePresentation();
+        mCallerDisplayName = connection.getCallerDisplayName();
+        mCallerDisplayNamePresentation = connection.getCallerDisplayNamePresentation();
+        mConference = null;
+    }
+
+    /**
      * Create a RemoteConnection which is used for failed connections. Note that using it for any
      * "real" purpose will almost certainly fail. Callers should note the failure and act
      * accordingly (moving on to another RemoteConnection, for example)
@@ -415,7 +438,7 @@
      * @hide
      */
     RemoteConnection(DisconnectCause disconnectCause) {
-        this("NULL", null, null);
+        mConnectionId = "NULL";
         mConnected = false;
         mState = Connection.STATE_DISCONNECTED;
         mDisconnectCause = disconnectCause;
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index af4ee22..4bb78c0 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -41,8 +41,9 @@
  */
 final class RemoteConnectionService {
 
+    // Note: Casting null to avoid ambiguous constructor reference.
     private static final RemoteConnection NULL_CONNECTION =
-            new RemoteConnection("NULL", null, null);
+            new RemoteConnection("NULL", null, (ConnectionRequest) null);
 
     private static final RemoteConference NULL_CONFERENCE =
             new RemoteConference("NULL", null);
@@ -286,6 +287,15 @@
                         .setConferenceableConnections(conferenceable);
             }
         }
+
+        @Override
+        public void addExistingConnection(String callId, ParcelableConnection connection) {
+            // TODO: add contents of this method
+            RemoteConnection remoteConnction = new RemoteConnection(callId,
+                    mOutgoingConnectionServiceRpc, connection);
+
+            mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnction);
+        }
     };
 
     private final ConnectionServiceAdapterServant mServant =