Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6344512c authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "Creating connections for conference event package participants."

parents e174a94c ad3b2b83
Loading
Loading
Loading
Loading
+29 −1
Original line number Diff line number Diff line
@@ -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 {
@@ -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.
     */
@@ -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.
     *
@@ -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);
                }
@@ -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.
     *
+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;
+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;
    }
}
+87 −16
Original line number Diff line number Diff line
@@ -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;

@@ -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 */
@@ -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();
            }
        }
@@ -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;
@@ -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;
    }

    /**
@@ -1041,6 +1078,7 @@ public abstract class Connection {
            mConference = conference;
            if (mConnectionService != null && mConnectionService.containsConference(conference)) {
                fireConferenceChanged();
                onConferenceChanged();
            }
            return true;
        }
@@ -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.
     */
@@ -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) {
@@ -1246,7 +1298,7 @@ public abstract class Connection {

    private final void  fireOnConferenceableConnectionsChanged() {
        for (Listener l : mListeners) {
            l.onConferenceableConnectionsChanged(this, getConferenceableConnections());
            l.onConferenceablesChanged(this, getConferenceables());
        }
    }

@@ -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();
    }
}
+118 −9
Original line number Diff line number Diff line
@@ -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
@@ -662,7 +662,7 @@ public abstract class ConnectionService extends Service {
                        connection.getAudioModeIsVoip(),
                        connection.getStatusHints(),
                        connection.getDisconnectCause(),
                        createConnectionIdList(connection.getConferenceableConnections()),
                        createIdList(connection.getConferenceables()),
                        connection.getCallSubstate()));
    }

@@ -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");
@@ -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);
@@ -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.
@@ -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
     */
@@ -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) {
@@ -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);
@@ -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);
@@ -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