Loading telecomm/java/android/telecom/Conference.java +29 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ import java.util.concurrent.CopyOnWriteArraySet; * @hide */ @SystemApi public abstract class Conference { public abstract class Conference implements IConferenceable { /** @hide */ public abstract static class Listener { Loading Loading @@ -182,6 +182,13 @@ public abstract class Conference { */ public void onAudioStateChanged(AudioState state) {} /** * Notifies this conference that a connection has been added to it. * * @param connection The newly added connection. */ public void onConnectionAdded(Connection connection) {} /** * Sets state to be on hold. */ Loading Loading @@ -210,6 +217,13 @@ public abstract class Conference { } } /** * @return The {@link DisconnectCause} for this connection. */ public final DisconnectCause getDisconnectCause() { return mDisconnectCause; } /** * Sets the capabilities of a conference. See {@link PhoneCapabilities} for valid values. * Loading @@ -235,6 +249,7 @@ public abstract class Conference { if (connection != null && !mChildConnections.contains(connection)) { if (connection.setConference(this)) { mChildConnections.add(connection); onConnectionAdded(connection); for (Listener l : mListeners) { l.onConnectionAdded(this, connection); } Loading Loading @@ -337,6 +352,19 @@ public abstract class Conference { return this; } /** * 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. * Loading telecomm/java/android/telecom/ConferenceParticipant.aidl 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * 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 android.telecom; /** * {@hide} */ parcelable ConferenceParticipant; telecomm/java/android/telecom/ConferenceParticipant.java 0 → 100644 +158 −0 Original line number Diff line number Diff line /* * 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 android.telecom; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; /** * Parcelable representation of a participant's state in a conference call. * @hide */ public class ConferenceParticipant implements Parcelable { /** * The conference participant's handle (e.g., phone number). */ private final Uri mHandle; /** * The display name for the participant. */ private final String mDisplayName; /** * The endpoint Uri which uniquely identifies this conference participant. E.g. for an IMS * conference call, this is the endpoint URI for the participant on the IMS conference server. */ private final Uri mEndpoint; /** * The state of the participant in the conference. * * @see android.telecom.Connection */ private final int mState; /** * Creates an instance of {@code ConferenceParticipant}. * * @param handle The conference participant's handle (e.g., phone number). * @param displayName The display name for the participant. * @param endpoint The enpoint Uri which uniquely identifies this conference participant. * @param state The state of the participant in the conference. */ public ConferenceParticipant(Uri handle, String displayName, Uri endpoint, int state) { mHandle = handle; mDisplayName = displayName; mEndpoint = endpoint; mState = state; } /** * Responsible for creating {@code ConferenceParticipant} objects for deserialized Parcels. */ public static final Parcelable.Creator<ConferenceParticipant> CREATOR = new Parcelable.Creator<ConferenceParticipant>() { @Override public ConferenceParticipant createFromParcel(Parcel source) { ClassLoader classLoader = ParcelableCall.class.getClassLoader(); Uri handle = source.readParcelable(classLoader); String displayName = source.readString(); Uri endpoint = source.readParcelable(classLoader); int state = source.readInt(); return new ConferenceParticipant(handle, displayName, endpoint, state); } @Override public ConferenceParticipant[] newArray(int size) { return new ConferenceParticipant[size]; } }; @Override public int describeContents() { return 0; } /** * Writes the {@code ConferenceParticipant} to a parcel. * * @param dest The Parcel in which the object should be written. * @param flags Additional flags about how the object should be written. */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(mHandle, 0); dest.writeString(mDisplayName); dest.writeParcelable(mEndpoint, 0); dest.writeInt(mState); } /** * Builds a string representation of this instance. * * @return String representing the conference participant. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[ConferenceParticipant Handle: "); sb.append(mHandle); sb.append(" DisplayName: "); sb.append(mDisplayName); sb.append(" Endpoint: "); sb.append(mEndpoint); sb.append(" State: "); sb.append(mState); sb.append("]"); return sb.toString(); } /** * The conference participant's handle (e.g., phone number). */ public Uri getHandle() { return mHandle; } /** * The display name for the participant. */ public String getDisplayName() { return mDisplayName; } /** * The enpoint Uri which uniquely identifies this conference participant. E.g. for an IMS * conference call, this is the endpoint URI for the participant on the IMS conference server. */ public Uri getEndpoint() { return mEndpoint; } /** * The state of the participant in the conference. * * @see android.telecom.Connection */ public int getState() { return mState; } } telecomm/java/android/telecom/Connection.java +87 −16 Original line number Diff line number Diff line Loading @@ -48,7 +48,7 @@ import java.util.concurrent.ConcurrentHashMap; * @hide */ @SystemApi public abstract class Connection { public abstract class Connection implements IConferenceable { private static final boolean DBG = false; Loading Loading @@ -106,11 +106,14 @@ public abstract class Connection { Connection c, VideoProvider videoProvider) {} public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {} public void onStatusHintsChanged(Connection c, StatusHints statusHints) {} public void onConferenceableConnectionsChanged( Connection c, List<Connection> conferenceableConnections) {} public void onConferenceablesChanged( Connection c, List<IConferenceable> conferenceables) {} public void onConferenceChanged(Connection c, Conference conference) {} public void onPhoneAccountChanged(Connection c, PhoneAccountHandle pHandle) {} public void onCallSubstateChanged(Connection c, int substate) {} /** @hide */ public void onConferenceParticipantsChanged(Connection c, List<ConferenceParticipant> participants) {} } /** @hide */ Loading Loading @@ -492,7 +495,16 @@ public abstract class Connection { private final Listener mConnectionDeathListener = new Listener() { @Override public void onDestroyed(Connection c) { if (mConferenceableConnections.remove(c)) { if (mConferenceables.remove(c)) { fireOnConferenceableConnectionsChanged(); } } }; private final Conference.Listener mConferenceDeathListener = new Conference.Listener() { @Override public void onDestroyed(Conference c) { if (mConferenceables.remove(c)) { fireOnConferenceableConnectionsChanged(); } } Loading @@ -505,9 +517,9 @@ public abstract class Connection { */ private final Set<Listener> mListeners = Collections.newSetFromMap( new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); private final List<Connection> mConferenceableConnections = new ArrayList<>(); private final List<Connection> mUnmodifiableConferenceableConnections = Collections.unmodifiableList(mConferenceableConnections); private final List<IConferenceable> mConferenceables = new ArrayList<>(); private final List<IConferenceable> mUnmodifiableConferenceables = Collections.unmodifiableList(mConferenceables); private int mState = STATE_NEW; private AudioState mAudioState; Loading Loading @@ -964,19 +976,44 @@ public abstract class Connection { for (Connection c : conferenceableConnections) { // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a // small amount of items here. if (!mConferenceableConnections.contains(c)) { if (!mConferenceables.contains(c)) { c.addConnectionListener(mConnectionDeathListener); mConferenceableConnections.add(c); mConferenceables.add(c); } } fireOnConferenceableConnectionsChanged(); } /** * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections * or conferences with which this connection can be conferenced. * * @param conferenceables The conferenceables. */ public final void setConferenceables(List<IConferenceable> conferenceables) { clearConferenceableList(); for (IConferenceable c : conferenceables) { // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a // small amount of items here. if (!mConferenceables.contains(c)) { if (c instanceof Connection) { Connection connection = (Connection) c; connection.addConnectionListener(mConnectionDeathListener); } else if (c instanceof Conference) { Conference conference = (Conference) c; conference.addListener(mConferenceDeathListener); } mConferenceables.add(c); } } fireOnConferenceableConnectionsChanged(); } /** * Returns the connections with which this connection can be conferenced. * Returns the connections or conferences with which this connection can be conferenced. */ public final List<Connection> getConferenceableConnections() { return mUnmodifiableConferenceableConnections; public final List<IConferenceable> getConferenceables() { return mUnmodifiableConferenceables; } /** Loading Loading @@ -1041,6 +1078,7 @@ public abstract class Connection { mConference = conference; if (mConnectionService != null && mConnectionService.containsConference(conference)) { fireConferenceChanged(); onConferenceChanged(); } return true; } Loading Loading @@ -1103,6 +1141,15 @@ public abstract class Connection { */ public void onDisconnect() {} /** * Notifies this Connection of a request to disconnect a participant of the conference managed * by the connection. * * @param endpoint the {@link Uri} of the participant to disconnect. * @hide */ public void onDisconnectConferenceParticipant(Uri endpoint) {} /** * Notifies this Connection of a request to separate from its parent conference. */ Loading Loading @@ -1168,6 +1215,11 @@ public abstract class Connection { */ public void onConferenceWith(Connection otherConnection) {} /** * Notifies this Connection that the conference which is set on it has changed. */ public void onConferenceChanged() {} static String toLogSafePhoneNumber(String number) { // For unknown number, log empty string. if (number == null) { Loading Loading @@ -1246,7 +1298,7 @@ public abstract class Connection { private final void fireOnConferenceableConnectionsChanged() { for (Listener l : mListeners) { l.onConferenceableConnectionsChanged(this, getConferenceableConnections()); l.onConferenceablesChanged(this, getConferenceables()); } } Loading @@ -1257,9 +1309,28 @@ public abstract class Connection { } private final void clearConferenceableList() { for (Connection c : mConferenceableConnections) { c.removeConnectionListener(mConnectionDeathListener); for (IConferenceable c : mConferenceables) { if (c instanceof Connection) { Connection connection = (Connection) c; connection.removeConnectionListener(mConnectionDeathListener); } else if (c instanceof Conference) { Conference conference = (Conference) c; conference.removeListener(mConferenceDeathListener); } } mConferenceables.clear(); } /** * Notifies listeners of a change to conference participant(s). * * @param conferenceParticipants The participants. * @hide */ protected final void updateConferenceParticipants( List<ConferenceParticipant> conferenceParticipants) { for (Listener l : mListeners) { l.onConferenceParticipantsChanged(this, conferenceParticipants); } mConferenceableConnections.clear(); } } telecomm/java/android/telecom/ConnectionService.java +118 −9 Original line number Diff line number Diff line Loading @@ -555,11 +555,11 @@ public abstract class ConnectionService extends Service { } @Override public void onConferenceableConnectionsChanged( Connection connection, List<Connection> conferenceableConnections) { public void onConferenceablesChanged( Connection connection, List<IConferenceable> conferenceables) { mAdapter.setConferenceableConnections( mIdByConnection.get(connection), createConnectionIdList(conferenceableConnections)); createIdList(conferenceables)); } @Override Loading Loading @@ -662,7 +662,7 @@ public abstract class ConnectionService extends Service { connection.getAudioModeIsVoip(), connection.getStatusHints(), connection.getDisconnectCause(), createConnectionIdList(connection.getConferenceableConnections()), createIdList(connection.getConferenceables()), connection.getCallSubstate())); } Loading Loading @@ -770,12 +770,19 @@ public abstract class ConnectionService extends Service { private void conference(String callId1, String callId2) { Log.d(this, "conference %s, %s", callId1, callId2); // Attempt to get second connection or conference. Connection connection2 = findConnectionForAction(callId2, "conference"); Conference conference2 = getNullConference(); if (connection2 == getNullConnection()) { Log.w(this, "Connection2 missing in conference request %s.", callId2); conference2 = findConferenceForAction(callId2, "conference"); if (conference2 == getNullConference()) { Log.w(this, "Connection2 or Conference2 missing in conference request %s.", callId2); return; } } // Attempt to get first connection or conference and perform merge. Connection connection1 = findConnectionForAction(callId1, "conference"); if (connection1 == getNullConnection()) { Conference conference1 = findConferenceForAction(callId1, "addConnection"); Loading @@ -784,12 +791,28 @@ public abstract class ConnectionService extends Service { "Connection1 or Conference1 missing in conference request %s.", callId1); } else { // Call 1 is a conference. if (connection2 != getNullConnection()) { // Call 2 is a connection so merge via call 1 (conference). conference1.onMerge(connection2); } else { // Call 2 is ALSO a conference; this should never happen. Log.wtf(this, "There can only be one conference and an attempt was made to " + "merge two conferences."); return; } } } else { // Call 1 is a connection. if (conference2 != getNullConference()) { // Call 2 is a conference, so merge via call 2. conference2.onMerge(connection1); } else { // Call 2 is a connection, so merge together. onConference(connection1, connection2); } } } private void splitFromConference(String callId) { Log.d(this, "splitFromConference(%s)", callId); Loading Loading @@ -941,6 +964,41 @@ public abstract class ConnectionService extends Service { } } /** * 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, connection.getCallSubstate()); mAdapter.addExistingConnection(id, parcelableConnection); } } /** * Returns all the active {@code Connection}s for which this {@code ConnectionService} * has taken responsibility. Loading Loading @@ -1025,6 +1083,12 @@ public abstract class ConnectionService extends Service { 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 */ Loading @@ -1037,6 +1101,11 @@ public abstract class ConnectionService extends Service { onRemoteConferenceAdded(remoteConference); } /** {@hide} */ void addRemoteExistingConnection(RemoteConnection remoteConnection) { onRemoteExistingConnectionAdded(remoteConnection); } private void onAccountsInitialized() { mAreAccountsInitialized = true; for (Runnable r : mPreInitializationConnectionRequests) { Loading @@ -1045,6 +1114,18 @@ public abstract class ConnectionService extends Service { 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); Loading @@ -1052,7 +1133,8 @@ public abstract class ConnectionService extends Service { connection.setConnectionService(this); } private void removeConnection(Connection connection) { /** {@hide} */ protected void removeConnection(Connection connection) { String id = mIdByConnection.get(connection); connection.unsetConnectionService(this); connection.removeConnectionListener(mConnectionListener); Loading Loading @@ -1120,6 +1202,33 @@ public abstract class ConnectionService extends Service { return ids; } /** * Builds a list of {@link Connection} and {@link Conference} IDs based on the list of * {@link IConferenceable}s passed in. * * @param conferenceables The {@link IConferenceable} connections and conferences. * @return List of string conference and call Ids. */ private List<String> createIdList(List<IConferenceable> conferenceables) { List<String> ids = new ArrayList<>(); for (IConferenceable c : conferenceables) { // Only allow Connection and Conference conferenceables. if (c instanceof Connection) { Connection connection = (Connection) c; if (mIdByConnection.containsKey(connection)) { ids.add(mIdByConnection.get(connection)); } } else if (c instanceof Conference) { Conference conference = (Conference) c; if (mIdByConference.containsKey(conference)) { ids.add(mIdByConference.get(conference)); } } } Collections.sort(ids); return ids; } private Conference getNullConference() { if (sNullConference == null) { sNullConference = new Conference(null) {}; Loading Loading
telecomm/java/android/telecom/Conference.java +29 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ import java.util.concurrent.CopyOnWriteArraySet; * @hide */ @SystemApi public abstract class Conference { public abstract class Conference implements IConferenceable { /** @hide */ public abstract static class Listener { Loading Loading @@ -182,6 +182,13 @@ public abstract class Conference { */ public void onAudioStateChanged(AudioState state) {} /** * Notifies this conference that a connection has been added to it. * * @param connection The newly added connection. */ public void onConnectionAdded(Connection connection) {} /** * Sets state to be on hold. */ Loading Loading @@ -210,6 +217,13 @@ public abstract class Conference { } } /** * @return The {@link DisconnectCause} for this connection. */ public final DisconnectCause getDisconnectCause() { return mDisconnectCause; } /** * Sets the capabilities of a conference. See {@link PhoneCapabilities} for valid values. * Loading @@ -235,6 +249,7 @@ public abstract class Conference { if (connection != null && !mChildConnections.contains(connection)) { if (connection.setConference(this)) { mChildConnections.add(connection); onConnectionAdded(connection); for (Listener l : mListeners) { l.onConnectionAdded(this, connection); } Loading Loading @@ -337,6 +352,19 @@ public abstract class Conference { return this; } /** * 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. * Loading
telecomm/java/android/telecom/ConferenceParticipant.aidl 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * 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 android.telecom; /** * {@hide} */ parcelable ConferenceParticipant;
telecomm/java/android/telecom/ConferenceParticipant.java 0 → 100644 +158 −0 Original line number Diff line number Diff line /* * 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 android.telecom; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; /** * Parcelable representation of a participant's state in a conference call. * @hide */ public class ConferenceParticipant implements Parcelable { /** * The conference participant's handle (e.g., phone number). */ private final Uri mHandle; /** * The display name for the participant. */ private final String mDisplayName; /** * The endpoint Uri which uniquely identifies this conference participant. E.g. for an IMS * conference call, this is the endpoint URI for the participant on the IMS conference server. */ private final Uri mEndpoint; /** * The state of the participant in the conference. * * @see android.telecom.Connection */ private final int mState; /** * Creates an instance of {@code ConferenceParticipant}. * * @param handle The conference participant's handle (e.g., phone number). * @param displayName The display name for the participant. * @param endpoint The enpoint Uri which uniquely identifies this conference participant. * @param state The state of the participant in the conference. */ public ConferenceParticipant(Uri handle, String displayName, Uri endpoint, int state) { mHandle = handle; mDisplayName = displayName; mEndpoint = endpoint; mState = state; } /** * Responsible for creating {@code ConferenceParticipant} objects for deserialized Parcels. */ public static final Parcelable.Creator<ConferenceParticipant> CREATOR = new Parcelable.Creator<ConferenceParticipant>() { @Override public ConferenceParticipant createFromParcel(Parcel source) { ClassLoader classLoader = ParcelableCall.class.getClassLoader(); Uri handle = source.readParcelable(classLoader); String displayName = source.readString(); Uri endpoint = source.readParcelable(classLoader); int state = source.readInt(); return new ConferenceParticipant(handle, displayName, endpoint, state); } @Override public ConferenceParticipant[] newArray(int size) { return new ConferenceParticipant[size]; } }; @Override public int describeContents() { return 0; } /** * Writes the {@code ConferenceParticipant} to a parcel. * * @param dest The Parcel in which the object should be written. * @param flags Additional flags about how the object should be written. */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(mHandle, 0); dest.writeString(mDisplayName); dest.writeParcelable(mEndpoint, 0); dest.writeInt(mState); } /** * Builds a string representation of this instance. * * @return String representing the conference participant. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[ConferenceParticipant Handle: "); sb.append(mHandle); sb.append(" DisplayName: "); sb.append(mDisplayName); sb.append(" Endpoint: "); sb.append(mEndpoint); sb.append(" State: "); sb.append(mState); sb.append("]"); return sb.toString(); } /** * The conference participant's handle (e.g., phone number). */ public Uri getHandle() { return mHandle; } /** * The display name for the participant. */ public String getDisplayName() { return mDisplayName; } /** * The enpoint Uri which uniquely identifies this conference participant. E.g. for an IMS * conference call, this is the endpoint URI for the participant on the IMS conference server. */ public Uri getEndpoint() { return mEndpoint; } /** * The state of the participant in the conference. * * @see android.telecom.Connection */ public int getState() { return mState; } }
telecomm/java/android/telecom/Connection.java +87 −16 Original line number Diff line number Diff line Loading @@ -48,7 +48,7 @@ import java.util.concurrent.ConcurrentHashMap; * @hide */ @SystemApi public abstract class Connection { public abstract class Connection implements IConferenceable { private static final boolean DBG = false; Loading Loading @@ -106,11 +106,14 @@ public abstract class Connection { Connection c, VideoProvider videoProvider) {} public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {} public void onStatusHintsChanged(Connection c, StatusHints statusHints) {} public void onConferenceableConnectionsChanged( Connection c, List<Connection> conferenceableConnections) {} public void onConferenceablesChanged( Connection c, List<IConferenceable> conferenceables) {} public void onConferenceChanged(Connection c, Conference conference) {} public void onPhoneAccountChanged(Connection c, PhoneAccountHandle pHandle) {} public void onCallSubstateChanged(Connection c, int substate) {} /** @hide */ public void onConferenceParticipantsChanged(Connection c, List<ConferenceParticipant> participants) {} } /** @hide */ Loading Loading @@ -492,7 +495,16 @@ public abstract class Connection { private final Listener mConnectionDeathListener = new Listener() { @Override public void onDestroyed(Connection c) { if (mConferenceableConnections.remove(c)) { if (mConferenceables.remove(c)) { fireOnConferenceableConnectionsChanged(); } } }; private final Conference.Listener mConferenceDeathListener = new Conference.Listener() { @Override public void onDestroyed(Conference c) { if (mConferenceables.remove(c)) { fireOnConferenceableConnectionsChanged(); } } Loading @@ -505,9 +517,9 @@ public abstract class Connection { */ private final Set<Listener> mListeners = Collections.newSetFromMap( new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); private final List<Connection> mConferenceableConnections = new ArrayList<>(); private final List<Connection> mUnmodifiableConferenceableConnections = Collections.unmodifiableList(mConferenceableConnections); private final List<IConferenceable> mConferenceables = new ArrayList<>(); private final List<IConferenceable> mUnmodifiableConferenceables = Collections.unmodifiableList(mConferenceables); private int mState = STATE_NEW; private AudioState mAudioState; Loading Loading @@ -964,19 +976,44 @@ public abstract class Connection { for (Connection c : conferenceableConnections) { // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a // small amount of items here. if (!mConferenceableConnections.contains(c)) { if (!mConferenceables.contains(c)) { c.addConnectionListener(mConnectionDeathListener); mConferenceableConnections.add(c); mConferenceables.add(c); } } fireOnConferenceableConnectionsChanged(); } /** * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections * or conferences with which this connection can be conferenced. * * @param conferenceables The conferenceables. */ public final void setConferenceables(List<IConferenceable> conferenceables) { clearConferenceableList(); for (IConferenceable c : conferenceables) { // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a // small amount of items here. if (!mConferenceables.contains(c)) { if (c instanceof Connection) { Connection connection = (Connection) c; connection.addConnectionListener(mConnectionDeathListener); } else if (c instanceof Conference) { Conference conference = (Conference) c; conference.addListener(mConferenceDeathListener); } mConferenceables.add(c); } } fireOnConferenceableConnectionsChanged(); } /** * Returns the connections with which this connection can be conferenced. * Returns the connections or conferences with which this connection can be conferenced. */ public final List<Connection> getConferenceableConnections() { return mUnmodifiableConferenceableConnections; public final List<IConferenceable> getConferenceables() { return mUnmodifiableConferenceables; } /** Loading Loading @@ -1041,6 +1078,7 @@ public abstract class Connection { mConference = conference; if (mConnectionService != null && mConnectionService.containsConference(conference)) { fireConferenceChanged(); onConferenceChanged(); } return true; } Loading Loading @@ -1103,6 +1141,15 @@ public abstract class Connection { */ public void onDisconnect() {} /** * Notifies this Connection of a request to disconnect a participant of the conference managed * by the connection. * * @param endpoint the {@link Uri} of the participant to disconnect. * @hide */ public void onDisconnectConferenceParticipant(Uri endpoint) {} /** * Notifies this Connection of a request to separate from its parent conference. */ Loading Loading @@ -1168,6 +1215,11 @@ public abstract class Connection { */ public void onConferenceWith(Connection otherConnection) {} /** * Notifies this Connection that the conference which is set on it has changed. */ public void onConferenceChanged() {} static String toLogSafePhoneNumber(String number) { // For unknown number, log empty string. if (number == null) { Loading Loading @@ -1246,7 +1298,7 @@ public abstract class Connection { private final void fireOnConferenceableConnectionsChanged() { for (Listener l : mListeners) { l.onConferenceableConnectionsChanged(this, getConferenceableConnections()); l.onConferenceablesChanged(this, getConferenceables()); } } Loading @@ -1257,9 +1309,28 @@ public abstract class Connection { } private final void clearConferenceableList() { for (Connection c : mConferenceableConnections) { c.removeConnectionListener(mConnectionDeathListener); for (IConferenceable c : mConferenceables) { if (c instanceof Connection) { Connection connection = (Connection) c; connection.removeConnectionListener(mConnectionDeathListener); } else if (c instanceof Conference) { Conference conference = (Conference) c; conference.removeListener(mConferenceDeathListener); } } mConferenceables.clear(); } /** * Notifies listeners of a change to conference participant(s). * * @param conferenceParticipants The participants. * @hide */ protected final void updateConferenceParticipants( List<ConferenceParticipant> conferenceParticipants) { for (Listener l : mListeners) { l.onConferenceParticipantsChanged(this, conferenceParticipants); } mConferenceableConnections.clear(); } }
telecomm/java/android/telecom/ConnectionService.java +118 −9 Original line number Diff line number Diff line Loading @@ -555,11 +555,11 @@ public abstract class ConnectionService extends Service { } @Override public void onConferenceableConnectionsChanged( Connection connection, List<Connection> conferenceableConnections) { public void onConferenceablesChanged( Connection connection, List<IConferenceable> conferenceables) { mAdapter.setConferenceableConnections( mIdByConnection.get(connection), createConnectionIdList(conferenceableConnections)); createIdList(conferenceables)); } @Override Loading Loading @@ -662,7 +662,7 @@ public abstract class ConnectionService extends Service { connection.getAudioModeIsVoip(), connection.getStatusHints(), connection.getDisconnectCause(), createConnectionIdList(connection.getConferenceableConnections()), createIdList(connection.getConferenceables()), connection.getCallSubstate())); } Loading Loading @@ -770,12 +770,19 @@ public abstract class ConnectionService extends Service { private void conference(String callId1, String callId2) { Log.d(this, "conference %s, %s", callId1, callId2); // Attempt to get second connection or conference. Connection connection2 = findConnectionForAction(callId2, "conference"); Conference conference2 = getNullConference(); if (connection2 == getNullConnection()) { Log.w(this, "Connection2 missing in conference request %s.", callId2); conference2 = findConferenceForAction(callId2, "conference"); if (conference2 == getNullConference()) { Log.w(this, "Connection2 or Conference2 missing in conference request %s.", callId2); return; } } // Attempt to get first connection or conference and perform merge. Connection connection1 = findConnectionForAction(callId1, "conference"); if (connection1 == getNullConnection()) { Conference conference1 = findConferenceForAction(callId1, "addConnection"); Loading @@ -784,12 +791,28 @@ public abstract class ConnectionService extends Service { "Connection1 or Conference1 missing in conference request %s.", callId1); } else { // Call 1 is a conference. if (connection2 != getNullConnection()) { // Call 2 is a connection so merge via call 1 (conference). conference1.onMerge(connection2); } else { // Call 2 is ALSO a conference; this should never happen. Log.wtf(this, "There can only be one conference and an attempt was made to " + "merge two conferences."); return; } } } else { // Call 1 is a connection. if (conference2 != getNullConference()) { // Call 2 is a conference, so merge via call 2. conference2.onMerge(connection1); } else { // Call 2 is a connection, so merge together. onConference(connection1, connection2); } } } private void splitFromConference(String callId) { Log.d(this, "splitFromConference(%s)", callId); Loading Loading @@ -941,6 +964,41 @@ public abstract class ConnectionService extends Service { } } /** * 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, connection.getCallSubstate()); mAdapter.addExistingConnection(id, parcelableConnection); } } /** * Returns all the active {@code Connection}s for which this {@code ConnectionService} * has taken responsibility. Loading Loading @@ -1025,6 +1083,12 @@ public abstract class ConnectionService extends Service { 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 */ Loading @@ -1037,6 +1101,11 @@ public abstract class ConnectionService extends Service { onRemoteConferenceAdded(remoteConference); } /** {@hide} */ void addRemoteExistingConnection(RemoteConnection remoteConnection) { onRemoteExistingConnectionAdded(remoteConnection); } private void onAccountsInitialized() { mAreAccountsInitialized = true; for (Runnable r : mPreInitializationConnectionRequests) { Loading @@ -1045,6 +1114,18 @@ public abstract class ConnectionService extends Service { 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); Loading @@ -1052,7 +1133,8 @@ public abstract class ConnectionService extends Service { connection.setConnectionService(this); } private void removeConnection(Connection connection) { /** {@hide} */ protected void removeConnection(Connection connection) { String id = mIdByConnection.get(connection); connection.unsetConnectionService(this); connection.removeConnectionListener(mConnectionListener); Loading Loading @@ -1120,6 +1202,33 @@ public abstract class ConnectionService extends Service { return ids; } /** * Builds a list of {@link Connection} and {@link Conference} IDs based on the list of * {@link IConferenceable}s passed in. * * @param conferenceables The {@link IConferenceable} connections and conferences. * @return List of string conference and call Ids. */ private List<String> createIdList(List<IConferenceable> conferenceables) { List<String> ids = new ArrayList<>(); for (IConferenceable c : conferenceables) { // Only allow Connection and Conference conferenceables. if (c instanceof Connection) { Connection connection = (Connection) c; if (mIdByConnection.containsKey(connection)) { ids.add(mIdByConnection.get(connection)); } } else if (c instanceof Conference) { Conference conference = (Conference) c; if (mIdByConference.containsKey(conference)) { ids.add(mIdByConference.get(conference)); } } } Collections.sort(ids); return ids; } private Conference getNullConference() { if (sNullConference == null) { sNullConference = new Conference(null) {}; Loading