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