/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.telephony.ims; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.net.InetAddresses; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.telephony.ims.stub.SipDelegate; import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Objects; /** * The IMS registration and other attributes that the {@link SipDelegateConnection} used by the * IMS application will need to be aware of to correctly generate outgoing {@link SipMessage}s. *

* The IMS service must generate new instances of this configuration as the IMS configuration * managed by the IMS service changes. Along with each {@link SipDelegateConfiguration} instance * containing the configuration is the "version", which should be incremented every time a new * {@link SipDelegateConfiguration} instance is created. The {@link SipDelegateConnection} will * include the version of the {@link SipDelegateConfiguration} instance that it used in order for * the {@link SipDelegate} to easily identify if the IMS application used a now stale configuration * to generate the {@link SipMessage} and return * {@link SipDelegateManager#MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION} in * {@link DelegateMessageCallback#onMessageSendFailure(String, int)} so that the IMS application can * regenerate that {@link SipMessage} using the correct {@link SipDelegateConfiguration} * instance. *

* Every time the IMS configuration state changes in the IMS service, a full configuration should * be generated. The new {@link SipDelegateConfiguration} instance should not be an incremental * update. * @see Builder * @hide */ @SystemApi public final class SipDelegateConfiguration implements Parcelable { /** * The SIP transport uses UDP. */ public static final int SIP_TRANSPORT_UDP = 0; /** * The SIP transport uses TCP. */ public static final int SIP_TRANSPORT_TCP = 1; /**@hide*/ @IntDef(prefix = "SIP_TRANSPORT_", value = { SIP_TRANSPORT_UDP, SIP_TRANSPORT_TCP }) @Retention(RetentionPolicy.SOURCE) public @interface TransportType {} /** * The value returned by {@link #getMaxUdpPayloadSizeBytes()} when it is not defined. */ public static final int UDP_PAYLOAD_SIZE_UNDEFINED = -1; /** * SIP over IPSec configuration */ public static final class IpSecConfiguration { private final int mLocalTxPort; private final int mLocalRxPort; private final int mLastLocalTxPort; private final int mRemoteTxPort; private final int mRemoteRxPort; private final int mLastRemoteTxPort; private final String mSecurityHeader; /** * Describes the SIP over IPSec configuration the SipDelegate will need to use. * * @param localTxPort Local SIP port number used to send traffic. * @param localRxPort Local SIP port number used to receive traffic. * @param lastLocalTxPort Local SIP port number used for the previous IPsec security * association. * @param remoteTxPort Remote port number used by the SIP server to send SIP traffic. * @param remoteRxPort Remote port number used by the SIP server to receive incoming SIP * traffic. * @param lastRemoteTxPort Remote port number used by the SIP server to send SIP traffic on * the previous IPSec security association. * @param securityHeader The value of the SIP security verify header. */ public IpSecConfiguration(int localTxPort, int localRxPort, int lastLocalTxPort, int remoteTxPort, int remoteRxPort, int lastRemoteTxPort, @NonNull String securityHeader) { mLocalTxPort = localTxPort; mLocalRxPort = localRxPort; mLastLocalTxPort = lastLocalTxPort; mRemoteTxPort = remoteTxPort; mRemoteRxPort = remoteRxPort; mLastRemoteTxPort = lastRemoteTxPort; mSecurityHeader = securityHeader; } /** * @return The local SIP port number used to send traffic. */ public int getLocalTxPort() { return mLocalTxPort; } /** * @return The Local SIP port number used to receive traffic. */ public int getLocalRxPort() { return mLocalRxPort; } /** * @return The last local SIP port number used for the previous IPsec security association. */ public int getLastLocalTxPort() { return mLastLocalTxPort; } /** * @return The remote port number used by the SIP server to send SIP traffic. */ public int getRemoteTxPort() { return mRemoteTxPort; } /** * @return the remote port number used by the SIP server to receive incoming SIP traffic. */ public int getRemoteRxPort() { return mRemoteRxPort; } /** * @return the remote port number used by the SIP server to send SIP traffic on the previous * IPSec security association. */ public int getLastRemoteTxPort() { return mLastRemoteTxPort; } /** * @return The value of the SIP security verify header. */ public @NonNull String getSipSecurityVerifyHeader() { return mSecurityHeader; } /** * Helper for parcelling this object. * @hide */ public void addToParcel(Parcel dest) { dest.writeInt(mLocalTxPort); dest.writeInt(mLocalRxPort); dest.writeInt(mLastLocalTxPort); dest.writeInt(mRemoteTxPort); dest.writeInt(mRemoteRxPort); dest.writeInt(mLastRemoteTxPort); dest.writeString(mSecurityHeader); } /** * Helper for unparcelling this object. * @hide */ public static IpSecConfiguration fromParcel(Parcel source) { return new IpSecConfiguration(source.readInt(), source.readInt(), source.readInt(), source.readInt(), source.readInt(), source.readInt(), source.readString()); } @Override public String toString() { return "IpSecConfiguration{" + "localTx=" + mLocalTxPort + ", localRx=" + mLocalRxPort + ", lastLocalTx=" + mLastLocalTxPort + ", remoteTx=" + mRemoteTxPort + ", remoteRx=" + mRemoteRxPort + ", lastRemoteTx=" + mLastRemoteTxPort + ", securityHeader=" + mSecurityHeader + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; IpSecConfiguration that = (IpSecConfiguration) o; return mLocalTxPort == that.mLocalTxPort && mLocalRxPort == that.mLocalRxPort && mLastLocalTxPort == that.mLastLocalTxPort && mRemoteTxPort == that.mRemoteTxPort && mRemoteRxPort == that.mRemoteRxPort && mLastRemoteTxPort == that.mLastRemoteTxPort && Objects.equals(mSecurityHeader, that.mSecurityHeader); } @Override public int hashCode() { return Objects.hash(mLocalTxPort, mLocalRxPort, mLastLocalTxPort, mRemoteTxPort, mRemoteRxPort, mLastRemoteTxPort, mSecurityHeader); } } /** * Creates a new instance of {@link SipDelegateConfiguration} composed from optional * configuration items. */ public static final class Builder { private final SipDelegateConfiguration mConfig; /** * * @param version The version associated with the {@link SipDelegateConfiguration} instance * being built. See {@link #getVersion()} for more information. * @param transportType The transport type to use for SIP signalling. * @param localAddr The local socket address used for SIP traffic. * @param serverAddr The SIP server or P-CSCF default IP address for sip traffic. * @see InetAddresses#parseNumericAddress(String) for how to create an * {@link InetAddress} without requiring a DNS lookup. */ public Builder(@IntRange(from = 0) long version, @TransportType int transportType, @NonNull InetSocketAddress localAddr, @NonNull InetSocketAddress serverAddr) { mConfig = new SipDelegateConfiguration(version, transportType, localAddr, serverAddr); } /** * Create a new {@link SipDelegateConfiguration} instance with the same exact configuration * as the passed in instance, except for the version parameter, which will be incremented * by 1. *

* This method is useful for cases where only a small subset of configurations have changed * and the new configuration is based off of the old configuration. * @param c The older {@link SipDelegateConfiguration} instance to base this instance's * configuration off of. */ public Builder(@NonNull SipDelegateConfiguration c) { mConfig = c.copyAndIncrementVersion(); } /** * Sets whether or not SIP compact form is enabled for the associated SIP delegate. *

* If unset, this configuration defaults to {@code false}. * @param isEnabled {@code true} if SIP compact form is enabled for the associated SIP * Delegate, {@code false} if it is not. * @return this Builder instance with the compact form configuration set. */ public @NonNull Builder setSipCompactFormEnabled(boolean isEnabled) { mConfig.mIsSipCompactFormEnabled = isEnabled; return this; } /** * Sets whether or not underlying SIP keepalives are enabled for the associated SIP * delegate. *

* If unset, this configuration defaults to {@code false}. * @param isEnabled {@code true} if SIP keepalives are enabled for the associated SIP * Delegate, {@code false} if it is not. * @return this Builder instance with the new configuration set. */ public @NonNull Builder setSipKeepaliveEnabled(boolean isEnabled) { mConfig.mIsSipKeepaliveEnabled = isEnabled; return this; } /** * Sets the max SIP payload size in bytes to be sent on UDP. If the SIP message payload is * greater than the max UDP payload size, then TCP must be used. *

* If unset, this configuration defaults to {@link #UDP_PAYLOAD_SIZE_UNDEFINED}, or no * size specified. * @param size The maximum SIP payload size in bytes for UDP. * @return this Builder instance with the new configuration set. */ public @NonNull Builder setMaxUdpPayloadSizeBytes(@IntRange(from = 1) int size) { mConfig.mMaxUdpPayloadSize = size; return this; } /** * Sets the IMS public user identifier. *

* If unset, this configuration defaults to {@code null}, or no identifier specified. * @param id The IMS public user identifier. * @return this Builder instance with the new configuration set. */ public @NonNull Builder setPublicUserIdentifier(@Nullable String id) { mConfig.mPublicUserIdentifier = id; return this; } /** * Sets the IMS private user identifier. *

* If unset, this configuration defaults to {@code null}, or no identifier specified. * @param id The IMS private user identifier. * @return this Builder instance with the new configuration set. */ public @NonNull Builder setPrivateUserIdentifier(@Nullable String id) { mConfig.mPrivateUserIdentifier = id; return this; } /** * Sets the IMS home domain. *

* If unset, this configuration defaults to {@code null}, or no domain specified. * @param domain The IMS home domain. * @return this Builder instance with the new configuration set. */ public @NonNull Builder setHomeDomain(@Nullable String domain) { mConfig.mHomeDomain = domain; return this; } /** * Sets the IMEI of the associated device. *

* Application can include the Instance-ID feature tag {@code "+sip.instance"} in the * Contact header with a value of the device IMEI in the form * {@code "urn:gsma:imei:"}. *

* If unset, this configuration defaults to {@code null}, or no IMEI string specified. * @param imei The IMEI of the device. * @return this Builder instance with the new configuration set. */ public @NonNull Builder setImei(@Nullable String imei) { mConfig.mImei = imei; return this; } /** * Set the optional {@link IpSecConfiguration} instance used if the associated SipDelegate * is communicating over IPSec. *

* If unset, this configuration defaults to {@code null} * @param c The IpSecConfiguration instance to set. * @return this Builder instance with IPSec configuration set. */ public @NonNull Builder setIpSecConfiguration(@Nullable IpSecConfiguration c) { mConfig.mIpSecConfiguration = c; return this; } /** * Describes the Device's Public IP Address and port that is set when Network Address * Translation is enabled and the device is behind a NAT. *

* If unset, this configuration defaults to {@code null} * @param addr The {@link InetAddress} representing the device's public IP address and port * when behind a NAT. * @return this Builder instance with the new configuration set. * @see InetAddresses#parseNumericAddress(String) For an example of how to create an * instance of {@link InetAddress} without causing a DNS lookup. */ public @NonNull Builder setNatSocketAddress(@Nullable InetSocketAddress addr) { mConfig.mNatAddress = addr; return this; } /** * Sets the optional URI of the device's Globally routable user-agent URI (GRUU) if this * feature is enabled for the SIP delegate. *

* If unset, this configuration defaults to {@code null} * @param uri The GRUU to set. * @return this builder instance with the new configuration set. */ public @NonNull Builder setPublicGruuUri(@Nullable Uri uri) { mConfig.mGruu = uri; return this; } /** * Sets the SIP authentication header value. *

* If unset, this configuration defaults to {@code null}. * @param header The SIP authentication header's value. * @return this builder instance with the new configuration set. */ public @NonNull Builder setSipAuthenticationHeader(@Nullable String header) { mConfig.mSipAuthHeader = header; return this; } /** * Sets the SIP authentication nonce. *

* If unset, this configuration defaults to {@code null}. * @param nonce The SIP authentication nonce. * @return this builder instance with the new configuration set. */ public @NonNull Builder setSipAuthenticationNonce(@Nullable String nonce) { mConfig.mSipAuthNonce = nonce; return this; } /** * Sets the SIP service route header value. *

* If unset, this configuration defaults to {@code null}. * @param header The SIP service route header value. * @return this builder instance with the new configuration set. */ public @NonNull Builder setSipServiceRouteHeader(@Nullable String header) { mConfig.mServiceRouteHeader = header; return this; } /** * Sets the SIP path header value. *

* If unset, this configuration defaults to {@code null}. * @param header The SIP path header value. * @return this builder instance with the new configuration set. */ public @NonNull Builder setSipPathHeader(@Nullable String header) { mConfig.mPathHeader = header; return this; } /** * Sets the SIP User-Agent header value. *

* If unset, this configuration defaults to {@code null}. * @param header The SIP User-Agent header value. * @return this builder instance with the new configuration set. */ public @NonNull Builder setSipUserAgentHeader(@Nullable String header) { mConfig.mUserAgentHeader = header; return this; } /** * Sets the SIP Contact header's User parameter value. *

* If unset, this configuration defaults to {@code null}. * @param param The SIP Contact header's User parameter value. * @return this builder instance with the new configuration set. */ public @NonNull Builder setSipContactUserParameter(@Nullable String param) { mConfig.mContactUserParam = param; return this; } /** * Sets the SIP P-Access-Network-Info (P-ANI) header value. Populated for networks that * require this information to be provided as part of outgoing SIP messages. *

* If unset, this configuration defaults to {@code null}. * @param header The SIP P-ANI header value. * @return this builder instance with the new configuration set. */ public @NonNull Builder setSipPaniHeader(@Nullable String header) { mConfig.mPaniHeader = header; return this; } /** * Sets the SIP P-Last-Access-Network-Info (P-LANI) header value. Populated for * networks that require this information to be provided as part of outgoing SIP messages. *

* If unset, this configuration defaults to {@code null}. * @param header The SIP P-LANI header value. * @return this builder instance with the new configuration set. */ public @NonNull Builder setSipPlaniHeader(@Nullable String header) { mConfig.mPlaniHeader = header; return this; } /** * Sets the SIP Cellular-Network-Info (CNI) header value (See 3GPP 24.229, section 7.2.15), * populated for networks that require this information to be provided as part of outgoing * SIP messages. *

* If unset, this configuration defaults to {@code null}. * @param header The SIP P-LANI header value. * @return this builder instance with the new configuration set. */ public @NonNull Builder setSipCniHeader(@Nullable String header) { mConfig.mCniHeader = header; return this; } /** * Sets the SIP P-associated-uri header value. *

* If unset, this configuration defaults to {@code null}. * @param header The SIP P-associated-uri header value. * @return this builder instance with the new configuration set. */ public @NonNull Builder setSipAssociatedUriHeader(@Nullable String header) { mConfig.mAssociatedUriHeader = header; return this; } /** * @return A {@link SipDelegateConfiguration} instance with the optional configurations set. */ public @NonNull SipDelegateConfiguration build() { return mConfig; } } private final long mVersion; private final int mTransportType; private final InetSocketAddress mLocalAddress; private final InetSocketAddress mSipServerAddress; private boolean mIsSipCompactFormEnabled = false; private boolean mIsSipKeepaliveEnabled = false; private int mMaxUdpPayloadSize = -1; private String mPublicUserIdentifier = null; private String mPrivateUserIdentifier = null; private String mHomeDomain = null; private String mImei = null; private Uri mGruu = null; private String mSipAuthHeader = null; private String mSipAuthNonce = null; private String mServiceRouteHeader = null; private String mPathHeader = null; private String mUserAgentHeader = null; private String mContactUserParam = null; private String mPaniHeader = null; private String mPlaniHeader = null; private String mCniHeader = null; private String mAssociatedUriHeader = null; private IpSecConfiguration mIpSecConfiguration = null; private InetSocketAddress mNatAddress = null; private SipDelegateConfiguration(long version, int transportType, InetSocketAddress localAddress, InetSocketAddress sipServerAddress) { mVersion = version; mTransportType = transportType; mLocalAddress = localAddress; mSipServerAddress = sipServerAddress; } private SipDelegateConfiguration(Parcel source) { mVersion = source.readLong(); mTransportType = source.readInt(); mLocalAddress = readAddressFromParcel(source); mSipServerAddress = readAddressFromParcel(source); mIsSipCompactFormEnabled = source.readBoolean(); mIsSipKeepaliveEnabled = source.readBoolean(); mMaxUdpPayloadSize = source.readInt(); mPublicUserIdentifier = source.readString(); mPrivateUserIdentifier = source.readString(); mHomeDomain = source.readString(); mImei = source.readString(); mGruu = source.readParcelable(null, android.net.Uri.class); mSipAuthHeader = source.readString(); mSipAuthNonce = source.readString(); mServiceRouteHeader = source.readString(); mPathHeader = source.readString(); mUserAgentHeader = source.readString(); mContactUserParam = source.readString(); mPaniHeader = source.readString(); mPlaniHeader = source.readString(); mCniHeader = source.readString(); mAssociatedUriHeader = source.readString(); boolean isIpsecConfigAvailable = source.readBoolean(); if (isIpsecConfigAvailable) { mIpSecConfiguration = IpSecConfiguration.fromParcel(source); } boolean isNatConfigAvailable = source.readBoolean(); if (isNatConfigAvailable) { mNatAddress = readAddressFromParcel(source); } } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeLong(mVersion); dest.writeInt(mTransportType); writeAddressToParcel(mLocalAddress, dest); writeAddressToParcel(mSipServerAddress, dest); dest.writeBoolean(mIsSipCompactFormEnabled); dest.writeBoolean(mIsSipKeepaliveEnabled); dest.writeInt(mMaxUdpPayloadSize); dest.writeString(mPublicUserIdentifier); dest.writeString(mPrivateUserIdentifier); dest.writeString(mHomeDomain); dest.writeString(mImei); dest.writeParcelable(mGruu, flags); dest.writeString(mSipAuthHeader); dest.writeString(mSipAuthNonce); dest.writeString(mServiceRouteHeader); dest.writeString(mPathHeader); dest.writeString(mUserAgentHeader); dest.writeString(mContactUserParam); dest.writeString(mPaniHeader); dest.writeString(mPlaniHeader); dest.writeString(mCniHeader); dest.writeString(mAssociatedUriHeader); dest.writeBoolean(mIpSecConfiguration != null); if (mIpSecConfiguration != null) { mIpSecConfiguration.addToParcel(dest); } dest.writeBoolean(mNatAddress != null); if (mNatAddress != null) { writeAddressToParcel(mNatAddress, dest); } } /** * @return A copy of this instance with an incremented version. * @hide */ public SipDelegateConfiguration copyAndIncrementVersion() { SipDelegateConfiguration c = new SipDelegateConfiguration(getVersion() + 1, mTransportType, mLocalAddress, mSipServerAddress); c.mIsSipCompactFormEnabled = mIsSipCompactFormEnabled; c.mIsSipKeepaliveEnabled = mIsSipKeepaliveEnabled; c.mMaxUdpPayloadSize = mMaxUdpPayloadSize; c.mIpSecConfiguration = mIpSecConfiguration; c.mNatAddress = mNatAddress; c.mPublicUserIdentifier = mPublicUserIdentifier; c.mPrivateUserIdentifier = mPrivateUserIdentifier; c.mHomeDomain = mHomeDomain; c.mImei = mImei; c.mGruu = mGruu; c.mSipAuthHeader = mSipAuthHeader; c.mSipAuthNonce = mSipAuthNonce; c.mServiceRouteHeader = mServiceRouteHeader; c.mPathHeader = mPathHeader; c.mUserAgentHeader = mUserAgentHeader; c.mContactUserParam = mContactUserParam; c.mPaniHeader = mPaniHeader; c.mPlaniHeader = mPlaniHeader; c.mCniHeader = mCniHeader; c.mAssociatedUriHeader = mAssociatedUriHeader; return c; } /** * An integer representing the version number of this SipDelegateImsConfiguration. * {@link SipMessage}s that are created using this configuration will also have a this * version number associated with them, which will allow the IMS service to validate that the * {@link SipMessage} was using the latest configuration during creation and not a stale * configuration due to race conditions between the configuration being updated and the RCS * application not receiving the updated configuration before generating a new message. *

* The version number should be a positive number that starts at 0 and increments sequentially * as new {@link SipDelegateConfiguration} instances are created to update the IMS * configuration state. * * @return the version number associated with this {@link SipDelegateConfiguration}. */ public @IntRange(from = 0) long getVersion() { return mVersion; } /** * @return The Transport type of the SIP delegate. */ public @TransportType int getTransportType() { return mTransportType; } /** * @return The local IP address and port used for SIP traffic. */ public @NonNull InetSocketAddress getLocalAddress() { return mLocalAddress; } /** * @return The default IP Address and port of the SIP server or P-CSCF used for SIP traffic. */ public @NonNull InetSocketAddress getSipServerAddress() { return mSipServerAddress; } /** * @return {@code true} if SIP compact form is enabled for the associated SIP Delegate, * {@code false} if it is not. */ public boolean isSipCompactFormEnabled() { return mIsSipCompactFormEnabled; } /** * @return {@code true} if SIP keepalives are enabled for the associated SIP Delegate, * {@code false} if it is not. */ public boolean isSipKeepaliveEnabled() { return mIsSipKeepaliveEnabled; } /** * @return The maximum SIP payload size in bytes for UDP or {code -1} if no value was set. */ public int getMaxUdpPayloadSizeBytes() { return mMaxUdpPayloadSize; } /** * @return The IMS public user identifier or {@code null} if it was not set. */ public @Nullable String getPublicUserIdentifier() { return mPublicUserIdentifier; } /** * @return The IMS private user identifier or {@code null} if it was not set. */ public @Nullable String getPrivateUserIdentifier() { return mPrivateUserIdentifier; } /** * @return The IMS home domain or {@code null} if it was not set. */ public @Nullable String getHomeDomain() { return mHomeDomain; } /** * get the IMEI of the associated device. *

* Application can include the Instance-ID feature tag {@code "+sip.instance"} in the Contact * header with a value of the device IMEI in the form {@code "urn:gsma:imei:"}. * @return The IMEI of the device or {@code null} if it was not set. */ public @Nullable String getImei() { return mImei; } /** * @return The IPSec configuration that must be used because SIP is communicating over IPSec. * This returns {@code null} SIP is not communicating over IPSec. */ public @Nullable IpSecConfiguration getIpSecConfiguration() { return mIpSecConfiguration; } /** * @return The public IP address and port of the device due to it being behind a NAT. * This returns {@code null} if the device is not behind a NAT. */ public @Nullable InetSocketAddress getNatSocketAddress() { return mNatAddress; } /** * @return The device's Globally routable user-agent URI (GRUU) or {@code null} if this feature * is not enabled for the SIP delegate. */ public @Nullable Uri getPublicGruuUri() { return mGruu; } /** * @return The value of the SIP authentication header or {@code null} if there is none set. */ public @Nullable String getSipAuthenticationHeader() { return mSipAuthHeader; } /** * @return The value of the SIP authentication nonce or {@code null} if there is none set. */ public @Nullable String getSipAuthenticationNonce() { return mSipAuthNonce; } /** * @return The value of the SIP service route header or {@code null} if there is none set. */ public @Nullable String getSipServiceRouteHeader() { return mServiceRouteHeader; } /** * @return The value of the SIP path header or {@code null} if there is none set. */ public @Nullable String getSipPathHeader() { return mPathHeader; } /** * @return The value of the SIP User-Agent header or {@code null} if there is none set. */ public @Nullable String getSipUserAgentHeader() { return mUserAgentHeader; } /** * @return The value of the SIP Contact header's User parameter or {@code null} if there is * none set. */ public @Nullable String getSipContactUserParameter() { return mContactUserParam; } /** * @return The value of the SIP P-Access-Network-Info (P-ANI) header or {@code null} if there is * none set. */ public @Nullable String getSipPaniHeader() { return mPaniHeader; } /** * @return The value of the SIP P-Last-Access-Network-Info (P-LANI) header or {@code null} if * there is none set. */ public @Nullable String getSipPlaniHeader() { return mPlaniHeader; } /** * @return The value of the SIP Cellular-Network-Info (CNI) header or {@code null} if there is * none set. */ public @Nullable String getSipCniHeader() { return mCniHeader; } /** * @return The value of the SIP P-associated-uri header or {@code null} if there is none set. */ public @Nullable String getSipAssociatedUriHeader() { return mAssociatedUriHeader; } private void writeAddressToParcel(InetSocketAddress addr, Parcel dest) { dest.writeByteArray(addr.getAddress().getAddress()); dest.writeInt(addr.getPort()); } private InetSocketAddress readAddressFromParcel(Parcel source) { final byte[] addressBytes = source.createByteArray(); final int port = source.readInt(); try { return new InetSocketAddress(InetAddress.getByAddress(addressBytes), port); } catch (UnknownHostException e) { // Should not happen, as length of array was verified before parcelling. Log.e("SipDelegateConfiguration", "exception reading address, returning null"); return null; } } @Override public int describeContents() { return 0; } public static final @NonNull Creator CREATOR = new Creator() { @Override public SipDelegateConfiguration createFromParcel(Parcel source) { return new SipDelegateConfiguration(source); } @Override public SipDelegateConfiguration[] newArray(int size) { return new SipDelegateConfiguration[size]; } }; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SipDelegateConfiguration that = (SipDelegateConfiguration) o; return mVersion == that.mVersion && mTransportType == that.mTransportType && mIsSipCompactFormEnabled == that.mIsSipCompactFormEnabled && mIsSipKeepaliveEnabled == that.mIsSipKeepaliveEnabled && mMaxUdpPayloadSize == that.mMaxUdpPayloadSize && Objects.equals(mLocalAddress, that.mLocalAddress) && Objects.equals(mSipServerAddress, that.mSipServerAddress) && Objects.equals(mPublicUserIdentifier, that.mPublicUserIdentifier) && Objects.equals(mPrivateUserIdentifier, that.mPrivateUserIdentifier) && Objects.equals(mHomeDomain, that.mHomeDomain) && Objects.equals(mImei, that.mImei) && Objects.equals(mGruu, that.mGruu) && Objects.equals(mSipAuthHeader, that.mSipAuthHeader) && Objects.equals(mSipAuthNonce, that.mSipAuthNonce) && Objects.equals(mServiceRouteHeader, that.mServiceRouteHeader) && Objects.equals(mPathHeader, that.mPathHeader) && Objects.equals(mUserAgentHeader, that.mUserAgentHeader) && Objects.equals(mContactUserParam, that.mContactUserParam) && Objects.equals(mPaniHeader, that.mPaniHeader) && Objects.equals(mPlaniHeader, that.mPlaniHeader) && Objects.equals(mCniHeader, that.mCniHeader) && Objects.equals(mAssociatedUriHeader, that.mAssociatedUriHeader) && Objects.equals(mIpSecConfiguration, that.mIpSecConfiguration) && Objects.equals(mNatAddress, that.mNatAddress); } @Override public int hashCode() { return Objects.hash(mVersion, mTransportType, mLocalAddress, mSipServerAddress, mIsSipCompactFormEnabled, mIsSipKeepaliveEnabled, mMaxUdpPayloadSize, mPublicUserIdentifier, mPrivateUserIdentifier, mHomeDomain, mImei, mGruu, mSipAuthHeader, mSipAuthNonce, mServiceRouteHeader, mPathHeader, mUserAgentHeader, mContactUserParam, mPaniHeader, mPlaniHeader, mCniHeader, mAssociatedUriHeader, mIpSecConfiguration, mNatAddress); } @Override public String toString() { return "SipDelegateConfiguration{ mVersion=" + mVersion + ", mTransportType=" + mTransportType + '}'; } }