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 17 package com.android.services.telephony; 18 19 import android.telecom.Conference; 20 import android.telecom.Connection; 21 import android.telecom.PhoneAccountHandle; 22 23 import com.android.internal.telephony.Call; 24 import com.android.internal.telephony.CallStateException; 25 import com.android.internal.telephony.Phone; 26 27 import java.util.List; 28 29 /** 30 * TelephonyConnection-based conference call for GSM conferences and IMS conferences (which may 31 * be either GSM-based or CDMA-based). 32 */ 33 public class TelephonyConference extends Conference { 34 35 public TelephonyConference(PhoneAccountHandle phoneAccount) { 36 super(phoneAccount); 37 setConnectionCapabilities( 38 Connection.CAPABILITY_SUPPORT_HOLD | 39 Connection.CAPABILITY_HOLD | 40 Connection.CAPABILITY_MUTE | 41 Connection.CAPABILITY_MANAGE_CONFERENCE); 42 setActive(); 43 } 44 45 /** 46 * Invoked when the Conference and all it's {@link Connection}s should be disconnected. 47 */ 48 @Override 49 public void onDisconnect() { 50 for (Connection connection : getConnections()) { 51 if (disconnectCall(connection)) { 52 break; 53 } 54 } 55 } 56 57 /** 58 * Disconnect the underlying Telephony Call for a connection. 59 * 60 * @param connection The connection. 61 * @return {@code True} if the call was disconnected. 62 */ 63 private boolean disconnectCall(Connection connection) { 64 Call call = getMultipartyCallForConnection(connection, "onDisconnect"); 65 if (call != null) { 66 Log.d(this, "Found multiparty call to hangup for conference."); 67 try { 68 call.hangup(); 69 return true; 70 } catch (CallStateException e) { 71 Log.e(this, e, "Exception thrown trying to hangup conference"); 72 } 73 } 74 return false; 75 } 76 77 /** 78 * Invoked when the specified {@link Connection} should be separated from the conference call. 79 * 80 * @param connection The connection to separate. 81 */ 82 @Override 83 public void onSeparate(Connection connection) { 84 com.android.internal.telephony.Connection radioConnection = 85 getOriginalConnection(connection); 86 try { 87 radioConnection.separate(); 88 } catch (CallStateException e) { 89 Log.e(this, e, "Exception thrown trying to separate a conference call"); 90 } 91 } 92 93 @Override 94 public void onMerge(Connection connection) { 95 try { 96 Phone phone = ((TelephonyConnection) connection).getPhone(); 97 if (phone != null) { 98 phone.conference(); 99 } 100 } catch (CallStateException e) { 101 Log.e(this, e, "Exception thrown trying to merge call into a conference"); 102 } 103 } 104 105 /** 106 * Invoked when the conference should be put on hold. 107 */ 108 @Override 109 public void onHold() { 110 final TelephonyConnection connection = getFirstConnection(); 111 if (connection != null) { 112 connection.performHold(); 113 } 114 } 115 116 /** 117 * Invoked when the conference should be moved from hold to active. 118 */ 119 @Override 120 public void onUnhold() { 121 final TelephonyConnection connection = getFirstConnection(); 122 if (connection != null) { 123 connection.performUnhold(); 124 } 125 } 126 127 @Override 128 public void onPlayDtmfTone(char c) { 129 final TelephonyConnection connection = getFirstConnection(); 130 if (connection != null) { 131 connection.onPlayDtmfTone(c); 132 } 133 } 134 135 @Override 136 public void onStopDtmfTone() { 137 final TelephonyConnection connection = getFirstConnection(); 138 if (connection != null) { 139 connection.onStopDtmfTone(); 140 } 141 } 142 143 @Override 144 public void onConnectionAdded(Connection connection) { 145 // If the conference was an IMS connection currently or before, disable MANAGE_CONFERENCE 146 // as the default behavior. If there is a conference event package, this may be overridden. 147 // If a conference event package was received, do not attempt to remove manage conference. 148 if (connection instanceof TelephonyConnection && 149 ((TelephonyConnection) connection).wasImsConnection()) { 150 removeCapability(Connection.CAPABILITY_MANAGE_CONFERENCE); 151 } 152 } 153 154 @Override 155 public Connection getPrimaryConnection() { 156 157 List<Connection> connections = getConnections(); 158 if (connections == null || connections.isEmpty()) { 159 return null; 160 } 161 162 // Default to the first connection. 163 Connection primaryConnection = connections.get(0); 164 165 // Otherwise look for a connection where the radio connection states it is multiparty. 166 for (Connection connection : connections) { 167 com.android.internal.telephony.Connection radioConnection = 168 getOriginalConnection(connection); 169 170 if (radioConnection != null && radioConnection.isMultiparty()) { 171 primaryConnection = connection; 172 break; 173 } 174 } 175 176 return primaryConnection; 177 } 178 179 private Call getMultipartyCallForConnection(Connection connection, String tag) { 180 com.android.internal.telephony.Connection radioConnection = 181 getOriginalConnection(connection); 182 if (radioConnection != null) { 183 Call call = radioConnection.getCall(); 184 if (call != null && call.isMultiparty()) { 185 return call; 186 } 187 } 188 return null; 189 } 190 191 protected com.android.internal.telephony.Connection getOriginalConnection( 192 Connection connection) { 193 194 if (connection instanceof TelephonyConnection) { 195 return ((TelephonyConnection) connection).getOriginalConnection(); 196 } else { 197 return null; 198 } 199 } 200 201 private TelephonyConnection getFirstConnection() { 202 final List<Connection> connections = getConnections(); 203 if (connections.isEmpty()) { 204 return null; 205 } 206 return (TelephonyConnection) connections.get(0); 207 } 208 } 209