blob: 66442a6adb540352e8ab36fbaa7be1c8f44c318a [file] [log] [blame]
/*
* 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.
}
}
}