Conference.java revision 7f3d41fd124dd7c4a8b72c1d48df08a8ee7209ec
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 int mState = Connection.STATE_NEW; 47 private DisconnectCause mDisconnectCause; 48 private int mCapabilities; 49 private String mDisconnectMessage; 50 51 /** 52 * Constructs a new Conference with a mandatory {@link PhoneAccountHandle} 53 * 54 * @param phoneAccount The {@code PhoneAccountHandle} associated with the conference. 55 */ 56 public Conference(PhoneAccountHandle phoneAccount) { 57 mPhoneAccount = phoneAccount; 58 } 59 60 /** 61 * Returns the {@link PhoneAccountHandle} the conference call is being placed through. 62 * 63 * @return A {@code PhoneAccountHandle} object representing the PhoneAccount of the conference. 64 */ 65 public final PhoneAccountHandle getPhoneAccountHandle() { 66 return mPhoneAccount; 67 } 68 69 /** 70 * Returns the list of connections currently associated with the conference call. 71 * 72 * @return A list of {@code Connection} objects which represent the children of the conference. 73 */ 74 public final List<Connection> getConnections() { 75 return mUnmodifiableChildConnections; 76 } 77 78 /** 79 * Gets the state of the conference call. See {@link Connection} for valid values. 80 * 81 * @return A constant representing the state the conference call is currently in. 82 */ 83 public final int getState() { 84 return mState; 85 } 86 87 /** 88 * Returns the capabilities of a conference. See {@link PhoneCapabilities} for valid values. 89 * 90 * @return A bitmask of the {@code PhoneCapabilities} of the conference call. 91 */ 92 public final int getCapabilities() { 93 return mCapabilities; 94 } 95 96 /** 97 * Invoked when the Conference and all it's {@link Connection}s should be disconnected. 98 */ 99 public void onDisconnect() {} 100 101 /** 102 * Invoked when the specified {@link Connection} should be separated from the conference call. 103 * 104 * @param connection The connection to separate. 105 */ 106 public void onSeparate(Connection connection) {} 107 108 /** 109 * Invoked when the conference should be put on hold. 110 */ 111 public void onHold() {} 112 113 /** 114 * Invoked when the conference should be moved from hold to active. 115 */ 116 public void onUnhold() {} 117 118 /** 119 * Invoked when the child calls should be merged. Only invoked if the conference contains the 120 * capability {@link PhoneCapabilities#MERGE_CONFERENCE}. 121 */ 122 public void onMerge() {} 123 124 /** 125 * Invoked when the child calls should be swapped. Only invoked if the conference contains the 126 * capability {@link PhoneCapabilities#SWAP_CONFERENCE}. 127 */ 128 public void onSwap() {} 129 130 /** 131 * Sets state to be on hold. 132 */ 133 public final void setOnHold() { 134 setState(Connection.STATE_HOLDING); 135 } 136 137 /** 138 * Sets state to be active. 139 */ 140 public final void setActive() { 141 setState(Connection.STATE_ACTIVE); 142 } 143 144 /** 145 * Sets state to disconnected. 146 * 147 * @param disconnectCause The reason for the disconnection, as described by 148 * {@link android.telecom.DisconnectCause}. 149 */ 150 public final void setDisconnected(DisconnectCause disconnectCause) { 151 mDisconnectCause = disconnectCause;; 152 setState(Connection.STATE_DISCONNECTED); 153 for (Listener l : mListeners) { 154 l.onDisconnected(this, mDisconnectCause); 155 } 156 } 157 158 /** 159 * Sets the capabilities of a conference. See {@link PhoneCapabilities} for valid values. 160 * 161 * @param capabilities A bitmask of the {@code PhoneCapabilities} of the conference call. 162 */ 163 public final void setCapabilities(int capabilities) { 164 if (capabilities != mCapabilities) { 165 mCapabilities = capabilities; 166 167 for (Listener l : mListeners) { 168 l.onCapabilitiesChanged(this, mCapabilities); 169 } 170 } 171 } 172 173 /** 174 * Adds the specified connection as a child of this conference. 175 * 176 * @param connection The connection to add. 177 * @return True if the connection was successfully added. 178 */ 179 public final boolean addConnection(Connection connection) { 180 if (connection != null && !mChildConnections.contains(connection)) { 181 if (connection.setConference(this)) { 182 mChildConnections.add(connection); 183 for (Listener l : mListeners) { 184 l.onConnectionAdded(this, connection); 185 } 186 return true; 187 } 188 } 189 return false; 190 } 191 192 /** 193 * Removes the specified connection as a child of this conference. 194 * 195 * @param connection The connection to remove. 196 */ 197 public final void removeConnection(Connection connection) { 198 Log.d(this, "removing %s from %s", connection, mChildConnections); 199 if (connection != null && mChildConnections.remove(connection)) { 200 connection.resetConference(); 201 for (Listener l : mListeners) { 202 l.onConnectionRemoved(this, connection); 203 } 204 } 205 } 206 207 /** 208 * Tears down the conference object and any of its current connections. 209 */ 210 public final void destroy() { 211 Log.d(this, "destroying conference : %s", this); 212 // Tear down the children. 213 for (Connection connection : mChildConnections) { 214 Log.d(this, "removing connection %s", connection); 215 removeConnection(connection); 216 } 217 218 // If not yet disconnected, set the conference call as disconnected first. 219 if (mState != Connection.STATE_DISCONNECTED) { 220 Log.d(this, "setting to disconnected"); 221 setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); 222 } 223 224 // ...and notify. 225 for (Listener l : mListeners) { 226 l.onDestroyed(this); 227 } 228 } 229 230 /** 231 * Add a listener to be notified of a state change. 232 * 233 * @param listener The new listener. 234 * @return This conference. 235 * @hide 236 */ 237 public final Conference addListener(Listener listener) { 238 mListeners.add(listener); 239 return this; 240 } 241 242 /** 243 * Removes the specified listener. 244 * 245 * @param listener The listener to remove. 246 * @return This conference. 247 * @hide 248 */ 249 public final Conference removeListener(Listener listener) { 250 mListeners.remove(listener); 251 return this; 252 } 253 254 private void setState(int newState) { 255 if (newState != Connection.STATE_ACTIVE && 256 newState != Connection.STATE_HOLDING && 257 newState != Connection.STATE_DISCONNECTED) { 258 Log.w(this, "Unsupported state transition for Conference call.", 259 Connection.stateToString(newState)); 260 return; 261 } 262 263 if (mState != newState) { 264 int oldState = mState; 265 mState = newState; 266 for (Listener l : mListeners) { 267 l.onStateChanged(this, oldState, newState); 268 } 269 } 270 } 271} 272