1 /* 2 * Copyright (C) 2018 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 android.telephony.ims; 18 19 import android.annotation.NonNull; 20 import android.annotation.SystemApi; 21 import android.annotation.TestApi; 22 import android.os.Bundle; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.telecom.Call; 26 import android.telecom.Connection; 27 28 import com.android.telephony.Rlog; 29 30 import java.util.HashMap; 31 import java.util.Iterator; 32 import java.util.Map.Entry; 33 import java.util.Set; 34 35 /** 36 * Provides the conference information (defined in RFC 4575) for IMS conference call. 37 * 38 * @hide 39 */ 40 @SystemApi 41 @TestApi 42 public final class ImsConferenceState implements Parcelable { 43 private static final String TAG = "ImsConferenceState"; 44 /** 45 * conference-info : user 46 */ 47 // user (String) : Tel or SIP URI 48 public static final String USER = "user"; 49 // user > display text (String) 50 public static final String DISPLAY_TEXT = "display-text"; 51 // user > endpoint (String) : URI or GRUU or Phone number 52 public static final String ENDPOINT = "endpoint"; 53 // user > endpoint > status 54 public static final String STATUS = "status"; 55 56 /** 57 * status-type (String) : 58 * "pending" : Endpoint is not yet in the session, but it is anticipated that he/she will 59 * join in the near future. 60 * "dialing-out" : Focus has dialed out to connect the endpoint to the conference, 61 * but the endpoint is not yet in the roster (probably being authenticated). 62 * "dialing-in" : Endpoint is dialing into the conference, not yet in the roster 63 * (probably being authenticated). 64 * "alerting" : PSTN alerting or SIP 180 Ringing was returned for the outbound call; 65 * endpoint is being alerted. 66 * "on-hold" : Active signaling dialog exists between an endpoint and a focus, 67 * but endpoint is "on-hold" for this conference, i.e., he/she is neither "hearing" 68 * the conference mix nor is his/her media being mixed in the conference. 69 * "connected" : Endpoint is a participant in the conference. Depending on the media policies, 70 * he/she can send and receive media to and from other participants. 71 * "disconnecting" : Focus is in the process of disconnecting the endpoint 72 * (e.g. in SIP a DISCONNECT or BYE was sent to the endpoint). 73 * "disconnected" : Endpoint is not a participant in the conference, and no active dialog 74 * exists between the endpoint and the focus. 75 * "muted-via-focus" : Active signaling dialog exists beween an endpoint and a focus and 76 * the endpoint can "listen" to the conference, but the endpoint's media is not being 77 * mixed into the conference. 78 * "connect-fail" : Endpoint fails to join the conference by rejecting the conference call. 79 */ 80 public static final String STATUS_PENDING = "pending"; 81 public static final String STATUS_DIALING_OUT = "dialing-out"; 82 public static final String STATUS_DIALING_IN = "dialing-in"; 83 public static final String STATUS_ALERTING = "alerting"; 84 public static final String STATUS_ON_HOLD = "on-hold"; 85 public static final String STATUS_CONNECTED = "connected"; 86 public static final String STATUS_DISCONNECTING = "disconnecting"; 87 public static final String STATUS_DISCONNECTED = "disconnected"; 88 public static final String STATUS_MUTED_VIA_FOCUS = "muted-via-focus"; 89 public static final String STATUS_CONNECT_FAIL = "connect-fail"; 90 public static final String STATUS_SEND_ONLY = "sendonly"; 91 public static final String STATUS_SEND_RECV = "sendrecv"; 92 93 /** 94 * conference-info : SIP status code (integer) 95 */ 96 public static final String SIP_STATUS_CODE = "sipstatuscode"; 97 98 public final HashMap<String, Bundle> mParticipants = new HashMap<String, Bundle>(); 99 100 /** @hide */ ImsConferenceState()101 public ImsConferenceState() { 102 } 103 ImsConferenceState(Parcel in)104 private ImsConferenceState(Parcel in) { 105 readFromParcel(in); 106 } 107 108 @Override describeContents()109 public int describeContents() { 110 return 0; 111 } 112 113 @Override writeToParcel(Parcel out, int flags)114 public void writeToParcel(Parcel out, int flags) { 115 out.writeInt(mParticipants.size()); 116 117 if (mParticipants.size() > 0) { 118 Set<Entry<String, Bundle>> entries = mParticipants.entrySet(); 119 120 if (entries != null) { 121 Iterator<Entry<String, Bundle>> iterator = entries.iterator(); 122 123 while (iterator.hasNext()) { 124 Entry<String, Bundle> entry = iterator.next(); 125 126 out.writeString(entry.getKey()); 127 out.writeParcelable(entry.getValue(), 0); 128 } 129 } 130 } 131 } 132 readFromParcel(Parcel in)133 private void readFromParcel(Parcel in) { 134 int size = in.readInt(); 135 136 for (int i = 0; i < size; ++i) { 137 String user = in.readString(); 138 Bundle state = in.readParcelable(null); 139 mParticipants.put(user, state); 140 } 141 } 142 143 public static final @android.annotation.NonNull Creator<ImsConferenceState> CREATOR = 144 new Creator<ImsConferenceState>() { 145 @Override 146 public ImsConferenceState createFromParcel(Parcel in) { 147 return new ImsConferenceState(in); 148 } 149 150 @Override 151 public ImsConferenceState[] newArray(int size) { 152 return new ImsConferenceState[size]; 153 } 154 }; 155 156 /** 157 * Translates an {@code ImsConferenceState} status type to a telecom connection state. 158 * 159 * @param status The status type. 160 * @return The corresponding {@link android.telecom.Connection} state. 161 */ getConnectionStateForStatus(String status)162 public static int getConnectionStateForStatus(String status) { 163 if (status.equals(STATUS_PENDING)) { 164 return Connection.STATE_INITIALIZING; 165 } else if (status.equals(STATUS_DIALING_IN)) { 166 return Connection.STATE_RINGING; 167 } else if (status.equals(STATUS_ALERTING) || 168 status.equals(STATUS_DIALING_OUT)) { 169 return Connection.STATE_DIALING; 170 } else if (status.equals(STATUS_ON_HOLD) || 171 status.equals(STATUS_SEND_ONLY)) { 172 return Connection.STATE_HOLDING; 173 } else if (status.equals(STATUS_CONNECTED) || 174 status.equals(STATUS_MUTED_VIA_FOCUS) || 175 status.equals(STATUS_DISCONNECTING) || 176 status.equals(STATUS_SEND_RECV)) { 177 return Connection.STATE_ACTIVE; 178 } else if (status.equals(STATUS_DISCONNECTED)) { 179 return Connection.STATE_DISCONNECTED; 180 } 181 return Call.STATE_ACTIVE; 182 } 183 184 @NonNull 185 @Override toString()186 public String toString() { 187 StringBuilder sb = new StringBuilder(); 188 sb.append("["); 189 sb.append(ImsConferenceState.class.getSimpleName()); 190 sb.append(" "); 191 if (mParticipants.size() > 0) { 192 Set<Entry<String, Bundle>> entries = mParticipants.entrySet(); 193 194 if (entries != null) { 195 Iterator<Entry<String, Bundle>> iterator = entries.iterator(); 196 sb.append("<"); 197 while (iterator.hasNext()) { 198 Entry<String, Bundle> entry = iterator.next(); 199 sb.append(Rlog.pii(TAG, entry.getKey())); 200 sb.append(": "); 201 Bundle participantData = entry.getValue(); 202 203 for (String key : participantData.keySet()) { 204 sb.append(key); 205 sb.append("="); 206 if (ENDPOINT.equals(key) || USER.equals(key)) { 207 sb.append(Rlog.pii(TAG, participantData.get(key))); 208 } else { 209 sb.append(participantData.get(key)); 210 } 211 sb.append(", "); 212 } 213 } 214 sb.append(">"); 215 } 216 } 217 sb.append("]"); 218 return sb.toString(); 219 } 220 } 221