Merge "Communicating participant changes to conference controller." into lmp-mr1-dev
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
new file mode 100644
index 0000000..a1ed6a3
--- /dev/null
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.services.telephony;
+
+import com.android.internal.telephony.PhoneConstants;
+
+import android.net.Uri;
+import android.telecom.ConferenceParticipant;
+import android.telecom.Connection;
+import android.telecom.DisconnectCause;
+import android.telecom.PhoneCapabilities;
+
+/**
+ * Represents a participant in a conference call.
+ */
+public class ConferenceParticipantConnection extends Connection {
+
+    /**
+     * The endpoint URI For the conference participant.
+     */
+    private final Uri mEndpoint;
+
+    /**
+     * The connection which owns this participant.
+     */
+    private final Connection mParentConnection;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param participant The conference participant to create the instance for.
+     */
+    public ConferenceParticipantConnection(
+            Connection parentConnection, ConferenceParticipant participant) {
+
+        mParentConnection = parentConnection;
+        setAddress(participant.getHandle(), PhoneConstants.PRESENTATION_ALLOWED);
+        setCallerDisplayName(participant.getDisplayName(), PhoneConstants.PRESENTATION_ALLOWED);
+        updateState(participant.getState());
+        mEndpoint = participant.getEndpoint();
+        setCapabilities();
+    }
+
+    /**
+     * Changes the state of the conference participant.
+     *
+     * @param newState The new state.
+     */
+    public void updateState(int newState) {
+        switch (newState) {
+            case STATE_INITIALIZING:
+                setInitializing();
+                break;
+            case STATE_RINGING:
+                setRinging();
+                break;
+            case STATE_DIALING:
+                setDialing();
+                break;
+            case STATE_HOLDING:
+                setOnHold();
+                break;
+            case STATE_ACTIVE:
+                setActive();
+                break;
+            case STATE_DISCONNECTED:
+                setDisconnected(new DisconnectCause(DisconnectCause.REMOTE));
+                break;
+            default:
+                setActive();
+        }
+    }
+
+    /**
+     * Configures the {@link android.telecom.PhoneCapabilities} applicable to this connection.  A
+     * conference participant can only be disconnected from a conference since there is not
+     * actual connection to the participant which could be split from the conference.
+     */
+    private void setCapabilities() {
+        int capabilities = PhoneCapabilities.DISCONNECT_FROM_CONFERENCE;
+        setCallCapabilities(capabilities);
+    }
+}
diff --git a/src/com/android/services/telephony/TelephonyConferenceController.java b/src/com/android/services/telephony/TelephonyConferenceController.java
index 5786b25..b64464d 100644
--- a/src/com/android/services/telephony/TelephonyConferenceController.java
+++ b/src/com/android/services/telephony/TelephonyConferenceController.java
@@ -18,11 +18,14 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import android.net.Uri;
 import android.telecom.Conference;
+import android.telecom.ConferenceParticipant;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
 
@@ -53,11 +56,31 @@
         public void onDestroyed(Connection connection) {
             remove((TelephonyConnection) connection);
         }
+
+        /**
+         * Handles notifications from an connection that a participant in a conference has changed
+         * state.
+         *
+         * @param c The connection.
+         * @param participant The participant information.
+         */
+        @Override
+        public void onConferenceParticipantChanged(Connection c, ConferenceParticipant participant)
+        {
+            Log.v(this, "onConferenceParticipantChanged: %s", participant);
+            handleConferenceParticipantUpdate(c, participant);
+        }
     };
 
     /** The known connections. */
     private final List<TelephonyConnection> mTelephonyConnections = new ArrayList<>();
 
+    /**
+     * The known conference participant connections.  The HashMap is keyed by endpoint Uri.
+     */
+    private final HashMap<Uri, ConferenceParticipantConnection> mConferenceParticipantConnections =
+            new HashMap<>();
+
     private final TelephonyConnectionService mConnectionService;
 
     public TelephonyConferenceController(TelephonyConnectionService connectionService) {
@@ -218,4 +241,44 @@
             }
         }
     }
+
+    /**
+     * Handles state changes for a conference participant.
+     *
+     * @param parent The connection which was notified of the conference participant.
+     * @param participant The conference participant.
+     */
+    private void handleConferenceParticipantUpdate(
+            Connection parent, ConferenceParticipant participant) {
+
+        Uri endpoint = participant.getEndpoint();
+        if (!mConferenceParticipantConnections.containsKey(endpoint)) {
+            createConferenceParticipantConnection(parent, participant);
+        } else {
+            ConferenceParticipantConnection connection =
+                    mConferenceParticipantConnections.get(endpoint);
+            connection.updateState(participant.getState());
+        }
+    }
+
+    /**
+     * Creates a new {@link ConferenceParticipantConnection} to represent a
+     * {@link ConferenceParticipant}.
+     * <p>
+     * The new connection is added to the conference controller and connection service.
+     *
+     * @param parent The connection which was notified of the participant change (e.g. the
+     *                         parent connection).
+     * @param participant The conference participant information.
+     */
+    private void createConferenceParticipantConnection(
+            Connection parent, ConferenceParticipant participant) {
+
+        ConferenceParticipantConnection connection = new ConferenceParticipantConnection(
+                parent, participant);
+        connection.addConnectionListener(mConnectionListener);
+        mConferenceParticipantConnections.put(participant.getEndpoint(), connection);
+
+        // TODO: Inform telecom of the new participant.
+    }
 }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index b8d3142..3af7481 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -22,6 +22,7 @@
 import android.os.Message;
 import android.telecom.AudioState;
 import android.telecom.Conference;
+import android.telecom.ConferenceParticipant;
 import android.telecom.Connection;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneCapabilities;
@@ -140,6 +141,17 @@
         public void onAudioQualityChanged(int audioQuality) {
             setAudioQuality(audioQuality);
         }
+
+        /**
+         * Handles a change in the state of a conference participant, as reported by the
+         * {@link com.android.internal.telephony.Connection}.
+         *
+         * @param participant The participant which changed.
+         */
+        @Override
+        public void onConferenceParticipantChanged(ConferenceParticipant participant) {
+            updateConferenceParticipant(participant);
+        }
     };
 
     private com.android.internal.telephony.Connection mOriginalConnection;