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