Conference.java revision 8635c578f0408ca76cbaef5464d27bfde7450425
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 java.util.Collections; 20import java.util.List; 21import java.util.Set; 22import java.util.concurrent.CopyOnWriteArrayList; 23import java.util.concurrent.CopyOnWriteArraySet; 24 25/** 26 * Represents a conference call which can contain any number of {@link Connection} objects. 27 */ 28public abstract class Conference { 29 30 /** @hide */ 31 public abstract static class Listener { 32 public void onStateChanged(Conference conference, int oldState, int newState) {} 33 public void onDisconnected(Conference conference, DisconnectCause disconnectCause) {} 34 public void onConnectionAdded(Conference conference, Connection connection) {} 35 public void onConnectionRemoved(Conference conference, Connection connection) {} 36 public void onDestroyed(Conference conference) {} 37 public void onCapabilitiesChanged(Conference conference, int capabilities) {} 38 } 39 40 private final Set<Listener> mListeners = new CopyOnWriteArraySet<>(); 41 private final List<Connection> mChildConnections = new CopyOnWriteArrayList<>(); 42 private final List<Connection> mUnmodifiableChildConnections = 43 Collections.unmodifiableList(mChildConnections); 44 45 private PhoneAccountHandle mPhoneAccount; 46 private AudioState mAudioState; 47 private int mState = Connection.STATE_NEW; 48 private DisconnectCause mDisconnectCause; 49 private int mCapabilities; 50 private String mDisconnectMessage; 51 52 /** 53 * Constructs a new Conference with a mandatory {@link PhoneAccountHandle} 54 * 55 * @param phoneAccount The {@code PhoneAccountHandle} associated with the conference. 56 */ 57 public Conference(PhoneAccountHandle phoneAccount) { 58 mPhoneAccount = phoneAccount; 59 } 60 61 /** 62 * Returns the {@link PhoneAccountHandle} the conference call is being placed through. 63 * 64 * @return A {@code PhoneAccountHandle} object representing the PhoneAccount of the conference. 65 */ 66 public final PhoneAccountHandle getPhoneAccountHandle() { 67 return mPhoneAccount; 68 } 69 70 /** 71 * Returns the list of connections currently associated with the conference call. 72 * 73 * @return A list of {@code Connection} objects which represent the children of the conference. 74 */ 75 public final List<Connection> getConnections() { 76 return mUnmodifiableChildConnections; 77 } 78 79 /** 80 * Gets the state of the conference call. See {@link Connection} for valid values. 81 * 82 * @return A constant representing the state the conference call is currently in. 83 */ 84 public final int getState() { 85 return mState; 86 } 87 88 /** 89 * Returns the capabilities of a conference. See {@link PhoneCapabilities} for valid values. 90 * 91 * @return A bitmask of the {@code PhoneCapabilities} of the conference call. 92 */ 93 public final int getCapabilities() { 94 return mCapabilities; 95 } 96 97 /** 98 * @return The audio state of the conference, describing how its audio is currently 99 * being routed by the system. This is {@code null} if this Conference 100 * does not directly know about its audio state. 101 */ 102 public final AudioState getAudioState() { 103 return mAudioState; 104 } 105 106 /** 107 * Invoked when the Conference and all it's {@link Connection}s should be disconnected. 108 */ 109 public void onDisconnect() {} 110 111 /** 112 * Invoked when the specified {@link Connection} should be separated from the conference call. 113 * 114 * @param connection The connection to separate. 115 */ 116 public void onSeparate(Connection connection) {} 117 118 /** 119 * Invoked when the conference should be put on hold. 120 */ 121 public void onHold() {} 122 123 /** 124 * Invoked when the conference should be moved from hold to active. 125 */ 126 public void onUnhold() {} 127 128 /** 129 * Invoked when the child calls should be merged. Only invoked if the conference contains the 130 * capability {@link PhoneCapabilities#MERGE_CONFERENCE}. 131 */ 132 public void onMerge() {} 133 134 /** 135 * Invoked when the child calls should be swapped. Only invoked if the conference contains the 136 * capability {@link PhoneCapabilities#SWAP_CONFERENCE}. 137 */ 138 public void onSwap() {} 139 140 /** 141 * Notifies this conference of a request to play a DTMF tone. 142 * 143 * @param c A DTMF character. 144 */ 145 public void onPlayDtmfTone(char c) {} 146 147 /** 148 * Notifies this conference of a request to stop any currently playing DTMF tones. 149 */ 150 public void onStopDtmfTone() {} 151 152 /** 153 * Notifies this conference that the {@link #getAudioState()} property has a new value. 154 * 155 * @param state The new call audio state. 156 */ 157 public void onAudioStateChanged(AudioState state) {} 158 159 /** 160 * Sets state to be on hold. 161 */ 162 public final void setOnHold() { 163 setState(Connection.STATE_HOLDING); 164 } 165 166 /** 167 * Sets state to be active. 168 */ 169 public final void setActive() { 170 setState(Connection.STATE_ACTIVE); 171 } 172 173 /** 174 * Sets state to disconnected. 175 * 176 * @param disconnectCause The reason for the disconnection, as described by 177 * {@link android.telecom.DisconnectCause}. 178 */ 179 public final void setDisconnected(DisconnectCause disconnectCause) { 180 mDisconnectCause = disconnectCause;; 181 setState(Connection.STATE_DISCONNECTED); 182 for (Listener l : mListeners) { 183 l.onDisconnected(this, mDisconnectCause); 184 } 185 } 186 187 /** 188 * Sets the capabilities of a conference. See {@link PhoneCapabilities} for valid values. 189 * 190 * @param capabilities A bitmask of the {@code PhoneCapabilities} of the conference call. 191 */ 192 public final void setCapabilities(int capabilities) { 193 if (capabilities != mCapabilities) { 194 mCapabilities = capabilities; 195 196 for (Listener l : mListeners) { 197 l.onCapabilitiesChanged(this, mCapabilities); 198 } 199 } 200 } 201 202 /** 203 * Adds the specified connection as a child of this conference. 204 * 205 * @param connection The connection to add. 206 * @return True if the connection was successfully added. 207 */ 208 public final boolean addConnection(Connection connection) { 209 if (connection != null && !mChildConnections.contains(connection)) { 210 if (connection.setConference(this)) { 211 mChildConnections.add(connection); 212 for (Listener l : mListeners) { 213 l.onConnectionAdded(this, connection); 214 } 215 return true; 216 } 217 } 218 return false; 219 } 220 221 /** 222 * Removes the specified connection as a child of this conference. 223 * 224 * @param connection The connection to remove. 225 */ 226 public final void removeConnection(Connection connection) { 227 Log.d(this, "removing %s from %s", connection, mChildConnections); 228 if (connection != null && mChildConnections.remove(connection)) { 229 connection.resetConference(); 230 for (Listener l : mListeners) { 231 l.onConnectionRemoved(this, connection); 232 } 233 } 234 } 235 236 /** 237 * Tears down the conference object and any of its current connections. 238 */ 239 public final void destroy() { 240 Log.d(this, "destroying conference : %s", this); 241 // Tear down the children. 242 for (Connection connection : mChildConnections) { 243 Log.d(this, "removing connection %s", connection); 244 removeConnection(connection); 245 } 246 247 // If not yet disconnected, set the conference call as disconnected first. 248 if (mState != Connection.STATE_DISCONNECTED) { 249 Log.d(this, "setting to disconnected"); 250 setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); 251 } 252 253 // ...and notify. 254 for (Listener l : mListeners) { 255 l.onDestroyed(this); 256 } 257 } 258 259 /** 260 * Add a listener to be notified of a state change. 261 * 262 * @param listener The new listener. 263 * @return This conference. 264 * @hide 265 */ 266 public final Conference addListener(Listener listener) { 267 mListeners.add(listener); 268 return this; 269 } 270 271 /** 272 * Removes the specified listener. 273 * 274 * @param listener The listener to remove. 275 * @return This conference. 276 * @hide 277 */ 278 public final Conference removeListener(Listener listener) { 279 mListeners.remove(listener); 280 return this; 281 } 282 283 /** 284 * Inform this Conference that the state of its audio output has been changed externally. 285 * 286 * @param state The new audio state. 287 * @hide 288 */ 289 final void setAudioState(AudioState state) { 290 Log.d(this, "setAudioState %s", state); 291 mAudioState = state; 292 onAudioStateChanged(state); 293 } 294 295 private void setState(int newState) { 296 if (newState != Connection.STATE_ACTIVE && 297 newState != Connection.STATE_HOLDING && 298 newState != Connection.STATE_DISCONNECTED) { 299 Log.w(this, "Unsupported state transition for Conference call.", 300 Connection.stateToString(newState)); 301 return; 302 } 303 304 if (mState != newState) { 305 int oldState = mState; 306 mState = newState; 307 for (Listener l : mListeners) { 308 l.onStateChanged(this, oldState, newState); 309 } 310 } 311 } 312} 313