diff options
| author | 2021-01-13 00:33:57 +0000 | |
|---|---|---|
| committer | 2021-01-13 00:33:57 +0000 | |
| commit | 5b51530d0d960ee21a26ec4460abfe49b3657e5a (patch) | |
| tree | 5315851831d2bba8bb2456736cfbc9f9e038ae23 | |
| parent | bbd9fb5c27045558af4368eae7edad2e83152307 (diff) | |
| parent | 50c18c12c66f141b3574a473e2bf199d7a460438 (diff) | |
Merge "[RCS UCE] Expose the RCS UCE publishing device's capabilities APIs"
11 files changed, 597 insertions, 188 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 74a7c1dab6d3..24788be6d031 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -11570,7 +11570,32 @@ package android.telephony.ims { } public class RcsUceAdapter { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addOnPublishStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) 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.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException; + field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 7; // 0x7 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 6; // 0x6 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 4; // 0x4 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 5; // 0x5 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 9; // 0x9 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 2; // 0x2 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 3; // 0x3 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 8; // 0x8 + field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 0; // 0x0 + field public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; // 0x2 + field public static final int PUBLISH_STATE_OK = 1; // 0x1 + field public static final int PUBLISH_STATE_OTHER_ERROR = 6; // 0x6 + field public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4; // 0x4 + field public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5; // 0x5 + field public static final int PUBLISH_STATE_VOICE_PROVISION_ERROR = 3; // 0x3 + } + + public static interface RcsUceAdapter.OnPublishStateChangedListener { + method public void onPublishStateChange(int); } public final class RtpHeaderExtension implements android.os.Parcelable { @@ -11777,16 +11802,24 @@ package android.telephony.ims.feature { } public class RcsFeature extends android.telephony.ims.feature.ImsFeature { - ctor public RcsFeature(); + ctor @Deprecated public RcsFeature(); + ctor public RcsFeature(@NonNull java.util.concurrent.Executor); method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); + method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener); method public void onFeatureReady(); method public void onFeatureRemoved(); + method public void removeCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase); } } package android.telephony.ims.stub { + public interface CapabilityExchangeEventListener { + method public void onRequestPublishCapabilities(int) throws android.telephony.ims.ImsException; + method public void onUnpublish() throws android.telephony.ims.ImsException; + } + public interface DelegateConnectionMessageCallback { method public void onMessageReceived(@NonNull android.telephony.ims.SipMessage); method public void onMessageSendFailure(@NonNull String, int); @@ -11967,6 +12000,27 @@ package android.telephony.ims.stub { method public int updateColr(int); } + public class RcsCapabilityExchangeImplBase { + ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor); + method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback); + 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_INSUFFICIENT_MEMORY = 5; // 0x5 + field public static final int COMMAND_CODE_INVALID_PARAM = 2; // 0x2 + field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 6; // 0x6 + field public static final int COMMAND_CODE_NOT_FOUND = 8; // 0x8 + field public static final int COMMAND_CODE_NOT_SUPPORTED = 7; // 0x7 + field public static final int COMMAND_CODE_NO_CHANGE = 10; // 0xa + field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 4; // 0x4 + field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 9; // 0x9 + field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0 + } + + public static interface RcsCapabilityExchangeImplBase.PublishResponseCallback { + method public void onCommandError(int) throws android.telephony.ims.ImsException; + method public void onNetworkResponse(@IntRange(from=100, to=699) int, @NonNull String) throws android.telephony.ims.ImsException; + } + public interface SipDelegate { method public void closeDialog(@NonNull String); method public void notifyMessageReceiveError(@NonNull String, int); diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java index e4d20e965c49..519d0164b0d6 100644 --- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java +++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java @@ -34,7 +34,7 @@ import java.util.List; * network during a SUBSCRIBE request. See RFC3863 for more information. * @hide */ -public class RcsContactPresenceTuple implements Parcelable { +public final class RcsContactPresenceTuple implements Parcelable { /** The service id of the MMTEL */ public static final String SERVICE_ID_MMTEL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel"; @@ -61,7 +61,7 @@ public class RcsContactPresenceTuple implements Parcelable { * An optional addition to the PIDF Presence Tuple containing service capabilities, which is * defined in the servcaps element. See RFC5196, section 3.2.1. */ - public static class ServiceCapabilities implements Parcelable { + public static final class ServiceCapabilities implements Parcelable { /** The service can simultaneously send and receive data. */ public static final String DUPLEX_MODE_FULL = "full"; @@ -88,7 +88,7 @@ public class RcsContactPresenceTuple implements Parcelable { /** * Builder to help construct {@link ServiceCapabilities} instances. */ - public static class Builder { + public static final class Builder { private ServiceCapabilities mCapabilities; @@ -106,7 +106,7 @@ public class RcsContactPresenceTuple implements Parcelable { * Add the supported duplex mode. * @param mode The supported duplex mode */ - public Builder addSupportedDuplexMode(@NonNull @DuplexMode String mode) { + public @NonNull Builder addSupportedDuplexMode(@NonNull @DuplexMode String mode) { mCapabilities.mSupportedDuplexModeList.add(mode); return this; } @@ -115,7 +115,7 @@ public class RcsContactPresenceTuple implements Parcelable { * Add the unsupported duplex mode. * @param mode The unsupported duplex mode */ - public Builder addUnsupportedDuplexMode(@NonNull @DuplexMode String mode) { + public @NonNull Builder addUnsupportedDuplexMode(@NonNull @DuplexMode String mode) { mCapabilities.mUnsupportedDuplexModeList.add(mode); return this; } @@ -123,7 +123,7 @@ public class RcsContactPresenceTuple implements Parcelable { /** * @return the ServiceCapabilities instance. */ - public ServiceCapabilities build() { + public @NonNull ServiceCapabilities build() { return mCapabilities; } } @@ -211,9 +211,9 @@ public class RcsContactPresenceTuple implements Parcelable { /** * Builder to help construct {@link RcsContactPresenceTuple} instances. */ - public static class Builder { + public static final class Builder { - private RcsContactPresenceTuple mPresenceTuple; + private final RcsContactPresenceTuple mPresenceTuple; /** * Builds a RcsContactPresenceTuple instance. @@ -230,7 +230,7 @@ public class RcsContactPresenceTuple implements Parcelable { /** * The optional SIP Contact URI associated with the PIDF tuple element. */ - public Builder addContactUri(@NonNull Uri contactUri) { + public @NonNull Builder addContactUri(@NonNull Uri contactUri) { mPresenceTuple.mContactUri = contactUri; return this; } @@ -239,7 +239,7 @@ public class RcsContactPresenceTuple implements Parcelable { * The optional timestamp indicating the data and time of the status change of this tuple. * See RFC3863, section 4.1.7 for more information on the expected format. */ - public Builder addTimeStamp(@NonNull String timestamp) { + public @NonNull Builder addTimeStamp(@NonNull String timestamp) { mPresenceTuple.mTimestamp = timestamp; return this; } @@ -248,7 +248,7 @@ public class RcsContactPresenceTuple implements Parcelable { * An optional parameter containing the description element of the service-description. See * OMA Presence SIMPLE specification v1.1 */ - public Builder addDescription(@NonNull String description) { + public @NonNull Builder addDescription(@NonNull String description) { mPresenceTuple.mServiceDescription = description; return this; } @@ -257,7 +257,7 @@ public class RcsContactPresenceTuple implements Parcelable { * An optional parameter containing the service capabilities of the presence tuple if they * are present in the servcaps element. */ - public Builder addServiceCapabilities(@NonNull ServiceCapabilities caps) { + public @NonNull Builder addServiceCapabilities(@NonNull ServiceCapabilities caps) { mPresenceTuple.mServiceCapabilities = caps; return this; } @@ -265,7 +265,7 @@ public class RcsContactPresenceTuple implements Parcelable { /** * @return the constructed instance. */ - public RcsContactPresenceTuple build() { + public @NonNull RcsContactPresenceTuple build() { return mPresenceTuple; } } diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java index 5848be8b0bf2..d4715bfeeb3e 100644 --- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java +++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java @@ -144,7 +144,7 @@ public final class RcsContactUceCapability implements Parcelable { * @param tag the supported feature tag * @return this OptionBuilder */ - public @NonNull OptionsBuilder addFeatureTag(String tag) { + public @NonNull OptionsBuilder addFeatureTag(@NonNull String tag) { mCapabilities.mFeatureTags.add(tag); return this; } @@ -154,7 +154,7 @@ public final class RcsContactUceCapability implements Parcelable { * @param tags the list of the supported feature tags * @return this OptionBuilder */ - public @NonNull OptionsBuilder addFeatureTags(List<String> tags) { + public @NonNull OptionsBuilder addFeatureTags(@NonNull List<String> tags) { mCapabilities.mFeatureTags.addAll(tags); return this; } @@ -195,7 +195,7 @@ public final class RcsContactUceCapability implements Parcelable { * @param tuple The {@link RcsContactPresenceTuple} to be added into. * @return this PresenceBuilder */ - public @NonNull PresenceBuilder addCapabilityTuple(RcsContactPresenceTuple tuple) { + public @NonNull PresenceBuilder addCapabilityTuple(@NonNull RcsContactPresenceTuple tuple) { mCapabilities.mPresenceTuples.add(tuple); return this; } @@ -205,7 +205,8 @@ public final class RcsContactUceCapability implements Parcelable { * @param tuples The list of the {@link RcsContactPresenceTuple} to be added into. * @return this PresenceBuilder */ - public @NonNull PresenceBuilder addCapabilityTuples(List<RcsContactPresenceTuple> tuples) { + public @NonNull PresenceBuilder addCapabilityTuples( + @NonNull List<RcsContactPresenceTuple> tuples) { mCapabilities.mPresenceTuples.addAll(tuples); return this; } @@ -282,7 +283,7 @@ public final class RcsContactUceCapability implements Parcelable { * @return The feature tags present in the OPTIONS response from the network. * <p> * Note: this is only populated if {@link #getCapabilityMechanism} is - * {@link CAPABILITY_MECHANISM_OPTIONS} + * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS} */ public @NonNull List<String> getOptionsFeatureTags() { if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) { @@ -296,7 +297,7 @@ public final class RcsContactUceCapability implements Parcelable { * contained in the NOTIFY response from the network. * <p> * Note: this is only populated if {@link #getCapabilityMechanism} is - * {@link CAPABILITY_MECHANISM_PRESENCE} + * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE} */ public @NonNull List<RcsContactPresenceTuple> getPresenceTuples() { if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) { @@ -312,9 +313,9 @@ public final class RcsContactUceCapability implements Parcelable { * * <p> * Note: this is only populated if {@link #getCapabilityMechanism} is - * {@link CAPABILITY_MECHANISM_PRESENCE} + * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE} */ - public @Nullable RcsContactPresenceTuple getPresenceTuple(String serviceId) { + public @Nullable RcsContactPresenceTuple getPresenceTuple(@NonNull String serviceId) { if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) { return null; } diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java index 8d7742b7510b..6c31466c2a89 100644 --- a/telephony/java/android/telephony/ims/RcsUceAdapter.java +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -36,7 +36,9 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.Executor; /** @@ -110,7 +112,7 @@ public class RcsUceAdapter { public static final int ERROR_FORBIDDEN = 6; /** - * The contact URI requested is not provisioned for VoLTE or it is not known as an IMS + * The contact URI requested is not provisioned for voice or it is not known as an IMS * subscriber to the carrier network. * @hide */ @@ -128,26 +130,26 @@ public class RcsUceAdapter { * The network did not respond to the capabilities request before the request timed out. * @hide */ - public static final int ERROR_REQUEST_TIMEOUT = 10; + public static final int ERROR_REQUEST_TIMEOUT = 9; /** * The request failed due to the service having insufficient memory. * @hide */ - public static final int ERROR_INSUFFICIENT_MEMORY = 11; + public static final int ERROR_INSUFFICIENT_MEMORY = 10; /** * The network was lost while trying to complete the request. * @hide */ - public static final int ERROR_LOST_NETWORK = 12; + public static final int ERROR_LOST_NETWORK = 11; /** * The network is temporarily unavailable or busy. Retries should only be done after the retry * time returned in {@link CapabilitiesCallback#onError} has elapsed. * @hide */ - public static final int ERROR_SERVER_UNAVAILABLE = 13; + public static final int ERROR_SERVER_UNAVAILABLE = 12; /**@hide*/ @Retention(RetentionPolicy.SOURCE) @@ -168,69 +170,93 @@ public class RcsUceAdapter { public @interface ErrorCode {} /** + * A capability update has been requested but the reason is unknown. + * @hide + */ + @SystemApi + public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 0; + + /** * A capability update has been requested due to the Entity Tag (ETag) expiring. * @hide */ - public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; + @SystemApi + public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; + /** * A capability update has been requested due to moving to LTE with VoPS disabled. * @hide */ - public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; + @SystemApi + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 2; + /** * A capability update has been requested due to moving to LTE with VoPS enabled. * @hide */ - public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; + @SystemApi + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 3; + /** * A capability update has been requested due to moving to eHRPD. * @hide */ - public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; + @SystemApi + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 4; + /** * A capability update has been requested due to moving to HSPA+. * @hide */ - public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; + @SystemApi + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 5; + /** * A capability update has been requested due to moving to 3G. * @hide */ - public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; + @SystemApi + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 6; + /** * A capability update has been requested due to moving to 2G. * @hide */ - public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; + @SystemApi + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 7; + /** * A capability update has been requested due to moving to WLAN * @hide */ - public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; + @SystemApi + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 8; + /** * A capability update has been requested due to moving to IWLAN * @hide */ - public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; - /** - * A capability update has been requested but the reason is unknown. - * @hide - */ - public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; + @SystemApi + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 9; + /** * A capability update has been requested due to moving to 5G NR with VoPS disabled. * @hide */ + @SystemApi public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; + /** * A capability update has been requested due to moving to 5G NR with VoPS enabled. * @hide */ + @SystemApi public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; /**@hide*/ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "ERROR_", value = { + CAPABILITY_UPDATE_TRIGGER_UNKNOWN, CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED, CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED, CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED, @@ -240,7 +266,6 @@ public class RcsUceAdapter { CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G, CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN, CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN, - CAPABILITY_UPDATE_TRIGGER_UNKNOWN, CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED, CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED }) @@ -251,32 +276,37 @@ public class RcsUceAdapter { * UCE. * @hide */ + @SystemApi public static final int PUBLISH_STATE_OK = 1; /** * The hasn't published its capabilities since boot or hasn't gotten any publish response yet. * @hide */ + @SystemApi public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; /** * The device has tried to publish its capabilities, which has resulted in an error. This error - * is related to the fact that the device is not VoLTE provisioned. + * is related to the fact that the device is not provisioned for voice. * @hide */ - public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; + @SystemApi + public static final int PUBLISH_STATE_VOICE_PROVISION_ERROR = 3; /** * The device has tried to publish its capabilities, which has resulted in an error. This error * is related to the fact that the device is not RCS or UCE provisioned. * @hide */ + @SystemApi public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4; /** * The last publish resulted in a "408 Request Timeout" response. * @hide */ + @SystemApi public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5; /** @@ -286,6 +316,7 @@ public class RcsUceAdapter { * Device shall retry with exponential back-off. * @hide */ + @SystemApi public static final int PUBLISH_STATE_OTHER_ERROR = 6; /**@hide*/ @@ -293,7 +324,7 @@ public class RcsUceAdapter { @IntDef(prefix = "PUBLISH_STATE_", value = { PUBLISH_STATE_OK, PUBLISH_STATE_NOT_PUBLISHED, - PUBLISH_STATE_VOLTE_PROVISION_ERROR, + PUBLISH_STATE_VOICE_PROVISION_ERROR, PUBLISH_STATE_RCS_PROVISION_ERROR, PUBLISH_STATE_REQUEST_TIMEOUT, PUBLISH_STATE_OTHER_ERROR @@ -301,56 +332,62 @@ public class RcsUceAdapter { public @interface PublishState {} /** - * An application can use {@link #registerPublishStateCallback} to register a - * {@link PublishStateCallback), which will notify the user when the publish state to the - * network changes. + * An application can use {@link #addOnPublishStateChangedListener} to register a + * {@link OnPublishStateChangedListener ), which will notify the user when the publish state to + * the network changes. * @hide */ - public static class PublishStateCallback { + @SystemApi + public interface OnPublishStateChangedListener { + /** + * Notifies the callback when the publish state has changed. + * @param publishState The latest update to the publish state. + */ + void onPublishStateChange(@PublishState int publishState); + } - private static class PublishStateBinder extends IRcsUcePublishStateCallback.Stub { + /** + * An application can use {@link #addOnPublishStateChangedListener} to register a + * {@link OnPublishStateChangedListener ), which will notify the user when the publish state to + * the network changes. + * @hide + */ + public static class PublishStateCallbackAdapter { - private final PublishStateCallback mLocalCallback; - private Executor mExecutor; + private static class PublishStateBinder extends IRcsUcePublishStateCallback.Stub { + private final OnPublishStateChangedListener mPublishStateChangeListener; + private final Executor mExecutor; - PublishStateBinder(PublishStateCallback c) { - mLocalCallback = c; + PublishStateBinder(Executor executor, OnPublishStateChangedListener listener) { + mExecutor = executor; + mPublishStateChangeListener = listener; } @Override public void onPublishStateChanged(int publishState) { - if (mLocalCallback == null) return; + if (mPublishStateChangeListener == null) return; final long callingIdentity = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> mLocalCallback.onChanged(publishState)); + mExecutor.execute(() -> + mPublishStateChangeListener.onPublishStateChange(publishState)); } finally { restoreCallingIdentity(callingIdentity); } } - - private void setExecutor(Executor executor) { - mExecutor = executor; - } } - private final PublishStateBinder mBinder = new PublishStateBinder(this); + private final PublishStateBinder mBinder; + + public PublishStateCallbackAdapter(@NonNull Executor executor, + @NonNull OnPublishStateChangedListener listener) { + mBinder = new PublishStateBinder(executor, listener); + } /**@hide*/ public final IRcsUcePublishStateCallback getBinder() { return mBinder; } - - private void setExecutor(Executor executor) { - mBinder.setExecutor(executor); - } - - /** - * Notifies the callback when the publish state has changed. - * @param publishState The latest update to the publish state. - */ - public void onChanged(@PublishState int publishState) { - } } /** @@ -395,6 +432,8 @@ public class RcsUceAdapter { private final Context mContext; private final int mSubId; + private final Map<OnPublishStateChangedListener, PublishStateCallbackAdapter> + mPublishStateCallbacks; /** * Not to be instantiated directly, use {@link ImsRcsManager#getUceAdapter()} to instantiate @@ -404,6 +443,7 @@ public class RcsUceAdapter { RcsUceAdapter(Context context, int subId) { mContext = context; mSubId = subId; + mPublishStateCallbacks = new HashMap<>(); } /** @@ -588,6 +628,7 @@ public class RcsUceAdapter { * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @PublishState int getUcePublishState() throws ImsException { IImsRcsController imsRcsController = getIImsRcsController(); @@ -609,81 +650,90 @@ public class RcsUceAdapter { } /** - * Registers a {@link PublishStateCallback} with the system, which will provide publish state - * updates for the subscription specified in {@link ImsManager@getRcsManager(subid)}. + * Registers a {@link OnPublishStateChangedListener} with the system, which will provide publish + * state updates for the subscription specified in {@link ImsManager@getRcsManager(subid)}. * <p> * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to subscription * changed events and call {@link #unregisterPublishStateCallback} to clean up. * <p> - * The registered {@link PublishStateCallback} will also receive a callback when it is + * The registered {@link OnPublishStateChangedListener} will also receive a callback when it is * registered with the current publish state. * * @param executor The executor the listener callback events should be run on. - * @param c The {@link PublishStateCallback} to be added. + * @param listener The {@link OnPublishStateChangedListener} to be added. * @throws ImsException if the subscription associated with this callback is valid, but * the {@link ImsService} associated with the subscription is not available. This can happen if * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed * reason. * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void registerPublishStateCallback(@NonNull @CallbackExecutor Executor executor, - @NonNull PublishStateCallback c) throws ImsException { - if (c == null) { - throw new IllegalArgumentException("Must include a non-null PublishStateCallback."); - } + public void addOnPublishStateChangedListener(@NonNull @CallbackExecutor Executor executor, + @NonNull OnPublishStateChangedListener listener) throws ImsException { if (executor == null) { throw new IllegalArgumentException("Must include a non-null Executor."); } + if (listener == null) { + throw new IllegalArgumentException( + "Must include a non-null OnPublishStateChangedListener."); + } IImsRcsController imsRcsController = getIImsRcsController(); if (imsRcsController == null) { - Log.e(TAG, "registerPublishStateCallback : IImsRcsController is null"); + Log.e(TAG, "addOnPublishStateChangedListener : IImsRcsController is null"); throw new ImsException("Cannot find remote IMS service", - ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } - c.setExecutor(executor); + PublishStateCallbackAdapter stateCallback = addPublishStateCallback(executor, listener); try { - imsRcsController.registerUcePublishStateCallback(mSubId, c.getBinder()); + imsRcsController.registerUcePublishStateCallback(mSubId, stateCallback.getBinder()); } catch (ServiceSpecificException e) { throw new ImsException(e.getMessage(), e.errorCode); } catch (RemoteException e) { Log.e(TAG, "Error calling IImsRcsController#registerUcePublishStateCallback", e); throw new ImsException("Remote IMS Service is not available", - ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } } /** - * Removes an existing {@link PublishStateCallback}. + * Removes an existing {@link OnPublishStateChangedListener}. * <p> * When the subscription associated with this callback is removed * (SIM removed, ESIM swap,etc...), this callback will automatically be removed. If this method * is called for an inactive subscription, it will result in a no-op. * - * @param c The callback to be unregistered. + * @param listener The callback to be unregistered. * @throws ImsException if the subscription associated with this callback is valid, but * the {@link ImsService} associated with the subscription is not available. This can happen if * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed * reason. * @hide */ + @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void unregisterPublishStateCallback(@NonNull PublishStateCallback c) - throws ImsException { - if (c == null) { - throw new IllegalArgumentException("Must include a non-null PublishStateCallback."); + public void removeOnPublishStateChangedListener( + @NonNull OnPublishStateChangedListener listener) throws ImsException { + if (listener == null) { + throw new IllegalArgumentException( + "Must include a non-null OnPublishStateChangedListener."); } IImsRcsController imsRcsController = getIImsRcsController(); if (imsRcsController == null) { - Log.e(TAG, "unregisterPublishStateCallback: IImsRcsController is null"); + Log.e(TAG, "removeOnPublishStateChangedListener: IImsRcsController is null"); throw new ImsException("Cannot find remote IMS service", ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } + PublishStateCallbackAdapter callback = removePublishStateCallback(listener); + if (callback == null) { + return; + } + try { - imsRcsController.unregisterUcePublishStateCallback(mSubId, c.getBinder()); + imsRcsController.unregisterUcePublishStateCallback(mSubId, callback.getBinder()); } catch (android.os.ServiceSpecificException e) { throw new ImsException(e.getMessage(), e.errorCode); } catch (RemoteException e) { @@ -763,6 +813,36 @@ public class RcsUceAdapter { } } + /** + * Add the {@link OnPublishStateChangedListener} to collection for tracking. + * @param executor The executor that will be used when the publish state is changed and the + * {@link OnPublishStateChangedListener} is called. + * @param listener The {@link OnPublishStateChangedListener} to call the publish state changed. + * @return The {@link PublishStateCallbackAdapter} to wrapper the + * {@link OnPublishStateChangedListener} + */ + private PublishStateCallbackAdapter addPublishStateCallback(@NonNull Executor executor, + @NonNull OnPublishStateChangedListener listener) { + PublishStateCallbackAdapter adapter = new PublishStateCallbackAdapter(executor, listener); + synchronized (mPublishStateCallbacks) { + mPublishStateCallbacks.put(listener, adapter); + } + return adapter; + } + + /** + * Remove the existing {@link OnPublishStateChangedListener}. + * @param listener The {@link OnPublishStateChangedListener} to remove from the collection. + * @return The wrapper class {@link PublishStateCallbackAdapter} associated with the + * {@link OnPublishStateChangedListener}. + */ + private PublishStateCallbackAdapter removePublishStateCallback( + @NonNull OnPublishStateChangedListener listener) { + synchronized (mPublishStateCallbacks) { + return mPublishStateCallbacks.remove(listener); + } + } + private IImsRcsController getIImsRcsController() { IBinder binder = TelephonyFrameworkInitializer .getTelephonyServiceManager() diff --git a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java new file mode 100644 index 000000000000..4435640e008c --- /dev/null +++ b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2020 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.aidl; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Uri; +import android.os.Binder; +import android.os.RemoteException; +import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.stub.CapabilityExchangeEventListener; +import android.util.Log; + +import java.util.List; + +/** + * The ICapabilityExchangeEventListener wrapper class to store the listener which is registered by + * the framework. This wrapper class also delivers the request to the framework when receive the + * request from the network. + * @hide + */ +public class CapabilityExchangeAidlWrapper implements CapabilityExchangeEventListener { + + private static final String LOG_TAG = "CapExchangeListener"; + + private final ICapabilityExchangeEventListener mListenerBinder; + + public CapabilityExchangeAidlWrapper(@Nullable ICapabilityExchangeEventListener listener) { + mListenerBinder = listener; + } + + /** + * Receives the request of publishing capabilities from the network and deliver this request + * to the framework via the registered capability exchange event listener. + */ + public void onRequestPublishCapabilities(int publishTriggerType) { + ICapabilityExchangeEventListener listener = mListenerBinder; + if (listener == null) { + return; + } + try { + listener.onRequestPublishCapabilities(publishTriggerType); + } catch (RemoteException e) { + Log.w(LOG_TAG, "request publish capabilities exception: " + e); + } + } + + /** + * Receives the unpublish notification and deliver this callback to the framework. + */ + public void onUnpublish() { + ICapabilityExchangeEventListener listener = mListenerBinder; + if (listener == null) { + return; + } + try { + listener.onUnpublish(); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Unpublish exception: " + e); + } + } + + /** + * Receives the callback of the remote capability request from the network and deliver this + * request to the framework. + */ + public void onRemoteCapabilityRequest(@NonNull Uri contactUri, + @NonNull List<String> remoteCapabilities, @NonNull OptionsRequestCallback callback) { + ICapabilityExchangeEventListener listener = mListenerBinder; + if (listener == null) { + return; + } + + IOptionsRequestCallback internalCallback = new IOptionsRequestCallback.Stub() { + @Override + public void respondToCapabilityRequest(RcsContactUceCapability ownCapabilities) { + final long callingIdentity = Binder.clearCallingIdentity(); + try { + callback.onRespondToCapabilityRequest(ownCapabilities); + } finally { + restoreCallingIdentity(callingIdentity); + } + } + @Override + public void respondToCapabilityRequestWithError(int code, String reason) { + final long callingIdentity = Binder.clearCallingIdentity(); + try { + callback.onRespondToCapabilityRequestWithError(code, reason); + } finally { + restoreCallingIdentity(callingIdentity); + } + } + }; + + try { + listener.onRemoteCapabilityRequest(contactUri, remoteCapabilities, internalCallback); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Remote capability request exception: " + e); + } + } +} diff --git a/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl b/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl index a4ffbef9fa84..078ac919b75e 100644 --- a/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl @@ -22,54 +22,15 @@ import android.telephony.ims.aidl.IOptionsRequestCallback; import java.util.List; /** - * Listener interface for the ImsService to use to notify the framework of UCE events. + * Listener interface for the ImsService to use to notify the framework of UCE + * events. + * + * See CapabilityExchangeEventListener for more information. * {@hide} */ oneway interface ICapabilityExchangeEventListener { - /** - * Trigger the framework to provide a capability update using - * {@link RcsCapabilityExchangeImplBase#publishCapabilities}. - * <p> - * This is typically used when trying to generate an initial PUBLISH for a new - * subscription to the network. The device will cache all presence publications - * after boot until this method is called the first time. - * @param publishTriggerType {@link StackPublishTriggerType} The reason for the - * capability update request. - * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is - * not currently connected to the framework. This can happen if the - * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the - * {@link RcsFeature} has not received the - * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare - * cases when the Telephony stack has crashed. - */ void onRequestPublishCapabilities(int publishTriggerType); - - /** - * Notify the framework that the device's capabilities have been unpublished from the network. - * - * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently - * connected to the framework. This can happen if the {@link RcsFeature} is not - * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the - * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the - * Telephony stack has crashed. - */ void onUnpublish(); - - /** - * Inform the framework of a query for this device's UCE capabilities. - * <p> - * The framework will respond via the - * {@link IOptionsRequestCallback#respondToCapabilityRequest} or - * {@link IOptionsRequestCallback#respondToCapabilityRequestWithError} method. - * @param contactUri The URI associated with the remote contact that is requesting capabilities. - * @param remoteCapabilities The remote contact's capability information. - * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently - * connected to the framework. This can happen if the {@link RcsFeature} is not - * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received - * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when - * the Telephony stack has crashed. - */ void onRemoteCapabilityRequest(in Uri contactUri, - in List<String> remoteCapabilities, - IOptionsRequestCallback cb); + in List<String> remoteCapabilities, IOptionsRequestCallback cb); } diff --git a/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl b/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl index d55670dd313b..d4d5301f38fa 100644 --- a/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl +++ b/telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl @@ -33,7 +33,6 @@ oneway interface IOptionsRequestCallback { /** * Respond to a remote capability request from the contact specified with the * specified error. - * @param contactUri A URI containing the remote contact. * @param code The SIP response code to respond with. * @param reason A non-null String containing the reason associated with the SIP code. */ diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index 96ca0225040f..8b26c3b27a3d 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -336,7 +336,7 @@ public abstract class ImsFeature { /** * @hide */ - public final void initialize(Context context, int slotId) { + public void initialize(Context context, int slotId) { mContext = context; mSlotId = slotId; } diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index cde7067e8bf3..22df921c4214 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -21,9 +21,11 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.content.Context; import android.net.Uri; import android.os.RemoteException; import android.telephony.ims.RcsUceAdapter; +import android.telephony.ims.aidl.CapabilityExchangeAidlWrapper; import android.telephony.ims.aidl.ICapabilityExchangeEventListener; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsRcsFeature; @@ -33,6 +35,7 @@ import android.telephony.ims.aidl.ISubscribeResponseCallback; import android.telephony.ims.aidl.RcsOptionsResponseAidlWrapper; import android.telephony.ims.aidl.RcsPublishResponseAidlWrapper; import android.telephony.ims.aidl.RcsSubscribeResponseAidlWrapper; +import android.telephony.ims.stub.CapabilityExchangeEventListener; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.RcsCapabilityExchangeImplBase; import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback; @@ -114,8 +117,10 @@ public class RcsFeature extends ImsFeature { @Override public void setCapabilityExchangeEventListener( @Nullable ICapabilityExchangeEventListener listener) throws RemoteException { - executeMethodAsync(() -> mReference.setCapabilityExchangeEventListener(listener), - "setCapabilityExchangeEventListener"); + CapabilityExchangeEventListener listenerWrapper = + new CapabilityExchangeAidlWrapper(listener); + executeMethodAsync(() -> mReference.setCapabilityExchangeEventListener( + mExecutor, listenerWrapper), "setCapabilityExchangeEventListener"); } @Override @@ -245,9 +250,10 @@ public class RcsFeature extends ImsFeature { } } + private final Executor mExecutor; private final RcsFeatureBinder mImsRcsBinder; private RcsCapabilityExchangeImplBase mCapabilityExchangeImpl; - private ICapabilityExchangeEventListener mCapExchangeEventListener; + private CapabilityExchangeEventListener mCapExchangeEventListener; /** * Create a new RcsFeature. @@ -255,26 +261,45 @@ public class RcsFeature extends ImsFeature { * Method stubs called from the framework will be called asynchronously. To specify the * {@link Executor} that the methods stubs will be called, use * {@link RcsFeature#RcsFeature(Executor)} instead. + * + * @deprecated Use {@link #RcsFeature(Executor)} to create the RcsFeature. */ + @Deprecated public RcsFeature() { super(); + mExecutor = Runnable::run; // Run on the Binder threads that call them. - mImsRcsBinder = new RcsFeatureBinder(this, Runnable::run); + mImsRcsBinder = new RcsFeatureBinder(this, mExecutor); } /** * Create a new RcsFeature using the Executor specified for methods being called by the * framework. - * @param executor The executor for the framework to use when making calls to this service. - * @hide + * @param executor The executor for the framework to use when executing the methods overridden + * by the implementation of RcsFeature. */ public RcsFeature(@NonNull Executor executor) { super(); if (executor == null) { throw new IllegalArgumentException("executor can not be null."); } + mExecutor = executor; // Run on the Binder thread by default. - mImsRcsBinder = new RcsFeatureBinder(this, executor); + mImsRcsBinder = new RcsFeatureBinder(this, mExecutor); + } + + /** + * Called when the RcsFeature is initialized. + * + * @param context The context that is used in the ImsService. + * @param slotId The slot ID associated with the RcsFeature. + * @hide + */ + @Override + public void initialize(Context context, int slotId) { + super.initialize(context, slotId); + // Notify that the RcsFeature is ready. + mExecutor.execute(() -> onFeatureReady()); } /** @@ -348,13 +373,26 @@ public class RcsFeature extends ImsFeature { * operation and the RcsFeature sets the status of the capability to true using * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. * - * @return An instance of {@link RcsCapabilityExchangeImplBase} that implements presence + * @param executor The executor for the framework to use when request RCS resquests to this + * service. + * @param listener A {@link CapabilityExchangeEventListener} to send the capability exchange + * event to the framework. + * @return An instance of {@link RcsCapabilityExchangeImplBase} that implements capability * exchange if it is supported by the device. - * @hide */ - public @NonNull RcsCapabilityExchangeImplBase createCapabilityExchangeImpl() { + public @NonNull RcsCapabilityExchangeImplBase createCapabilityExchangeImpl( + @NonNull Executor executor, @NonNull CapabilityExchangeEventListener listener) { // Base Implementation, override to implement functionality - return new RcsCapabilityExchangeImplBase(); + return new RcsCapabilityExchangeImplBase(executor); + } + + /** + * Remove the given CapabilityExchangeImplBase instance. + * @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be removed. + */ + public void removeCapabilityExchangeImpl( + @NonNull RcsCapabilityExchangeImplBase capExchangeImpl) { + // Override to implement the process of removing RcsCapabilityExchangeImplBase instance. } /**{@inheritDoc}*/ @@ -377,18 +415,58 @@ public class RcsFeature extends ImsFeature { return mImsRcsBinder; } - private void setCapabilityExchangeEventListener(ICapabilityExchangeEventListener listener) { - mCapExchangeEventListener = listener; - if (mCapExchangeEventListener != null) { - onFeatureReady(); + /** + * Set the capability exchange listener. + * @param executor The executor for the framework to use when request RCS requests to this + * service. + * @param listener A {@link CapabilityExchangeEventListener} to send the capability exchange + * event to the framework. + */ + private void setCapabilityExchangeEventListener(@NonNull Executor executor, + @Nullable CapabilityExchangeEventListener listener) { + synchronized (mLock) { + mCapExchangeEventListener = listener; + if (mCapExchangeEventListener != null) { + initRcsCapabilityExchangeImplBase(executor, mCapExchangeEventListener); + } else { + // Remove the RcsCapabilityExchangeImplBase instance when the capability exchange + // instance has been removed in the framework. + if (mCapabilityExchangeImpl != null) { + removeCapabilityExchangeImpl(mCapabilityExchangeImpl); + } + mCapabilityExchangeImpl = null; + } } } - private RcsCapabilityExchangeImplBase getCapabilityExchangeImplBaseInternal() { + /** + * Initialize the RcsCapabilityExchangeImplBase instance if the capability exchange instance + * has already been created in the framework. + * @param executor The executor for the framework to use when request RCS requests to this + * service. + * @param listener A {@link CapabilityExchangeEventListener} to send the capability exchange + * event to the framework. + */ + private void initRcsCapabilityExchangeImplBase(@NonNull Executor executor, + @NonNull CapabilityExchangeEventListener listener) { + synchronized (mLock) { + // Remove the original instance + if (mCapabilityExchangeImpl != null) { + removeCapabilityExchangeImpl(mCapabilityExchangeImpl); + } + mCapabilityExchangeImpl = createCapabilityExchangeImpl(executor, listener); + } + } + + /** + * @return the {@link RcsCapabilityExchangeImplBase} associated with the RcsFeature. + */ + private @NonNull RcsCapabilityExchangeImplBase getCapabilityExchangeImplBaseInternal() { synchronized (mLock) { + // The method should not be called if the instance of RcsCapabilityExchangeImplBase has + // not been created yet. if (mCapabilityExchangeImpl == null) { - mCapabilityExchangeImpl = createCapabilityExchangeImpl(); - mCapabilityExchangeImpl.setEventListener(mCapExchangeEventListener); + throw new IllegalStateException("Session is not available."); } return mCapabilityExchangeImpl; } diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java new file mode 100644 index 000000000000..d2cb9761a028 --- /dev/null +++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020 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.stub; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.net.Uri; +import android.telephony.ims.ImsException; +import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.RcsUceAdapter; +import android.telephony.ims.feature.ImsFeature; +import android.telephony.ims.feature.RcsFeature; + +import java.util.List; + +/** + * The interface of the capabilities event listener for ImsService to notify the framework of the + * UCE request and status updated. + * @hide + */ +@SystemApi +public interface CapabilityExchangeEventListener { + /** + * Interface used by the framework to respond to OPTIONS requests. + * @hide + */ + interface OptionsRequestCallback { + /** + * Respond to a remote capability request from the contact specified with the + * capabilities of this device. + * @param ownCapabilities The capabilities of this device. + */ + void onRespondToCapabilityRequest(@NonNull RcsContactUceCapability ownCapabilities); + + /** + * Respond to a remote capability request from the contact specified with the + * specified error. + * @param code The SIP response code to respond with. + * @param reason A non-null String containing the reason associated with the SIP code. + */ + void onRespondToCapabilityRequestWithError(int code, @NonNull String reason); + } + + /** + * Trigger the framework to provide a capability update using + * {@link RcsCapabilityExchangeImplBase#publishCapabilities}. + * <p> + * This is typically used when trying to generate an initial PUBLISH for a new subscription to + * the network. The device will cache all presence publications after boot until this method is + * called the first time. + * @param publishTriggerType {@link RcsUceAdapter#StackPublishTriggerType} The reason for the + * capability update request. + * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not currently + * connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the + * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the + * Telephony stack has crashed. + */ + void onRequestPublishCapabilities( + @RcsUceAdapter.StackPublishTriggerType int publishTriggerType) throws ImsException; + + /** + * Notify the framework that the device's capabilities have been unpublished + * from the network. + * + * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not currently + * connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the + * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the + * Telephony stack has crashed. + */ + void onUnpublish() throws ImsException; + + /** + * Inform the framework of a query for this device's UCE capabilities. + * <p> + * The framework will respond via the + * {@link OptionsRequestCallback#onRespondToCapabilityRequest} or + * {@link OptionsRequestCallback#onRespondToCapabilityRequestWithError} + * @param contactUri The URI associated with the remote contact that is + * requesting capabilities. + * @param remoteCapabilities The remote contact's capability information. + * @param callback The callback of this request which is sent from the remote user. + * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not + * currently connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received + * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare + * cases when the Telephony stack has crashed. + * @hide + */ + void onRemoteCapabilityRequest(@NonNull Uri contactUri, + @NonNull List<String> remoteCapabilities, + @NonNull OptionsRequestCallback callback) throws ImsException; +} diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java index 3a0fb6edb2fb..c84e23c38e97 100644 --- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java @@ -20,20 +20,28 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.net.Uri; import android.telephony.ims.ImsException; -import android.telephony.ims.aidl.ICapabilityExchangeEventListener; +import android.telephony.ims.feature.ImsFeature; +import android.telephony.ims.feature.RcsFeature; import android.util.Log; import android.util.Pair; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; +import java.util.concurrent.Executor; /** - * Base class for different types of Capability exchange. + * Extend this base class to implement RCS User Capability Exchange (UCE) for the AOSP platform + * using the vendor ImsService. + * <p> + * See RCC.07 for more details on UCE as well as how UCE should be implemented. * @hide */ +@SystemApi public class RcsCapabilityExchangeImplBase { private static final String LOG_TAG = "RcsCapExchangeImplBase"; @@ -70,13 +78,11 @@ public class RcsCapabilityExchangeImplBase { /** * Network connection is lost. - * @hide */ public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 6; /** * Requested feature/resource is not supported. - * @hide */ public static final int COMMAND_CODE_NOT_SUPPORTED = 7; @@ -117,7 +123,8 @@ public class RcsCapabilityExchangeImplBase { */ public interface PublishResponseCallback { /** - * Notify the framework that the command associated with this callback has failed. + * Notify the framework that the command associated with the + * {@link #publishCapabilities(String, PublishResponseCallback)} has failed. * * @param code The reason why the associated command has failed. * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is @@ -128,15 +135,15 @@ public class RcsCapabilityExchangeImplBase { */ void onCommandError(@CommandCode int code) throws ImsException; - /** * Provide the framework with a subsequent network response update to * {@link #publishCapabilities(String, PublishResponseCallback)}. * * @param code The SIP response code sent from the network for the operation * token specified. - * @param reason The optional reason response from the network. If the network - * provided no reason with the code, the string should be empty. + * @param reason The optional reason response from the network. If there is a reason header + * included in the response, that should take precedence over the reason provided in the + * status line. If the network provided no reason with the code, the string should be empty. * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is * not currently connected to the framework. This can happen if the {@link RcsFeature} * is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received @@ -149,6 +156,7 @@ public class RcsCapabilityExchangeImplBase { /** * Interface used by the framework to respond to OPTIONS requests. + * @hide */ public interface OptionsResponseCallback { /** @@ -171,7 +179,7 @@ public class RcsCapabilityExchangeImplBase { * If none was sent, this should be an empty string. * @param theirCaps the contact's UCE capabilities associated with the * capability request. - * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not + * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not * currently connected to the framework. This can happen if the * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the * {@link RcsFeature} has not received the @@ -184,6 +192,7 @@ public class RcsCapabilityExchangeImplBase { /** * Interface used by the framework to receive the response of the subscribe request. + * @hide */ public interface SubscribeResponseCallback { /** @@ -219,17 +228,16 @@ public class RcsCapabilityExchangeImplBase { /** * Provides the framework with latest XML PIDF documents included in the * network response for the requested contacts' capabilities requested by the - * Framework using {@link #requestCapabilities(List, int)}. This should be + * Framework using {@link #requestCapabilities(List, int)}. This should be * called every time a new NOTIFY event is received with new capability * information. * * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is - * not currently - * connected to the framework. This can happen if the {@link RcsFeature} is not - * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received - * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in - * rare cases when the - * Telephony stack has crashed. + * not currently connected to the framework. + * This can happen if the {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the + * {@link RcsFeature} {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not + * received the {@link ImsFeature#onFeatureReady()} callback. This may also happen in + * rare cases when the Telephony stack has crashed. */ void onNotifyCapabilitiesUpdate(@NonNull List<String> pidfXmls) throws ImsException; @@ -250,24 +258,21 @@ public class RcsCapabilityExchangeImplBase { * This allows the framework to know that there will no longer be any * capability updates for the requested operationToken. */ - void onTerminated(String reason, long retryAfterMilliseconds) throws ImsException; + void onTerminated(@NonNull String reason, long retryAfterMilliseconds) throws ImsException; } - - private ICapabilityExchangeEventListener mListener; + private final Executor mBinderExecutor; /** - * Set the event listener to send the request to Framework. + * Create a new RcsCapabilityExchangeImplBase instance. + * + * @param executor The executor that remote calls from the framework will be called on. */ - public void setEventListener(ICapabilityExchangeEventListener listener) { - mListener = listener; - } - - /** - * Get the event listener. - */ - public ICapabilityExchangeEventListener getEventListener() { - return mListener; + public RcsCapabilityExchangeImplBase(@NonNull Executor executor) { + if (executor == null) { + throw new IllegalArgumentException("executor must not be null"); + } + mBinderExecutor = executor; } /** @@ -284,7 +289,10 @@ public class RcsCapabilityExchangeImplBase { * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE * capabilities for. * @param cb The callback of the subscribe request. + * @hide */ + // executor used is defined in the constructor. + @SuppressLint("ExecutorRegistration") public void subscribeForCapabilities(@NonNull List<Uri> uris, @NonNull SubscribeResponseCallback cb) { // Stub - to be implemented by service @@ -300,11 +308,13 @@ public class RcsCapabilityExchangeImplBase { * The capabilities of this device have been updated and should be published to the network. * <p> * If this operation succeeds, network response updates should be sent to the framework using - * {@link #onNetworkResponse(int, String)}. + * {@link PublishResponseCallback#onNetworkResponse(int, String)}. * @param pidfXml The XML PIDF document containing the capabilities of this device to be sent * to the carrier’s presence server. * @param cb The callback of the publish request */ + // executor used is defined in the constructor. + @SuppressLint("ExecutorRegistration") public void publishCapabilities(@NonNull String pidfXml, @NonNull PublishResponseCallback cb) { // Stub - to be implemented by service Log.w(LOG_TAG, "publishCapabilities called with no implementation."); @@ -324,7 +334,10 @@ public class RcsCapabilityExchangeImplBase { * @param contactUri The URI of the remote user that we wish to get the capabilities of. * @param myCapabilities The capabilities of this device to send to the remote user. * @param callback The callback of this request which is sent from the remote user. + * @hide */ + // executor used is defined in the constructor. + @SuppressLint("ExecutorRegistration") public void sendOptionsCapabilityRequest(@NonNull Uri contactUri, @NonNull List<String> myCapabilities, @NonNull OptionsResponseCallback callback) { // Stub - to be implemented by service |