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.net.Uri; 20 import android.telecom.Connection; 21 import android.telecom.DisconnectCause; 22 import android.telephony.SubscriptionInfo; 23 import android.text.TextUtils; 24 25 import com.android.ims.internal.ConferenceParticipant; 26 import com.android.internal.telephony.Phone; 27 import com.android.internal.telephony.PhoneConstants; 28 import com.android.telephony.Rlog; 29 30 /** 31 * Represents a participant in a conference call. 32 */ 33 public class ConferenceParticipantConnection extends Connection { 34 35 private static final String LOG_TAG = "ConferenceParticipantConnection"; 36 37 /** 38 * The user entity URI For the conference participant. 39 */ 40 private final Uri mUserEntity; 41 42 /** 43 * The endpoint URI For the conference participant. 44 */ 45 private final Uri mEndpoint; 46 47 /** 48 * The connection which owns this participant. 49 */ 50 private final com.android.internal.telephony.Connection mParentConnection; 51 52 /** 53 * Creates a new instance. 54 * 55 * @param participant The conference participant to create the instance for. 56 * @param isRemotelyHosted {@code true} if this participant is part of a conference remotely 57 * hosted on another device, {@code false} otherwise. 58 */ ConferenceParticipantConnection( com.android.internal.telephony.Connection parentConnection, ConferenceParticipant participant, boolean isRemotelyHosted)59 public ConferenceParticipantConnection( 60 com.android.internal.telephony.Connection parentConnection, 61 ConferenceParticipant participant, 62 boolean isRemotelyHosted) { 63 64 mParentConnection = parentConnection; 65 66 int presentation = participant.getParticipantPresentation(); 67 Uri address; 68 if (presentation != PhoneConstants.PRESENTATION_ALLOWED) { 69 address = null; 70 } else { 71 String countryIso = getCountryIso(parentConnection.getCall().getPhone()); 72 address = ConferenceParticipant.getParticipantAddress(participant.getHandle(), 73 countryIso); 74 } 75 setAddress(address, presentation); 76 setVideoState(parentConnection.getVideoState()); 77 setCallerDisplayName(participant.getDisplayName(), presentation); 78 79 mUserEntity = participant.getHandle(); 80 mEndpoint = participant.getEndpoint(); 81 82 setCapabilitiesAndProperties(isRemotelyHosted); 83 } 84 85 /** 86 * Changes the state of the conference participant. 87 * 88 * @param newState The new state. 89 */ updateState(int newState)90 public void updateState(int newState) { 91 Log.v(this, "updateState endPoint: %s state: %s", Rlog.pii(LOG_TAG, mEndpoint), 92 Connection.stateToString(newState)); 93 if (newState == getState()) { 94 return; 95 } 96 97 switch (newState) { 98 case STATE_INITIALIZING: 99 setInitializing(); 100 break; 101 case STATE_RINGING: 102 setRinging(); 103 break; 104 case STATE_DIALING: 105 setDialing(); 106 break; 107 case STATE_HOLDING: 108 setOnHold(); 109 break; 110 case STATE_ACTIVE: 111 setActive(); 112 break; 113 case STATE_DISCONNECTED: 114 setDisconnected(new DisconnectCause(DisconnectCause.CANCELED)); 115 destroy(); 116 break; 117 default: 118 setActive(); 119 } 120 } 121 122 /** 123 * Disconnects the current {@code ConferenceParticipantConnection} from the conference. 124 * <p> 125 * Sends a participant disconnect signal to the associated parent connection. The participant 126 * connection is not disconnected and cleaned up here. On successful disconnection of the 127 * participant, the conference server will send an update to the conference controller 128 * indicating the disconnection was successful. 129 */ 130 @Override onDisconnect()131 public void onDisconnect() { 132 mParentConnection.onDisconnectConferenceParticipant(mUserEntity); 133 } 134 135 /** 136 * Retrieves the user handle for this connection. 137 * 138 * @return The userEntity. 139 */ getUserEntity()140 public Uri getUserEntity() { 141 return mUserEntity; 142 } 143 144 /** 145 * Retrieves the endpoint for this connection. 146 * 147 * @return The endpoint. 148 */ getEndpoint()149 public Uri getEndpoint() { 150 return mEndpoint; 151 } 152 153 /** 154 * Configures the capabilities and properties applicable to this connection. A 155 * conference participant can only be disconnected from a conference since there is not 156 * actual connection to the participant which could be split from the conference. 157 * @param isRemotelyHosted {@code true} if this participant is part of a conference hosted 158 * hosted on a remote device, {@code false} otherwise. 159 */ setCapabilitiesAndProperties(boolean isRemotelyHosted)160 private void setCapabilitiesAndProperties(boolean isRemotelyHosted) { 161 int capabilities = CAPABILITY_DISCONNECT_FROM_CONFERENCE; 162 setConnectionCapabilities(capabilities); 163 164 if (isRemotelyHosted) { 165 setConnectionProperties(PROPERTY_REMOTELY_HOSTED); 166 } 167 } 168 169 /** 170 * Given a {@link Phone} instance, determines the country ISO associated with the phone's 171 * subscription. 172 * 173 * @param phone The phone instance. 174 * @return The country ISO. 175 */ getCountryIso(Phone phone)176 private String getCountryIso(Phone phone) { 177 if (phone == null) { 178 return null; 179 } 180 181 int subId = phone.getSubId(); 182 183 SubscriptionInfo subInfo = TelecomAccountRegistry.getInstance(null). 184 getSubscriptionManager().getActiveSubscriptionInfo(subId); 185 186 if (subInfo == null || TextUtils.isEmpty(subInfo.getCountryIso())) { 187 return null; 188 } 189 // The SubscriptionInfo reports ISO country codes in lower case. Convert to upper case, 190 // since ultimately we use this ISO when formatting the CEP phone number, and the phone 191 // number formatting library expects uppercase ISO country codes. 192 return subInfo.getCountryIso().toUpperCase(); 193 } 194 195 /** 196 * Builds a string representation of this conference participant connection. 197 * 198 * @return String representation of connection. 199 */ 200 @Override toString()201 public String toString() { 202 StringBuilder sb = new StringBuilder(); 203 sb.append("[ConferenceParticipantConnection objId:"); 204 sb.append(System.identityHashCode(this)); 205 sb.append(" endPoint:"); 206 sb.append(Rlog.pii(LOG_TAG, mEndpoint)); 207 sb.append(" address:"); 208 sb.append(Rlog.pii(LOG_TAG, getAddress())); 209 sb.append(" addressPresentation:"); 210 sb.append(getAddressPresentation()); 211 sb.append(" parentConnection:"); 212 sb.append(Rlog.pii(LOG_TAG, mParentConnection.getAddress())); 213 sb.append(" state:"); 214 sb.append(Connection.stateToString(getState())); 215 sb.append(" connectTime:"); 216 sb.append(getConnectTimeMillis()); 217 sb.append(" connectElapsedTime:"); 218 sb.append(getConnectionStartElapsedRealtimeMillis()); 219 sb.append("]"); 220 221 return sb.toString(); 222 } 223 } 224