summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author James Lin <jamescflin@google.com> 2021-01-13 00:33:57 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2021-01-13 00:33:57 +0000
commit5b51530d0d960ee21a26ec4460abfe49b3657e5a (patch)
tree5315851831d2bba8bb2456736cfbc9f9e038ae23
parentbbd9fb5c27045558af4368eae7edad2e83152307 (diff)
parent50c18c12c66f141b3574a473e2bf199d7a460438 (diff)
Merge "[RCS UCE] Expose the RCS UCE publishing device's capabilities APIs"
-rw-r--r--core/api/system-current.txt56
-rw-r--r--telephony/java/android/telephony/ims/RcsContactPresenceTuple.java26
-rw-r--r--telephony/java/android/telephony/ims/RcsContactUceCapability.java17
-rw-r--r--telephony/java/android/telephony/ims/RcsUceAdapter.java224
-rw-r--r--telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java115
-rw-r--r--telephony/java/android/telephony/ims/aidl/ICapabilityExchangeEventListener.aidl49
-rw-r--r--telephony/java/android/telephony/ims/aidl/IOptionsRequestCallback.aidl1
-rw-r--r--telephony/java/android/telephony/ims/feature/ImsFeature.java2
-rw-r--r--telephony/java/android/telephony/ims/feature/RcsFeature.java114
-rw-r--r--telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java108
-rw-r--r--telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java73
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