1 /* 2 * Copyright (C) 2022 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.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.text.TextUtils; 25 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 import java.util.Objects; 29 30 /** 31 * Contains the information for SIP. 32 */ 33 public final class SipDetails implements Parcelable { 34 /** 35 * Define a SIP method type related to this information. 36 * @hide 37 */ 38 @Retention(RetentionPolicy.SOURCE) 39 @IntDef(prefix = "METHOD_", value = { 40 METHOD_UNKNOWN, 41 METHOD_REGISTER, 42 METHOD_PUBLISH, 43 METHOD_SUBSCRIBE 44 }) 45 public @interface Method {} 46 47 public static final int METHOD_UNKNOWN = 0; 48 49 /** 50 * Indicates information related to the SIP registration method. 51 * See RFC 3261 for details. 52 */ 53 public static final int METHOD_REGISTER = 1; 54 /** 55 * Indicates information related to the SIP publication method. 56 * See RFC 3903 for details. 57 */ 58 public static final int METHOD_PUBLISH = 2; 59 /** 60 * Indicates information related to the SIP subscription method. 61 * See RFC 3856 for details. 62 */ 63 public static final int METHOD_SUBSCRIBE = 3; 64 65 /** 66 * Builder for creating {@link SipDetails} instances. 67 * @hide 68 */ 69 public static final class Builder { 70 private int mMethod; 71 // Command Sequence value defined in RFC3261 Section 8.1.1.5 72 private int mCseq = 0; 73 private int mResponseCode = 0; 74 private String mResponsePhrase = ""; 75 private int mReasonHeaderCause = 0; 76 private String mReasonHeaderText = ""; 77 private @Nullable String mCallId; 78 79 /** 80 * Build a new instance of {@link SipDetails}. 81 * 82 * @param method Indicates which SIP method this information is for. 83 */ Builder(@ethod int method)84 public Builder(@Method int method) { 85 this.mMethod = method; 86 } 87 88 /** 89 * Sets the value of the CSeq header field for this SIP method. 90 * The CSeq header field serves as a way to identify and order transactions. 91 * It consists of a sequence number and a method. 92 * The method MUST match that of the request. 93 * Ref RFC3261 Section 8.1.1.5. 94 * @param cSeq The value of the CSeq header field. 95 * @return The same instance of the builder. 96 */ setCSeq(int cSeq)97 public @NonNull Builder setCSeq(int cSeq) { 98 this.mCseq = cSeq; 99 return this; 100 } 101 102 /** 103 * Sets the SIP response code and reason response for this SIP method. 104 * Ref RFC3261 Section 21. 105 * @param responseCode The SIP response code sent from the network for the 106 * operation token specified. 107 * @param responsePhrase The optional reason response from the network. If 108 * there is a reason header included in the response, that should take 109 * precedence over the reason provided in the status line. If the network 110 * provided no reason with the SIP code, the string should be empty. 111 * @return The same instance of the builder. 112 */ setSipResponseCode(int responseCode, @NonNull String responsePhrase)113 public Builder setSipResponseCode(int responseCode, 114 @NonNull String responsePhrase) { 115 this.mResponseCode = responseCode; 116 this.mResponsePhrase = responsePhrase; 117 return this; 118 } 119 120 121 /** 122 * Sets the detailed information of reason header for this SIP method. 123 * Ref RFC3326. 124 * @param reasonHeaderCause The “cause” parameter of the “reason” 125 * header included in the SIP message. 126 * @param reasonHeaderText The “text” parameter of the “reason” 127 * header included in the SIP message. 128 * @return The same instance of the builder. 129 */ setSipResponseReasonHeader(int reasonHeaderCause, @NonNull String reasonHeaderText)130 public Builder setSipResponseReasonHeader(int reasonHeaderCause, 131 @NonNull String reasonHeaderText) { 132 this.mReasonHeaderCause = reasonHeaderCause; 133 this.mReasonHeaderText = reasonHeaderText; 134 return this; 135 } 136 137 138 /** 139 * Sets the value of the Call-ID header field for this SIP method. 140 * Ref RFC3261 Section 8.1.1.4. 141 * @param callId The value of the Call-ID header field. 142 * @return The same instance of the builder. 143 */ setCallId(@onNull String callId)144 public @NonNull Builder setCallId(@NonNull String callId) { 145 this.mCallId = callId; 146 return this; 147 } 148 149 /** 150 * @return a new SipDetails from this Builder. 151 */ build()152 public @NonNull SipDetails build() { 153 return new SipDetails(this); 154 } 155 } 156 157 private final int mMethod; 158 private final int mCseq; 159 private final int mResponseCode; 160 private final @NonNull String mResponsePhrase; 161 private final int mReasonHeaderCause; 162 private final @NonNull String mReasonHeaderText; 163 private final @Nullable String mCallId; 164 SipDetails(Builder builder)165 private SipDetails(Builder builder) { 166 mMethod = builder.mMethod; 167 mCseq = builder.mCseq; 168 mResponseCode = builder.mResponseCode; 169 mResponsePhrase = builder.mResponsePhrase; 170 mReasonHeaderCause = builder.mReasonHeaderCause; 171 mReasonHeaderText = builder.mReasonHeaderText; 172 mCallId = builder.mCallId; 173 } 174 175 /** 176 * Get the method type of this instance. 177 * @return The method type associated with this SIP information. 178 */ getMethod()179 public @Method int getMethod() { 180 return mMethod; 181 } 182 183 /** 184 * Get the value of CSeq header field. 185 * The CSeq header field serves as a way to identify and order transactions. 186 * @return The command sequence value associated with this SIP information. 187 */ getCSeq()188 public int getCSeq() { 189 return mCseq; 190 } 191 192 /** 193 * Get the value of response code from the SIP response. 194 * The SIP response code sent from the network for the operation token specified. 195 * @return The SIP response code associated with this SIP information. 196 */ getResponseCode()197 public int getResponseCode() { 198 return mResponseCode; 199 } 200 201 /** 202 * Get the value of reason from the SIP response. 203 * The optional reason response from the network. If 204 * there is a reason header included in the response, that should take 205 * precedence over the reason provided in the status line. 206 * @return The optional reason response associated with this SIP information. If the network 207 * provided no reason with the SIP code, the string should be empty. 208 */ getResponsePhrase()209 public @NonNull String getResponsePhrase() { 210 return mResponsePhrase; 211 } 212 213 /** 214 * Get the "cause" parameter of the "reason" header. 215 * @return The "cause" parameter of the reason header. If the SIP message from the network 216 * does not have a reason header, it should be 0. 217 */ getReasonHeaderCause()218 public int getReasonHeaderCause() { 219 return mReasonHeaderCause; 220 } 221 222 /** 223 * Get the "text" parameter of the "reason" header in the SIP message. 224 * @return The "text" parameter of the reason header. If the SIP message from the network 225 * does not have a reason header, it can be empty. 226 */ getReasonHeaderText()227 public @NonNull String getReasonHeaderText() { 228 return mReasonHeaderText; 229 } 230 231 /** 232 * Get the value of the Call-ID header field for this SIP method. 233 * @return The Call-ID value associated with this SIP information. If the Call-ID value is 234 * not set when ImsService notifies the framework, this value will be null. 235 */ getCallId()236 public @Nullable String getCallId() { 237 return mCallId; 238 } 239 240 @Override describeContents()241 public int describeContents() { 242 return 0; 243 } 244 245 @Override writeToParcel(@onNull Parcel dest, int flags)246 public void writeToParcel(@NonNull Parcel dest, int flags) { 247 dest.writeInt(mMethod); 248 dest.writeInt(mCseq); 249 dest.writeInt(mResponseCode); 250 dest.writeString(mResponsePhrase); 251 dest.writeInt(mReasonHeaderCause); 252 dest.writeString(mReasonHeaderText); 253 dest.writeString(mCallId); 254 } 255 256 public static final @NonNull Creator<SipDetails> CREATOR = 257 new Creator<SipDetails>() { 258 @Override 259 public SipDetails createFromParcel(Parcel source) { 260 return new SipDetails(source); 261 } 262 263 @Override 264 public SipDetails[] newArray(int size) { 265 return new SipDetails[size]; 266 } 267 }; 268 269 /** 270 * Construct a SipDetails object from the given parcel. 271 */ SipDetails(Parcel in)272 private SipDetails(Parcel in) { 273 mMethod = in.readInt(); 274 mCseq = in.readInt(); 275 mResponseCode = in.readInt(); 276 mResponsePhrase = in.readString(); 277 mReasonHeaderCause = in.readInt(); 278 mReasonHeaderText = in.readString(); 279 mCallId = in.readString(); 280 } 281 282 @Override equals(Object o)283 public boolean equals(Object o) { 284 if (this == o) return true; 285 if (o == null || getClass() != o.getClass()) return false; 286 SipDetails that = (SipDetails) o; 287 return mMethod == that.mMethod 288 && mCseq == that.mCseq 289 && mResponseCode == that.mResponseCode 290 && TextUtils.equals(mResponsePhrase, that.mResponsePhrase) 291 && mReasonHeaderCause == that.mReasonHeaderCause 292 && TextUtils.equals(mReasonHeaderText, that.mReasonHeaderText) 293 && TextUtils.equals(mCallId, that.mCallId); 294 } 295 296 @Override hashCode()297 public int hashCode() { 298 return Objects.hash(mMethod, mCseq, mResponseCode, mResponsePhrase, mReasonHeaderCause, 299 mReasonHeaderText, mCallId); 300 } 301 302 @Override toString()303 public String toString() { 304 return "SipDetails { methodType= " + mMethod + ", cSeq=" + mCseq 305 + ", ResponseCode=" + mResponseCode + ", ResponseCPhrase=" + mResponsePhrase 306 + ", ReasonHeaderCause=" + mReasonHeaderCause 307 + ", ReasonHeaderText=" + mReasonHeaderText + ", callId=" + mCallId + "}"; 308 } 309 } 310