| /* |
| * 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.IntDef; |
| import android.annotation.IntRange; |
| import android.annotation.NonNull; |
| import android.annotation.SuppressLint; |
| import android.annotation.SystemApi; |
| import android.net.Uri; |
| import android.telephony.ims.ImsException; |
| import android.telephony.ims.RcsUceAdapter; |
| import android.telephony.ims.SipDetails; |
| import android.telephony.ims.feature.ImsFeature; |
| import android.telephony.ims.feature.RcsFeature; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.util.Pair; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.concurrent.Executor; |
| |
| /** |
| * 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"; |
| |
| /** |
| * Service is unknown. |
| */ |
| public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; |
| |
| /** |
| * The command failed with an unknown error. |
| */ |
| public static final int COMMAND_CODE_GENERIC_FAILURE = 1; |
| |
| /** |
| * Invalid parameter(s). |
| */ |
| public static final int COMMAND_CODE_INVALID_PARAM = 2; |
| |
| /** |
| * Fetch error. |
| */ |
| public static final int COMMAND_CODE_FETCH_ERROR = 3; |
| |
| /** |
| * Request timed out. |
| */ |
| public static final int COMMAND_CODE_REQUEST_TIMEOUT = 4; |
| |
| /** |
| * Failure due to insufficient memory available. |
| */ |
| public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 5; |
| |
| /** |
| * Network connection is lost. |
| */ |
| public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 6; |
| |
| /** |
| * Requested feature/resource is not supported. |
| */ |
| public static final int COMMAND_CODE_NOT_SUPPORTED = 7; |
| |
| /** |
| * Contact or resource is not found. |
| */ |
| public static final int COMMAND_CODE_NOT_FOUND = 8; |
| |
| /** |
| * Service is not available. |
| */ |
| public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 9; |
| |
| /** |
| * Command resulted in no change in state, ignoring. |
| */ |
| public static final int COMMAND_CODE_NO_CHANGE = 10; |
| |
| /**@hide*/ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef(prefix = "COMMAND_CODE_", value = { |
| COMMAND_CODE_SERVICE_UNKNOWN, |
| COMMAND_CODE_GENERIC_FAILURE, |
| COMMAND_CODE_INVALID_PARAM, |
| COMMAND_CODE_FETCH_ERROR, |
| COMMAND_CODE_REQUEST_TIMEOUT, |
| COMMAND_CODE_INSUFFICIENT_MEMORY, |
| COMMAND_CODE_LOST_NETWORK_CONNECTION, |
| COMMAND_CODE_NOT_SUPPORTED, |
| COMMAND_CODE_NOT_FOUND, |
| COMMAND_CODE_SERVICE_UNAVAILABLE, |
| COMMAND_CODE_NO_CHANGE |
| }) |
| public @interface CommandCode {} |
| |
| /** |
| * Interface used by the framework to receive the response of the publish request. |
| */ |
| public interface PublishResponseCallback { |
| /** |
| * 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 |
| * 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 onCommandError(@CommandCode int code) throws ImsException; |
| |
| /** |
| * Provide the framework with a subsequent network response update to |
| * {@link #publishCapabilities(String, PublishResponseCallback)}. |
| * |
| * If this network response also contains a “Reason” header, then the |
| * {@link #onNetworkResponse(int, String, int, String)} method should be used instead. |
| * |
| * @param sipCode The SIP response code sent from the network for the operation |
| * token specified. |
| * @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 sip 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 |
| * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases |
| * when the Telephony stack has crashed. |
| * |
| * @deprecated Replaced sip information with the newly added |
| * {@link #onNetworkResponse(SipDetails)}. |
| */ |
| @Deprecated |
| void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, |
| @NonNull String reason) throws ImsException; |
| |
| /** |
| * Provide the framework with a subsequent network response update to |
| * {@link #publishCapabilities(String, PublishResponseCallback)} that also |
| * includes a reason provided in the “reason” header. See RFC3326 for more |
| * information. |
| * |
| * @param sipCode The SIP response code sent from the network. |
| * @param reasonPhrase The optional reason response from the network. If the |
| * network provided no reason with the sip code, the string should be empty. |
| * @param reasonHeaderCause The “cause” parameter of the “reason” header |
| * included in the SIP message. |
| * @param reasonHeaderText The “text” parameter of the “reason” header |
| * included in the SIP message. |
| * @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. |
| * |
| * @deprecated Replaced sip information with the newly added |
| * {@link #onNetworkResponse(SipDetails)}. |
| */ |
| @Deprecated |
| void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, |
| @NonNull String reasonPhrase, |
| @IntRange(from = 100, to = 699) int reasonHeaderCause, |
| @NonNull String reasonHeaderText) throws ImsException; |
| |
| /** |
| * Provide the framework with a subsequent network response update to |
| * {@link #publishCapabilities(String, PublishResponseCallback)}. |
| * |
| * @param details The SIP information received in response to a publish operation. |
| * @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. |
| */ |
| default void onNetworkResponse(@NonNull SipDetails details) throws ImsException { |
| if (TextUtils.isEmpty(details.getReasonHeaderText())) { |
| onNetworkResponse(details.getResponseCode(), details.getResponsePhrase()); |
| } else { |
| onNetworkResponse(details.getResponseCode(), details.getResponsePhrase(), |
| details.getReasonHeaderCause(), details.getReasonHeaderText()); |
| } |
| } |
| } |
| |
| /** |
| * Interface used by the framework to respond to OPTIONS requests. |
| */ |
| public interface OptionsResponseCallback { |
| /** |
| * Notify the framework that the command associated with this callback has failed. |
| * |
| * @param code The reason why the associated command has failed. |
| * @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 onCommandError(@CommandCode int code) throws ImsException; |
| |
| /** |
| * Send the response of a SIP OPTIONS capability exchange to the framework. |
| * @param sipCode The SIP response code that was sent by the network in response |
| * to the request sent by {@link #sendOptionsCapabilityRequest}. |
| * @param reason The optional SIP response reason sent by the network. |
| * 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 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 onNetworkResponse(int sipCode, @NonNull String reason, |
| @NonNull List<String> theirCaps) throws ImsException; |
| } |
| |
| /** |
| * Interface used by the framework to receive the response of the subscribe request. |
| */ |
| public interface SubscribeResponseCallback { |
| /** |
| * Notify the framework that the command associated with this callback has failed. |
| * <p> |
| * Must only be called when there was an error generating a SUBSCRIBE request due to an |
| * IMS stack error. This is a terminating event, so no other callback event will be |
| * expected after this callback. |
| * |
| * @param code The reason why the associated command has failed. |
| * @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 onCommandError(@CommandCode int code) throws ImsException; |
| |
| /** |
| * Notify the framework of the response to the SUBSCRIBE request from |
| * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)}. |
| * <p> |
| * If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the |
| * framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate}, |
| * {@link #onResourceTerminated}, and {@link #onTerminated} as required for the |
| * subsequent NOTIFY responses to the subscription. |
| * |
| * If this network response also contains a “Reason” header, then the |
| * {@link #onNetworkResponse(int, String, int, String)} method should be used instead. |
| * |
| * @param sipCode 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 sip 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 the {@link ImsFeature#onFeatureReady()} callback. |
| * This may also happen in rare cases when the Telephony stack has crashed. |
| * |
| * @deprecated Replaced sip information with the newly added |
| * {@link #onNetworkResponse(SipDetails)}. |
| */ |
| @Deprecated |
| void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, |
| @NonNull String reason) throws ImsException; |
| |
| /** |
| * Notify the framework of the response to the SUBSCRIBE request from |
| * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)} that also |
| * includes a reason provided in the “reason” header. See RFC3326 for more |
| * information. |
| * |
| * @param sipCode The SIP response code sent from the network, |
| * @param reasonPhrase The optional reason response from the network. If the |
| * network provided no reason with the sip code, the string should be empty. |
| * @param reasonHeaderCause The “cause” parameter of the “reason” header |
| * included in the SIP message. |
| * @param reasonHeaderText The “text” parameter of the “reason” header |
| * included in the SIP message. |
| * @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. |
| * |
| * @deprecated Replaced sip information with the newly added |
| * {@link #onNetworkResponse(SipDetails)}. |
| */ |
| @Deprecated |
| void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, |
| @NonNull String reasonPhrase, |
| @IntRange(from = 100, to = 699) int reasonHeaderCause, |
| @NonNull String reasonHeaderText) throws ImsException; |
| |
| /** |
| * Notify the framework of the response to the SUBSCRIBE request from |
| * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)}. |
| * <p> |
| * If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the |
| * framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate}, |
| * {@link #onResourceTerminated}, and {@link #onTerminated} as required for the |
| * subsequent NOTIFY responses to the subscription. |
| * |
| * @param details The SIP information related to this 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. |
| */ |
| default void onNetworkResponse(@NonNull SipDetails details) throws ImsException { |
| if (TextUtils.isEmpty(details.getReasonHeaderText())) { |
| onNetworkResponse(details.getResponseCode(), details.getResponsePhrase()); |
| } else { |
| onNetworkResponse(details.getResponseCode(), details.getResponsePhrase(), |
| details.getReasonHeaderCause(), details.getReasonHeaderText()); |
| } |
| }; |
| |
| /** |
| * Notify the framework of the latest XML PIDF documents included in the network response |
| * for the requested contacts' capabilities requested by the Framework using |
| * {@link RcsUceAdapter#requestCapabilities(List, Executor, |
| * RcsUceAdapter.CapabilitiesCallback)}. |
| * <p> |
| * The expected format for the PIDF XML is defined in RFC3861. Each XML document must be a |
| * "application/pidf+xml" object and start with a root <presence> element. For NOTIFY |
| * responses that contain RLMI information and potentially multiple PIDF XMLs, each |
| * PIDF XML should be separated and added as a separate item in the List. This should be |
| * called every time a new NOTIFY event is received with new capability information. |
| * |
| * @param pidfXmls The list of the PIDF XML data for the contact URIs that it subscribed |
| * for. |
| * @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} {@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; |
| |
| /** |
| * Notify the framework that a resource in the RLMI XML contained in the NOTIFY response |
| * for the ongoing SUBSCRIBE dialog has been terminated. |
| * <p> |
| * This will be used to notify the framework that a contact URI that the IMS stack has |
| * subscribed to on the Resource List Server has been terminated as well as the reason why. |
| * Usually this means that there will not be any capability information for the contact URI |
| * that they subscribed for. See RFC 4662 for more information. |
| * |
| * @param uriTerminatedReason The contact URIs which have been terminated. Each pair in the |
| * list is the contact URI and its terminated reason. |
| * @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} {@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 onResourceTerminated( |
| @NonNull List<Pair<Uri, String>> uriTerminatedReason) throws ImsException; |
| |
| /** |
| * The subscription associated with a previous |
| * {@link RcsUceAdapter#requestCapabilities(List, Executor, |
| * RcsUceAdapter.CapabilitiesCallback)} |
| * operation has been terminated. This will mostly be due to the network sending a final |
| * NOTIFY response due to the subscription expiring, but this may also happen due to a |
| * network error. |
| * |
| * @param reason The reason for the request being unable to process. |
| * @param retryAfterMilliseconds The time in milliseconds the requesting application should |
| * wait before retrying, if non-zero. |
| * @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} {@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 onTerminated(@NonNull String reason, long retryAfterMilliseconds) throws ImsException; |
| } |
| |
| /** |
| * Create a new RcsCapabilityExchangeImplBase instance. |
| */ |
| public RcsCapabilityExchangeImplBase() { |
| } |
| |
| /** |
| * The user capabilities of one or multiple contacts have been requested by the framework. |
| * <p> |
| * The implementer must follow up this call with an |
| * {@link SubscribeResponseCallback#onCommandError} call to indicate this operation has failed. |
| * The response from the network to the SUBSCRIBE request must be sent back to the framework |
| * using {@link SubscribeResponseCallback#onNetworkResponse(int, String)}. |
| * As NOTIFY requests come in from the network, the requested contact’s capabilities should be |
| * sent back to the framework using |
| * {@link SubscribeResponseCallback#onNotifyCapabilitiesUpdate(List<String>}) and |
| * {@link SubscribeResponseCallback#onResourceTerminated(List<Pair<Uri, String>>)} |
| * should be called with the presence information for the contacts specified. |
| * <p> |
| * Once the subscription is terminated, |
| * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the |
| * framework to finish listening for NOTIFY responses. |
| * |
| * @param uris A {@link Collection} of the {@link Uri}s that the framework is requesting the |
| * UCE capabilities for. |
| * @param cb The callback of the subscribe request. |
| */ |
| // executor used is defined in the constructor. |
| @SuppressLint("ExecutorRegistration") |
| public void subscribeForCapabilities(@NonNull Collection<Uri> uris, |
| @NonNull SubscribeResponseCallback cb) { |
| // Stub - to be implemented by service |
| Log.w(LOG_TAG, "subscribeForCapabilities called with no implementation."); |
| try { |
| cb.onCommandError(COMMAND_CODE_NOT_SUPPORTED); |
| } catch (ImsException e) { |
| // Do not do anything, this is a stub implementation. |
| } |
| } |
| |
| /** |
| * The capabilities of this device have been updated and should be published to the network. |
| * <p> |
| * If this operation succeeds, network response updates should be sent to the framework using |
| * {@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."); |
| try { |
| cb.onCommandError(COMMAND_CODE_NOT_SUPPORTED); |
| } catch (ImsException e) { |
| // Do not do anything, this is a stub implementation. |
| } |
| } |
| |
| /** |
| * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism |
| * in order to receive the capabilities of the remote user in response. |
| * <p> |
| * The implementer must use {@link OptionsResponseCallback} to send the response of |
| * this query from the network back to the framework. |
| * @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. |
| */ |
| // executor used is defined in the constructor. |
| @SuppressLint("ExecutorRegistration") |
| public void sendOptionsCapabilityRequest(@NonNull Uri contactUri, |
| @NonNull Set<String> myCapabilities, @NonNull OptionsResponseCallback callback) { |
| // Stub - to be implemented by service |
| Log.w(LOG_TAG, "sendOptionsCapabilityRequest called with no implementation."); |
| try { |
| callback.onCommandError(COMMAND_CODE_NOT_SUPPORTED); |
| } catch (ImsException e) { |
| // Do not do anything, this is a stub implementation. |
| } |
| } |
| } |