diff --git a/Android.bp b/Android.bp index 8e3ae83a1aa94..8ea03062beba9 100644 --- a/Android.bp +++ b/Android.bp @@ -560,6 +560,7 @@ java_defaults { "telephony/java/android/telephony/ims/aidl/IImsServiceControllerListener.aidl", "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl", "telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl", + "telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl", "telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl", "telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl", "telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl", diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java index 8e1324b3be0bf..6187e67a6acb6 100644 --- a/telephony/java/android/telephony/ims/ImsException.java +++ b/telephony/java/android/telephony/ims/ImsException.java @@ -39,11 +39,11 @@ public final class ImsException extends Exception { */ public static final int CODE_ERROR_UNSPECIFIED = 0; /** - * The operation has failed because there is no {@link ImsService} available to service it. This - * may be due to an {@link ImsService} crash or other illegal state. + * The operation has failed because there is no remote process available to service it. This + * may be due to a process crash or other illegal state. *
* This is a temporary error and the operation may be retried until the connection to the
- * {@link ImsService} is restored.
+ * remote process is restored.
*/
public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1;
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
index 691cfba9a28ca..4b98b79f10952 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
@@ -16,10 +16,38 @@
package android.telephony.ims.aidl;
+import android.net.Uri;
+import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IRcsFeatureListener;
+import android.telephony.ims.feature.CapabilityChangeRequest;
+
+import java.util.List;
+
/**
* See RcsFeature for more information.
* {@hide}
*/
interface IImsRcsFeature {
- //Empty Default Implementation
+ // Not oneway because we need to verify this completes before doing anything else.
+ void setListener(IRcsFeatureListener listener);
+ int queryCapabilityStatus();
+ // Inherited from ImsFeature
+ int getFeatureState();
+ oneway void addCapabilityCallback(IImsCapabilityCallback c);
+ oneway void removeCapabilityCallback(IImsCapabilityCallback c);
+ oneway void changeCapabilitiesConfiguration(in CapabilityChangeRequest r,
+ IImsCapabilityCallback c);
+ oneway void queryCapabilityConfiguration(int capability, int radioTech,
+ IImsCapabilityCallback c);
+ // RcsPresenceExchangeImplBase specific api
+ oneway void requestCapabilities(in List
+ * 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.
+ */
+ public RcsFeature() {
+ super();
+ // Run on the Binder threads that call them.
+ mImsRcsBinder = new RcsFeatureBinder(this, Runnable::run);
+ }
+
+ /**
+ * 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
+ */
+ public RcsFeature(@NonNull Executor executor) {
+ super();
+ if (executor == null) {
+ throw new IllegalArgumentException("executor can not be null.");
+ }
+ // Run on the Binder thread by default.
+ mImsRcsBinder = new RcsFeatureBinder(this, executor);
+ }
+
/**
* Query the current {@link RcsImsCapabilities} status set by the RcsFeature. If a capability is
* set, the {@link RcsFeature} has brought up the capability and is ready for framework
@@ -111,7 +290,7 @@ public class RcsFeature extends ImsFeature {
*/
@Override
public final RcsImsCapabilities queryCapabilityStatus() {
- throw new UnsupportedOperationException();
+ return new RcsImsCapabilities(super.queryCapabilityStatus());
}
/**
@@ -120,8 +299,11 @@ public class RcsFeature extends ImsFeature {
* Call {@link #queryCapabilityStatus()} to return the current capability status.
* @hide
*/
- public final void notifyCapabilitiesStatusChanged(RcsImsCapabilities c) {
- throw new UnsupportedOperationException();
+ public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities c) {
+ if (c == null) {
+ throw new IllegalArgumentException("RcsImsCapabilities must be non-null!");
+ }
+ super.notifyCapabilitiesStatusChanged(c);
}
/**
@@ -133,8 +315,10 @@ public class RcsFeature extends ImsFeature {
* @hide
*/
public boolean queryCapabilityConfiguration(
- @RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
- throw new UnsupportedOperationException();
+ @RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+ @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
+ // Base Implementation - Override to provide functionality
+ return false;
}
/**
* Called from the framework when the {@link RcsImsCapabilities} that have been configured for
@@ -155,7 +339,7 @@ public class RcsFeature extends ImsFeature {
@Override
public void changeEnabledCapabilities(CapabilityChangeRequest request,
CapabilityCallbackProxy c) {
- throw new UnsupportedOperationException();
+ // Base Implementation - Override to provide functionality
}
/**
@@ -192,13 +376,6 @@ public class RcsFeature extends ImsFeature {
return new RcsPresenceExchangeImplBase();
}
- /**
- * Construct a new {@link RcsFeature} instance.
- */
- public RcsFeature() {
- super();
- }
-
/**{@inheritDoc}*/
@Override
public void onFeatureRemoved() {
@@ -218,4 +395,40 @@ public class RcsFeature extends ImsFeature {
public final IImsRcsFeature getBinder() {
return mImsRcsBinder;
}
+
+ /**@hide*/
+ public IRcsFeatureListener getListener() {
+ synchronized (mLock) {
+ return mListenerBinder;
+ }
+ }
+
+ private void setListener(IRcsFeatureListener listener) {
+ synchronized (mLock) {
+ mListenerBinder = listener;
+ if (mListenerBinder != null) {
+ onFeatureReady();
+ }
+ }
+ }
+
+ private RcsPresenceExchangeImplBase getPresenceExchangeInternal() {
+ synchronized (mLock) {
+ if (mPresExchange == null) {
+ mPresExchange = getPresenceExchangeImpl();
+ mPresExchange.initialize(this);
+ }
+ return mPresExchange;
+ }
+ }
+
+ private RcsSipOptionsImplBase getOptionsExchangeInternal() {
+ synchronized (mLock) {
+ if (mSipOptions == null) {
+ mSipOptions = getOptionsExchangeImpl();
+ mSipOptions.initialize(this);
+ }
+ return mSipOptions;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
index 289fd4c8a1343..fda295a271118 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
@@ -17,6 +17,11 @@
package android.telephony.ims.stub;
import android.annotation.IntDef;
+import android.os.RemoteException;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.aidl.IRcsFeatureListener;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.RcsFeature;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -72,6 +77,24 @@ public class RcsCapabilityExchange {
})
public @interface CommandCode {}
+
+ private RcsFeature mFeature;
+
+ /** @hide */
+ public final void initialize(RcsFeature feature) {
+ mFeature = feature;
+ }
+
+ /** @hide */
+ protected final IRcsFeatureListener getListener() throws ImsException {
+ IRcsFeatureListener listener = mFeature.getListener();
+ if (listener == null) {
+ throw new ImsException("Connection to Framework has not been established, wait for "
+ + "onFeatureReady().", ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ return mFeature.getListener();
+ }
+
/**
* Provides the framework with an update as to whether or not a command completed successfully
* locally. This includes capabilities requests and updates from the network. If it does not
@@ -82,8 +105,18 @@ public class RcsCapabilityExchange {
* @param code The result of the pending command. If {@link #COMMAND_CODE_SUCCESS}, further
* updates will be sent for this command using the associated operationToken.
* @param operationToken the token associated with the pending command.
+ * @throws ImsException If this {@link RcsCapabilityExchange} 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.
*/
- public final void onCommandUpdate(@CommandCode int code, int operationToken) {
- throw new UnsupportedOperationException();
+ public final void onCommandUpdate(@CommandCode int code, int operationToken)
+ throws ImsException {
+ try {
+ getListener().onCommandUpdate(code, operationToken);
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
index 44024703042d6..055fca57a6287 100644
--- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
@@ -19,7 +19,11 @@ package android.telephony.ims.stub;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.ims.ImsException;
import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -113,54 +117,95 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
* Provide the framework with a subsequent network response update to
* {@link #updateCapabilities(RcsContactUceCapability, int)} and
* {@link #requestCapabilities(List, int)} operations.
+ *
* @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 operationToken The token associated with the operation this service is providing a
* response for.
+ * @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.
*/
public final void onNetworkResponse(@PresenceResponseCode int code, @NonNull String reason,
- int operationToken) {
- throw new UnsupportedOperationException();
+ int operationToken) throws ImsException {
+ try {
+ getListener().onNetworkResponse(code, reason, operationToken);
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
* Provides the framework with the requested contacts’ capabilities requested by the framework
- * using {@link #requestCapabilities(List, int)} .
+ * using {@link #requestCapabilities(List, int)}.
+ *
+ * @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.
*/
public final void onCapabilityRequestResponse(@NonNull List
- * The device will cache all presence publications after boot until this method is called once.
+ * 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 once.
+ * @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.
*/
- public final void onNotifyUpdateCapabilites() {
- throw new UnsupportedOperationException();
+ public final void onNotifyUpdateCapabilites() throws ImsException {
+ try {
+ getListener().onNotifyUpdateCapabilities();
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
* 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.
*/
- public final void onUnpublish() {
- throw new UnsupportedOperationException();
+ public final void onUnpublish() throws ImsException {
+ try {
+ getListener().onUnpublish();
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
- * The user capabilities of one or multiple contacts have been requested.
+ * The user capabilities of one or multiple contacts have been requested by the framework.
*
- * This must be followed up with one call to {@link #onCommandUpdate(int, int)} with an update
- * as to whether or not the command completed as well as subsequent network
- * updates using {@link #onNetworkResponse(int, String, int)}. When the operation is completed,
- * {@link #onCapabilityRequestResponse(List, int)} should be called with
- * the presence information for the contacts specified.
- * @param uris A {@link List} of the URIs that the framework is requesting the UCE capabilities
- * for.
+ * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to
+ * indicate whether or not this operation succeeded. If this operation succeeds, network
+ * response updates should be sent to the framework using
+ * {@link #onNetworkResponse(int, String, int)}. When the operation is completed,
+ * {@link #onCapabilityRequestResponse(List, int)} should be called with the presence
+ * information for the contacts specified.
+ * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
+ * capabilities for.
* @param operationToken The token associated with this operation. Updates to this request using
* {@link #onCommandUpdate(int, int)}, {@link #onNetworkResponse(int, String, int)}, and
* {@link #onCapabilityRequestResponse(List, int)} must use the same operation token
@@ -169,14 +214,20 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
public void requestCapabilities(@NonNull List
+ * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to
+ * indicate whether or not this operation succeeded. If this operation succeeds, network
+ * response updates should be sent to the framework using
+ * {@link #onNetworkResponse(int, String, int)}.
* @param capabilities The capabilities for this device.
* @param operationToken The token associated with this operation. Any subsequent
* {@link #onCommandUpdate(int, int)} or {@link #onNetworkResponse(int, String, int)}
@@ -186,6 +237,10 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "updateCapabilities called with no implementation.");
- onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ try {
+ getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
+ } catch (RemoteException | ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
}
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
index 3343074ea52cc..1c68fc08529e7 100644
--- a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
@@ -20,7 +20,11 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.ims.ImsException;
import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -87,10 +91,19 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
* @param info the contact's UCE capabilities associated with the capability request.
* @param operationToken The token associated with the original capability request, set by
* {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
+ * @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.
*/
public final void onCapabilityRequestResponse(@SipResponseCode int code, @NonNull String reason,
- @Nullable RcsContactUceCapability info, int operationToken) {
- throw new UnsupportedOperationException();
+ @Nullable RcsContactUceCapability info, int operationToken) throws ImsException {
+ try {
+ getListener().onCapabilityRequestResponseOptions(code, reason, info, operationToken);
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
@@ -104,10 +117,19 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
* @param operationToken An unique operation token that you have generated that will be returned
* by the framework in
* {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)}.
+ * @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.
*/
public final void onRemoteCapabilityRequest(@NonNull Uri contactUri,
- @NonNull RcsContactUceCapability remoteInfo, int operationToken) {
- throw new UnsupportedOperationException();
+ @NonNull RcsContactUceCapability remoteInfo, int operationToken) throws ImsException {
+ try {
+ getListener().onRemoteCapabilityRequest(contactUri, remoteInfo, operationToken);
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
}
/**
@@ -127,7 +149,11 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
@NonNull RcsContactUceCapability capabilities, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "sendCapabilityRequest called with no implementation.");
- onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ try {
+ getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
+ } catch (RemoteException | ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
}
/**
@@ -145,7 +171,11 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
@NonNull RcsContactUceCapability ownCapabilities, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "respondToCapabilityRequest called with no implementation.");
- onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ try {
+ getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
+ } catch (RemoteException | ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
}
/**
@@ -164,6 +194,10 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
@SipResponseCode int code, @NonNull String reason, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "respondToCapabiltyRequestWithError called with no implementation.");
- onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ try {
+ getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
+ } catch (RemoteException | ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
}
}