Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3290af87 authored by James Lin's avatar James Lin Committed by Automerger Merge Worker
Browse files

Merge "Update the RCS UCE APIs." into sc-dev am: 22344bbe

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13698340

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I121fe341502dd5c60afd4f9959f5223c101b4efc
parents d95b7b49 22344bbe
Loading
Loading
Loading
Loading
+4 −4
Original line number Original line Diff line number Diff line
@@ -13059,7 +13059,7 @@ package android.telephony.ims {
    method @NonNull public String getServiceId();
    method @NonNull public String getServiceId();
    method @NonNull public String getServiceVersion();
    method @NonNull public String getServiceVersion();
    method @NonNull public String getStatus();
    method @NonNull public String getStatus();
    method @Nullable public String getTimestamp();
    method @Nullable public java.time.Instant getTime();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactPresenceTuple> CREATOR;
    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactPresenceTuple> CREATOR;
    field public static final String SERVICE_ID_CALL_COMPOSER = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callcomposer";
    field public static final String SERVICE_ID_CALL_COMPOSER = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callcomposer";
@@ -13086,7 +13086,7 @@ package android.telephony.ims {
    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setContactUri(@NonNull android.net.Uri);
    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setContactUri(@NonNull android.net.Uri);
    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceCapabilities(@NonNull android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities);
    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceCapabilities(@NonNull android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities);
    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceDescription(@NonNull String);
    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceDescription(@NonNull String);
    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setTimestamp(@NonNull String);
    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setTime(@NonNull java.time.Instant);
  }
  }
  public static final class RcsContactPresenceTuple.ServiceCapabilities implements android.os.Parcelable {
  public static final class RcsContactPresenceTuple.ServiceCapabilities implements android.os.Parcelable {
@@ -13142,7 +13142,7 @@ package android.telephony.ims {
    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException;
    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException;
    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnPublishStateChangedListener(@NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException;
    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnPublishStateChangedListener(@NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException;
    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
    field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
    field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
    field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1
    field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1
@@ -13618,7 +13618,7 @@ package android.telephony.ims.stub {
    ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor);
    ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor);
    method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback);
    method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback);
    method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback);
    method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback);
    method public void subscribeForCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
    method public void subscribeForCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
    field public static final int COMMAND_CODE_FETCH_ERROR = 3; // 0x3
    field public static final int COMMAND_CODE_FETCH_ERROR = 3; // 0x3
    field public static final int COMMAND_CODE_GENERIC_FAILURE = 1; // 0x1
    field public static final int COMMAND_CODE_GENERIC_FAILURE = 1; // 0x1
    field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 5; // 0x5
    field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 5; // 0x5
+57 −5
Original line number Original line Diff line number Diff line
@@ -24,9 +24,14 @@ import android.net.Uri;
import android.os.Build;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;


import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collections;
import java.util.List;
import java.util.List;
@@ -39,6 +44,8 @@ import java.util.List;
@SystemApi
@SystemApi
public final class RcsContactPresenceTuple implements Parcelable {
public final class RcsContactPresenceTuple implements Parcelable {


    private static final String LOG_TAG = "RcsContactPresenceTuple";

    /**
    /**
     * The service ID used to indicate that service discovery via presence is available.
     * The service ID used to indicate that service discovery via presence is available.
     * <p>
     * <p>
@@ -370,7 +377,8 @@ public final class RcsContactPresenceTuple implements Parcelable {
        }
        }


        /**
        /**
         * The optional SIP Contact URI associated with the PIDF tuple element.
         * The optional SIP Contact URI associated with the PIDF tuple element if the network
         * expects the user to use the URI instead of the contact URI to contact it.
         */
         */
        public @NonNull Builder setContactUri(@NonNull Uri contactUri) {
        public @NonNull Builder setContactUri(@NonNull Uri contactUri) {
            mPresenceTuple.mContactUri = contactUri;
            mPresenceTuple.mContactUri = contactUri;
@@ -381,8 +389,24 @@ public final class RcsContactPresenceTuple implements Parcelable {
         * The optional timestamp indicating the data and time of the status change of this tuple.
         * The optional timestamp indicating the data and time of the status change of this tuple.
         * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
         * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
         * string per RFC3339.
         * string per RFC3339.
         * @hide
         */
         */
        public @NonNull Builder setTimestamp(@NonNull String timestamp) {
        public @NonNull Builder setTimestamp(@NonNull String timestamp) {
            try {
                mPresenceTuple.mTimestamp =
                        DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(timestamp, Instant::from);
            } catch (DateTimeParseException e) {
                Log.d(LOG_TAG, "Parse timestamp failed " + e);
            }
            return this;
        }

        /**
         * The optional timestamp indicating the data and time of the status change of this tuple.
         * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
         * string per RFC3339.
         */
        public @NonNull Builder setTime(@NonNull Instant timestamp) {
            mPresenceTuple.mTimestamp = timestamp;
            mPresenceTuple.mTimestamp = timestamp;
            return this;
            return this;
        }
        }
@@ -414,7 +438,7 @@ public final class RcsContactPresenceTuple implements Parcelable {
    }
    }


    private Uri mContactUri;
    private Uri mContactUri;
    private String mTimestamp;
    private Instant mTimestamp;
    private @BasicStatus String mStatus;
    private @BasicStatus String mStatus;


    // The service information in the service-description element.
    // The service information in the service-description element.
@@ -433,7 +457,7 @@ public final class RcsContactPresenceTuple implements Parcelable {


    private RcsContactPresenceTuple(Parcel in) {
    private RcsContactPresenceTuple(Parcel in) {
        mContactUri = in.readParcelable(Uri.class.getClassLoader());
        mContactUri = in.readParcelable(Uri.class.getClassLoader());
        mTimestamp = in.readString();
        mTimestamp = convertStringFormatTimeToInstant(in.readString());
        mStatus = in.readString();
        mStatus = in.readString();
        mServiceId = in.readString();
        mServiceId = in.readString();
        mServiceVersion = in.readString();
        mServiceVersion = in.readString();
@@ -444,7 +468,7 @@ public final class RcsContactPresenceTuple implements Parcelable {
    @Override
    @Override
    public void writeToParcel(@NonNull Parcel out, int flags) {
    public void writeToParcel(@NonNull Parcel out, int flags) {
        out.writeParcelable(mContactUri, flags);
        out.writeParcelable(mContactUri, flags);
        out.writeString(mTimestamp);
        out.writeString(convertInstantToStringFormat(mTimestamp));
        out.writeString(mStatus);
        out.writeString(mStatus);
        out.writeString(mServiceId);
        out.writeString(mServiceId);
        out.writeString(mServiceVersion);
        out.writeString(mServiceVersion);
@@ -470,6 +494,26 @@ public final class RcsContactPresenceTuple implements Parcelable {
                }
                }
            };
            };


    // Convert the Instant to the string format
    private String convertInstantToStringFormat(Instant instant) {
        if (instant == null) {
            return "";
        }
        return instant.toString();
    }

    // Convert the time string format to Instant
    private @Nullable Instant convertStringFormatTimeToInstant(String timestamp) {
        if (TextUtils.isEmpty(timestamp)) {
            return null;
        }
        try {
            return DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(timestamp, Instant::from);
        } catch (DateTimeParseException e) {
            return null;
        }
    }

    /** @return the status of the tuple element. */
    /** @return the status of the tuple element. */
    public @NonNull @BasicStatus String getStatus() {
    public @NonNull @BasicStatus String getStatus() {
        return mStatus;
        return mStatus;
@@ -490,8 +534,16 @@ public final class RcsContactPresenceTuple implements Parcelable {
        return mContactUri;
        return mContactUri;
    }
    }


    /** @return the timestamp element contained in the tuple if it exists */
    /**
     * @return the timestamp element contained in the tuple if it exists
     * @hide
     */
    public @Nullable String getTimestamp() {
    public @Nullable String getTimestamp() {
        return (mTimestamp == null) ? null : mTimestamp.toString();
    }

    /** @return the timestamp element contained in the tuple if it exists */
    public @Nullable Instant getTime() {
        return mTimestamp;
        return mTimestamp;
    }
    }


+1 −0
Original line number Original line Diff line number Diff line
@@ -340,6 +340,7 @@ public final class RcsContactUceCapability implements Parcelable {
    }
    }


    /**
    /**
     * Retrieve the contact URI requested by the applications.
     * @return the URI representing the contact associated with the capabilities.
     * @return the URI representing the contact associated with the capabilities.
     */
     */
    public @NonNull Uri getContactUri() {
    public @NonNull Uri getContactUri() {
+98 −4
Original line number Original line Diff line number Diff line
@@ -32,11 +32,12 @@ import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
import android.util.Log;


import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashMap;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
@@ -431,13 +432,15 @@ public class RcsUceAdapter {


        /**
        /**
         * The pending request has completed successfully due to all requested contacts information
         * The pending request has completed successfully due to all requested contacts information
         * being delivered.
         * being delivered. The callback {@link #onCapabilitiesReceived(List)}
         * for each contacts is required to be called before {@link #onComplete} is called.
         */
         */
        void onComplete();
        void onComplete();


        /**
        /**
         * The pending request has resulted in an error and may need to be retried, depending on the
         * The pending request has resulted in an error and may need to be retried, depending on the
         * error code.
         * error code. The callback {@link #onCapabilitiesReceived(List)}
         * for each contacts is required to be called before {@link #onError} is called.
         * @param errorCode The reason for the framework being unable to process the request.
         * @param errorCode The reason for the framework being unable to process the request.
         * @param retryIntervalMillis The time in milliseconds the requesting application should
         * @param retryIntervalMillis The time in milliseconds the requesting application should
         * wait before retrying, if non-zero.
         * wait before retrying, if non-zero.
@@ -484,7 +487,6 @@ public class RcsUceAdapter {
     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
     * @hide
     * @hide
     */
     */
    @SystemApi
    @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE,
    @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE,
            Manifest.permission.READ_CONTACTS})
            Manifest.permission.READ_CONTACTS})
    public void requestCapabilities(@NonNull List<Uri> contactNumbers,
    public void requestCapabilities(@NonNull List<Uri> contactNumbers,
@@ -549,6 +551,94 @@ public class RcsUceAdapter {
        }
        }
    }
    }


    /**
     * Request the User Capability Exchange capabilities for one or more contacts.
     * <p>
     * This will return the cached capabilities of the contact and will not perform a capability
     * poll on the network unless there are contacts being queried with stale information.
     * <p>
     * Be sure to check the availability of this feature using
     * {@link ImsRcsManager#isAvailable(int, int)} and ensuring
     * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or
     * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else
     * this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
     *
     * @param contactNumbers A list of numbers that the capabilities are being requested for.
     * @param executor The executor that will be used when the request is completed and the
     *         {@link CapabilitiesCallback} is called.
     * @param c A one-time callback for when the request for capabilities completes or there is an
     *         error processing the request.
     * @throws ImsException if the subscription associated with this instance of
     * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
     * available. This can happen if the ImsService has crashed, for example, or if the subscription
     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
     * @hide
     */
    @SystemApi
    @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE,
            Manifest.permission.READ_CONTACTS})
    public void requestCapabilities(@NonNull Collection<Uri> contactNumbers,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull CapabilitiesCallback c) throws ImsException {
        if (c == null) {
            throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback.");
        }
        if (executor == null) {
            throw new IllegalArgumentException("Must include a non-null Executor.");
        }
        if (contactNumbers == null) {
            throw new IllegalArgumentException("Must include non-null contact number list.");
        }

        IImsRcsController imsRcsController = getIImsRcsController();
        if (imsRcsController == null) {
            Log.e(TAG, "requestCapabilities: IImsRcsController is null");
            throw new ImsException("Can not find remote IMS service",
                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
        }

        IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() {
            @Override
            public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
                final long callingIdentity = Binder.clearCallingIdentity();
                try {
                    executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
                } finally {
                    restoreCallingIdentity(callingIdentity);
                }
            }
            @Override
            public void onComplete() {
                final long callingIdentity = Binder.clearCallingIdentity();
                try {
                    executor.execute(() -> c.onComplete());
                } finally {
                    restoreCallingIdentity(callingIdentity);
                }
            }
            @Override
            public void onError(int errorCode, long retryAfterMilliseconds) {
                final long callingIdentity = Binder.clearCallingIdentity();
                try {
                    executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds));
                } finally {
                    restoreCallingIdentity(callingIdentity);
                }
            }
        };

        try {
            imsRcsController.requestCapabilities(mSubId, mContext.getOpPackageName(),
                    mContext.getAttributionTag(), new ArrayList(contactNumbers), internalCallback);
        } catch (ServiceSpecificException e) {
            throw new ImsException(e.toString(), e.errorCode);
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling IImsRcsController#requestCapabilities", e);
            throw new ImsException("Remote IMS Service is not available",
                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
        }
    }

    /**
    /**
     * Ignore the device cache and perform a capability discovery for one contact, also called
     * Ignore the device cache and perform a capability discovery for one contact, also called
     * "availability fetch."
     * "availability fetch."
@@ -570,6 +660,10 @@ public class RcsUceAdapter {
     * {@link CapabilitiesCallback} is called.
     * {@link CapabilitiesCallback} is called.
     * @param c A one-time callback for when the request for capabilities completes or there is
     * @param c A one-time callback for when the request for capabilities completes or there is
     * an error processing the request.
     * an error processing the request.
     * @throws ImsException if the subscription associated with this instance of
     * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
     * available. This can happen if the ImsService has crashed, for example, or if the subscription
     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
     * @hide
     * @hide
     */
     */
    @SystemApi
    @SystemApi
+38 −2
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ import android.util.Pair;


import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
import java.util.List;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executor;


@@ -241,7 +242,7 @@ public class RcsCapabilityExchangeImplBase {


        /**
        /**
         * Notify the framework of the response to the SUBSCRIBE request from
         * Notify the framework of the response to the SUBSCRIBE request from
         * {@link #subscribeForCapabilities(List, SubscribeResponseCallback)}.
         * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)}.
         * <p>
         * <p>
         * If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the
         * If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the
         * framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate},
         * framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate},
@@ -266,7 +267,7 @@ public class RcsCapabilityExchangeImplBase {


        /**
        /**
         * Notify the framework  of the response to the SUBSCRIBE request from
         * Notify the framework  of the response to the SUBSCRIBE request from
         * {@link #subscribeForCapabilities(List, SubscribeResponseCallback)} that also
         * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)} that also
         * includes a reason provided in the “reason” header. See RFC3326 for more
         * includes a reason provided in the “reason” header. See RFC3326 for more
         * information.
         * information.
         *
         *
@@ -388,6 +389,7 @@ public class RcsCapabilityExchangeImplBase {
     * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
     * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
     * capabilities for.
     * capabilities for.
     * @param cb The callback of the subscribe request.
     * @param cb The callback of the subscribe request.
     * @hide
     */
     */
    // executor used is defined in the constructor.
    // executor used is defined in the constructor.
    @SuppressLint("ExecutorRegistration")
    @SuppressLint("ExecutorRegistration")
@@ -402,6 +404,40 @@ public class RcsCapabilityExchangeImplBase {
        }
        }
    }
    }


    /**
     * The user capabilities of one or multiple contacts have been requested by the framework.
     * <p>
     * The implementer must follow up this call with an
     * {@link SubscribeResponseCallback#onCommandError} call to indicate this operation has failed.
     * The response from the network to the SUBSCRIBE request must be sent back to the framework
     * using {@link SubscribeResponseCallback#onNetworkResponse(int, String)}.
     * As NOTIFY requests come in from the network, the requested contact’s capabilities should be
     * sent back to the framework using
     * {@link SubscribeResponseCallback#onNotifyCapabilitiesUpdate(List<String>}) and
     * {@link SubscribeResponseCallback#onResourceTerminated(List<Pair<Uri, String>>)}
     * should be called with the presence information for the contacts specified.
     * <p>
     * Once the subscription is terminated,
     * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the
     * framework to finish listening for NOTIFY responses.
     *
     * @param uris A {@link Collection} of the {@link Uri}s that the framework is requesting the
     * UCE capabilities for.
     * @param cb The callback of the subscribe request.
     */
    // executor used is defined in the constructor.
    @SuppressLint("ExecutorRegistration")
    public void subscribeForCapabilities(@NonNull Collection<Uri> uris,
            @NonNull SubscribeResponseCallback cb) {
        // Stub - to be implemented by service
        Log.w(LOG_TAG, "subscribeForCapabilities called with no implementation.");
        try {
            cb.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
        } catch (ImsException e) {
            // Do not do anything, this is a stub implementation.
        }
    }

    /**
    /**
     * The capabilities of this device have been updated and should be published to the network.
     * The capabilities of this device have been updated and should be published to the network.
     * <p>
     * <p>