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