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 com.android.services.telephony; 18 19import android.content.Context; 20import android.os.PersistableBundle; 21import android.telecom.Conference; 22import android.telecom.Connection; 23import android.telecom.PhoneAccountHandle; 24import android.telephony.CarrierConfigManager; 25 26import com.android.internal.telephony.Call; 27import com.android.internal.telephony.CallStateException; 28import com.android.phone.PhoneGlobals; 29import com.android.phone.common.R; 30 31import java.util.List; 32 33/** 34 * CDMA-based conference call. 35 */ 36public class CdmaConference extends Conference { 37 private int mCapabilities; 38 private int mProperties; 39 40 public CdmaConference(PhoneAccountHandle phoneAccount) { 41 super(phoneAccount); 42 setActive(); 43 44 mProperties = Connection.PROPERTY_GENERIC_CONFERENCE; 45 setConnectionProperties(mProperties); 46 } 47 48 public void updateCapabilities(int capabilities) { 49 capabilities |= Connection.CAPABILITY_MUTE; 50 setConnectionCapabilities(capabilities); 51 } 52 53 /** 54 * Invoked when the Conference and all it's {@link Connection}s should be disconnected. 55 */ 56 @Override 57 public void onDisconnect() { 58 Call call = getOriginalCall(); 59 if (call != null) { 60 Log.d(this, "Found multiparty call to hangup for conference."); 61 try { 62 call.hangup(); 63 } catch (CallStateException e) { 64 Log.e(this, e, "Exception thrown trying to hangup conference"); 65 } 66 } 67 } 68 69 @Override 70 public void onSeparate(Connection connection) { 71 Log.e(this, new Exception(), "Separate not supported for CDMA conference call."); 72 } 73 74 @Override 75 public void onHold() { 76 Log.e(this, new Exception(), "Hold not supported for CDMA conference call."); 77 } 78 79 /** 80 * Invoked when the conference should be moved from hold to active. 81 */ 82 @Override 83 public void onUnhold() { 84 Log.e(this, new Exception(), "Unhold not supported for CDMA conference call."); 85 } 86 87 @Override 88 public void onMerge() { 89 Log.i(this, "Merging CDMA conference call."); 90 // Can only merge once 91 mCapabilities &= ~Connection.CAPABILITY_MERGE_CONFERENCE; 92 // Once merged, swap is enabled. 93 if (isSwapSupportedAfterMerge()){ 94 mCapabilities |= Connection.CAPABILITY_SWAP_CONFERENCE; 95 } 96 updateCapabilities(mCapabilities); 97 sendFlash(); 98 } 99 100 @Override 101 public void onPlayDtmfTone(char c) { 102 final CdmaConnection connection = getFirstConnection(); 103 if (connection != null) { 104 connection.onPlayDtmfTone(c); 105 } else { 106 Log.w(this, "No CDMA connection found while trying to play dtmf tone."); 107 } 108 } 109 110 @Override 111 public void onStopDtmfTone() { 112 final CdmaConnection connection = getFirstConnection(); 113 if (connection != null) { 114 connection.onStopDtmfTone(); 115 } else { 116 Log.w(this, "No CDMA connection found while trying to stop dtmf tone."); 117 } 118 } 119 120 @Override 121 public void onSwap() { 122 Log.i(this, "Swapping CDMA conference call."); 123 sendFlash(); 124 } 125 126 private void sendFlash() { 127 Call call = getOriginalCall(); 128 if (call != null) { 129 try { 130 // For CDMA calls, this just sends a flash command. 131 call.getPhone().switchHoldingAndActive(); 132 } catch (CallStateException e) { 133 Log.e(this, e, "Error while trying to send flash command."); 134 } 135 } 136 } 137 138 private Call getMultipartyCallForConnection(Connection connection) { 139 com.android.internal.telephony.Connection radioConnection = 140 getOriginalConnection(connection); 141 if (radioConnection != null) { 142 Call call = radioConnection.getCall(); 143 if (call != null && call.isMultiparty()) { 144 return call; 145 } 146 } 147 return null; 148 } 149 150 private Call getOriginalCall() { 151 List<Connection> connections = getConnections(); 152 if (!connections.isEmpty()) { 153 com.android.internal.telephony.Connection originalConnection = 154 getOriginalConnection(connections.get(0)); 155 if (originalConnection != null) { 156 return originalConnection.getCall(); 157 } 158 } 159 return null; 160 } 161 162 /** 163 * Return whether network support swap after merge conference call. 164 * 165 * @return true to support, false not support. 166 */ 167 private final boolean isSwapSupportedAfterMerge() 168 { 169 boolean supportSwapAfterMerge = true; 170 Context context = PhoneGlobals.getInstance(); 171 172 if (context != null) { 173 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService( 174 Context.CARRIER_CONFIG_SERVICE); 175 PersistableBundle b = configManager.getConfig(); 176 if (b != null) { 177 supportSwapAfterMerge = 178 b.getBoolean(CarrierConfigManager.KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL); 179 Log.d(this, "Current network support swap after call merged capability is " 180 + supportSwapAfterMerge); 181 } 182 } 183 return supportSwapAfterMerge; 184 } 185 186 private com.android.internal.telephony.Connection getOriginalConnection(Connection connection) { 187 if (connection instanceof CdmaConnection) { 188 return ((CdmaConnection) connection).getOriginalConnection(); 189 } else { 190 Log.e(this, null, "Non CDMA connection found in a CDMA conference"); 191 return null; 192 } 193 } 194 195 private CdmaConnection getFirstConnection() { 196 final List<Connection> connections = getConnections(); 197 if (connections.isEmpty()) { 198 return null; 199 } 200 return (CdmaConnection) connections.get(0); 201 } 202} 203