1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.telecom;
18
19import com.android.internal.telecom.IConnectionService;
20
21import android.annotation.SystemApi;
22import android.os.RemoteException;
23
24import java.util.ArrayList;
25import java.util.Collections;
26import java.util.List;
27import java.util.Set;
28import java.util.concurrent.CopyOnWriteArrayList;
29import java.util.concurrent.CopyOnWriteArraySet;
30
31/**
32 * Represents a conference call which can contain any number of {@link Connection} objects.
33 * @hide
34 */
35@SystemApi
36public final class RemoteConference {
37
38    public abstract static class Callback {
39        public void onStateChanged(RemoteConference conference, int oldState, int newState) {}
40        public void onDisconnected(RemoteConference conference, DisconnectCause disconnectCause) {}
41        public void onConnectionAdded(RemoteConference conference, RemoteConnection connection) {}
42        public void onConnectionRemoved(RemoteConference conference, RemoteConnection connection) {}
43        public void onConnectionCapabilitiesChanged(
44                RemoteConference conference,
45                int connectionCapabilities) {}
46        public void onConferenceableConnectionsChanged(
47                RemoteConference conference,
48                List<RemoteConnection> conferenceableConnections) {}
49        public void onDestroyed(RemoteConference conference) {}
50    }
51
52    private final String mId;
53    private final IConnectionService mConnectionService;
54
55    private final Set<Callback> mCallbacks = new CopyOnWriteArraySet<>();
56    private final List<RemoteConnection> mChildConnections = new CopyOnWriteArrayList<>();
57    private final List<RemoteConnection> mUnmodifiableChildConnections =
58            Collections.unmodifiableList(mChildConnections);
59    private final List<RemoteConnection> mConferenceableConnections = new ArrayList<>();
60    private final List<RemoteConnection> mUnmodifiableConferenceableConnections =
61            Collections.unmodifiableList(mConferenceableConnections);
62
63    private int mState = Connection.STATE_NEW;
64    private DisconnectCause mDisconnectCause;
65    private int mConnectionCapabilities;
66
67    /** {@hide} */
68    RemoteConference(String id, IConnectionService connectionService) {
69        mId = id;
70        mConnectionService = connectionService;
71    }
72
73    /** {@hide} */
74    String getId() {
75        return mId;
76    }
77
78    /** {@hide} */
79    void setDestroyed() {
80        for (RemoteConnection connection : mChildConnections) {
81            connection.setConference(null);
82        }
83        for (Callback c : mCallbacks) {
84            c.onDestroyed(this);
85        }
86    }
87
88    /** {@hide} */
89    void setState(int newState) {
90        if (newState != Connection.STATE_ACTIVE &&
91                newState != Connection.STATE_HOLDING &&
92                newState != Connection.STATE_DISCONNECTED) {
93            Log.w(this, "Unsupported state transition for Conference call.",
94                    Connection.stateToString(newState));
95            return;
96        }
97
98        if (mState != newState) {
99            int oldState = mState;
100            mState = newState;
101            for (Callback c : mCallbacks) {
102                c.onStateChanged(this, oldState, newState);
103            }
104        }
105    }
106
107    /** {@hide} */
108    void addConnection(RemoteConnection connection) {
109        if (!mChildConnections.contains(connection)) {
110            mChildConnections.add(connection);
111            connection.setConference(this);
112            for (Callback c : mCallbacks) {
113                c.onConnectionAdded(this, connection);
114            }
115        }
116    }
117
118    /** {@hide} */
119    void removeConnection(RemoteConnection connection) {
120        if (mChildConnections.contains(connection)) {
121            mChildConnections.remove(connection);
122            connection.setConference(null);
123            for (Callback c : mCallbacks) {
124                c.onConnectionRemoved(this, connection);
125            }
126        }
127    }
128
129    /** {@hide} */
130    void setConnectionCapabilities(int connectionCapabilities) {
131        if (mConnectionCapabilities != connectionCapabilities) {
132            mConnectionCapabilities = connectionCapabilities;
133            for (Callback c : mCallbacks) {
134                c.onConnectionCapabilitiesChanged(this, mConnectionCapabilities);
135            }
136        }
137    }
138
139    /** @hide */
140    void setConferenceableConnections(List<RemoteConnection> conferenceableConnections) {
141        mConferenceableConnections.clear();
142        mConferenceableConnections.addAll(conferenceableConnections);
143        for (Callback c : mCallbacks) {
144            c.onConferenceableConnectionsChanged(this, mUnmodifiableConferenceableConnections);
145        }
146    }
147
148    /** {@hide} */
149    void setDisconnected(DisconnectCause disconnectCause) {
150        if (mState != Connection.STATE_DISCONNECTED) {
151            mDisconnectCause = disconnectCause;
152            setState(Connection.STATE_DISCONNECTED);
153            for (Callback c : mCallbacks) {
154                c.onDisconnected(this, disconnectCause);
155            }
156        }
157    }
158
159    public final List<RemoteConnection> getConnections() {
160        return mUnmodifiableChildConnections;
161    }
162
163    public final int getState() {
164        return mState;
165    }
166
167    /** @hide */
168    @Deprecated public final int getCallCapabilities() {
169        return getConnectionCapabilities();
170    }
171
172    public final int getConnectionCapabilities() {
173        return mConnectionCapabilities;
174    }
175
176    public void disconnect() {
177        try {
178            mConnectionService.disconnect(mId);
179        } catch (RemoteException e) {
180        }
181    }
182
183    public void separate(RemoteConnection connection) {
184        if (mChildConnections.contains(connection)) {
185            try {
186                mConnectionService.splitFromConference(connection.getId());
187            } catch (RemoteException e) {
188            }
189        }
190    }
191
192    public void merge() {
193        try {
194            mConnectionService.mergeConference(mId);
195        } catch (RemoteException e) {
196        }
197    }
198
199    public void swap() {
200        try {
201            mConnectionService.swapConference(mId);
202        } catch (RemoteException e) {
203        }
204    }
205
206    public void hold() {
207        try {
208            mConnectionService.hold(mId);
209        } catch (RemoteException e) {
210        }
211    }
212
213    public void unhold() {
214        try {
215            mConnectionService.unhold(mId);
216        } catch (RemoteException e) {
217        }
218    }
219
220    public DisconnectCause getDisconnectCause() {
221        return mDisconnectCause;
222    }
223
224    public void playDtmfTone(char digit) {
225        try {
226            mConnectionService.playDtmfTone(mId, digit);
227        } catch (RemoteException e) {
228        }
229    }
230
231    public void stopDtmfTone() {
232        try {
233            mConnectionService.stopDtmfTone(mId);
234        } catch (RemoteException e) {
235        }
236    }
237
238    public void setAudioState(AudioState state) {
239        try {
240            mConnectionService.onAudioStateChanged(mId, state);
241        } catch (RemoteException e) {
242        }
243    }
244
245    public List<RemoteConnection> getConferenceableConnections() {
246        return mUnmodifiableConferenceableConnections;
247    }
248
249    public final void registerCallback(Callback callback) {
250        mCallbacks.add(callback);
251    }
252
253    public final void unregisterCallback(Callback callback) {
254        mCallbacks.remove(callback);
255    }
256}
257