1 /* 2 * Copyright (c) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.telephony.ims.stub; 18 19 import android.annotation.IntDef; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 import android.annotation.SuppressLint; 23 import android.annotation.SystemApi; 24 import android.net.Uri; 25 import android.telephony.ims.ImsException; 26 import android.telephony.ims.RcsUceAdapter; 27 import android.telephony.ims.feature.ImsFeature; 28 import android.telephony.ims.feature.RcsFeature; 29 import android.util.Log; 30 import android.util.Pair; 31 32 import java.lang.annotation.Retention; 33 import java.lang.annotation.RetentionPolicy; 34 import java.util.Collection; 35 import java.util.List; 36 import java.util.Set; 37 import java.util.concurrent.Executor; 38 39 /** 40 * Extend this base class to implement RCS User Capability Exchange (UCE) for the AOSP platform 41 * using the vendor ImsService. 42 * <p> 43 * See RCC.07 for more details on UCE as well as how UCE should be implemented. 44 * @hide 45 */ 46 @SystemApi 47 public class RcsCapabilityExchangeImplBase { 48 49 private static final String LOG_TAG = "RcsCapExchangeImplBase"; 50 51 /** 52 * Service is unknown. 53 */ 54 public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; 55 56 /** 57 * The command failed with an unknown error. 58 */ 59 public static final int COMMAND_CODE_GENERIC_FAILURE = 1; 60 61 /** 62 * Invalid parameter(s). 63 */ 64 public static final int COMMAND_CODE_INVALID_PARAM = 2; 65 66 /** 67 * Fetch error. 68 */ 69 public static final int COMMAND_CODE_FETCH_ERROR = 3; 70 71 /** 72 * Request timed out. 73 */ 74 public static final int COMMAND_CODE_REQUEST_TIMEOUT = 4; 75 76 /** 77 * Failure due to insufficient memory available. 78 */ 79 public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 5; 80 81 /** 82 * Network connection is lost. 83 */ 84 public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 6; 85 86 /** 87 * Requested feature/resource is not supported. 88 */ 89 public static final int COMMAND_CODE_NOT_SUPPORTED = 7; 90 91 /** 92 * Contact or resource is not found. 93 */ 94 public static final int COMMAND_CODE_NOT_FOUND = 8; 95 96 /** 97 * Service is not available. 98 */ 99 public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 9; 100 101 /** 102 * Command resulted in no change in state, ignoring. 103 */ 104 public static final int COMMAND_CODE_NO_CHANGE = 10; 105 106 /**@hide*/ 107 @Retention(RetentionPolicy.SOURCE) 108 @IntDef(prefix = "COMMAND_CODE_", value = { 109 COMMAND_CODE_SERVICE_UNKNOWN, 110 COMMAND_CODE_GENERIC_FAILURE, 111 COMMAND_CODE_INVALID_PARAM, 112 COMMAND_CODE_FETCH_ERROR, 113 COMMAND_CODE_REQUEST_TIMEOUT, 114 COMMAND_CODE_INSUFFICIENT_MEMORY, 115 COMMAND_CODE_LOST_NETWORK_CONNECTION, 116 COMMAND_CODE_NOT_SUPPORTED, 117 COMMAND_CODE_NOT_FOUND, 118 COMMAND_CODE_SERVICE_UNAVAILABLE, 119 COMMAND_CODE_NO_CHANGE 120 }) 121 public @interface CommandCode {} 122 123 /** 124 * Interface used by the framework to receive the response of the publish request. 125 */ 126 public interface PublishResponseCallback { 127 /** 128 * Notify the framework that the command associated with the 129 * {@link #publishCapabilities(String, PublishResponseCallback)} has failed. 130 * 131 * @param code The reason why the associated command has failed. 132 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is 133 * not currently connected to the framework. This can happen if the {@link RcsFeature} 134 * is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received 135 * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases 136 * when the Telephony stack has crashed. 137 */ onCommandError(@ommandCode int code)138 void onCommandError(@CommandCode int code) throws ImsException; 139 140 /** 141 * Provide the framework with a subsequent network response update to 142 * {@link #publishCapabilities(String, PublishResponseCallback)}. 143 * 144 * If this network response also contains a “Reason” header, then the 145 * {@link #onNetworkResponse(int, String, int, String)} method should be used instead. 146 * 147 * @param sipCode The SIP response code sent from the network for the operation 148 * token specified. 149 * @param reason The optional reason response from the network. If there is a reason header 150 * included in the response, that should take precedence over the reason provided in the 151 * status line. If the network provided no reason with the sip code, the string should be 152 * empty. 153 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is 154 * not currently connected to the framework. This can happen if the {@link RcsFeature} 155 * is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received 156 * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases 157 * when the Telephony stack has crashed. 158 */ onNetworkResponse(@ntRangefrom = 100, to = 699) int sipCode, @NonNull String reason)159 void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, 160 @NonNull String reason) throws ImsException; 161 162 /** 163 * Provide the framework with a subsequent network response update to 164 * {@link #publishCapabilities(String, PublishResponseCallback)} that also 165 * includes a reason provided in the “reason” header. See RFC3326 for more 166 * information. 167 * 168 * @param sipCode The SIP response code sent from the network. 169 * @param reasonPhrase The optional reason response from the network. If the 170 * network provided no reason with the sip code, the string should be empty. 171 * @param reasonHeaderCause The “cause” parameter of the “reason” header 172 * included in the SIP message. 173 * @param reasonHeaderText The “text” parameter of the “reason” header 174 * included in the SIP message. 175 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is 176 * not currently connected to the framework. This can happen if the 177 * {@link RcsFeature} is not 178 * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received 179 * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in 180 * rare cases when the Telephony stack has crashed. 181 */ onNetworkResponse(@ntRangefrom = 100, to = 699) int sipCode, @NonNull String reasonPhrase, @IntRange(from = 100, to = 699) int reasonHeaderCause, @NonNull String reasonHeaderText)182 void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, 183 @NonNull String reasonPhrase, 184 @IntRange(from = 100, to = 699) int reasonHeaderCause, 185 @NonNull String reasonHeaderText) throws ImsException; 186 } 187 188 /** 189 * Interface used by the framework to respond to OPTIONS requests. 190 */ 191 public interface OptionsResponseCallback { 192 /** 193 * Notify the framework that the command associated with this callback has failed. 194 * 195 * @param code The reason why the associated command has failed. 196 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is 197 * not currently connected to the framework. This can happen if the 198 * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature} 199 * has not received the {@link ImsFeature#onFeatureReady()} callback. This may also happen 200 * in rare cases when the Telephony stack has crashed. 201 */ onCommandError(@ommandCode int code)202 void onCommandError(@CommandCode int code) throws ImsException; 203 204 /** 205 * Send the response of a SIP OPTIONS capability exchange to the framework. 206 * @param sipCode The SIP response code that was sent by the network in response 207 * to the request sent by {@link #sendOptionsCapabilityRequest}. 208 * @param reason The optional SIP response reason sent by the network. 209 * If none was sent, this should be an empty string. 210 * @param theirCaps the contact's UCE capabilities associated with the 211 * capability request. 212 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not 213 * currently connected to the framework. This can happen if the 214 * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the 215 * {@link RcsFeature} has not received the 216 * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare 217 * cases when the Telephony stack has crashed. 218 */ onNetworkResponse(int sipCode, @NonNull String reason, @NonNull List<String> theirCaps)219 void onNetworkResponse(int sipCode, @NonNull String reason, 220 @NonNull List<String> theirCaps) throws ImsException; 221 } 222 223 /** 224 * Interface used by the framework to receive the response of the subscribe request. 225 */ 226 public interface SubscribeResponseCallback { 227 /** 228 * Notify the framework that the command associated with this callback has failed. 229 * <p> 230 * Must only be called when there was an error generating a SUBSCRIBE request due to an 231 * IMS stack error. This is a terminating event, so no other callback event will be 232 * expected after this callback. 233 * 234 * @param code The reason why the associated command has failed. 235 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is 236 * not currently connected to the framework. This can happen if the 237 * {@link RcsFeature} is not 238 * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received 239 * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in 240 * rare cases when the Telephony stack has crashed. 241 */ onCommandError(@ommandCode int code)242 void onCommandError(@CommandCode int code) throws ImsException; 243 244 /** 245 * Notify the framework of the response to the SUBSCRIBE request from 246 * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)}. 247 * <p> 248 * If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the 249 * framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate}, 250 * {@link #onResourceTerminated}, and {@link #onTerminated} as required for the 251 * subsequent NOTIFY responses to the subscription. 252 * 253 * If this network response also contains a “Reason” header, then the 254 * {@link #onNetworkResponse(int, String, int, String)} method should be used instead. 255 * 256 * @param sipCode The SIP response code sent from the network for the operation 257 * token specified. 258 * @param reason The optional reason response from the network. If the network 259 * provided no reason with the sip code, the string should be empty. 260 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is 261 * not currently connected to the framework. This can happen if the 262 * {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the 263 * {@link RcsFeature} has not received the {@link ImsFeature#onFeatureReady()} callback. 264 * This may also happen in rare cases when the Telephony stack has crashed. 265 */ onNetworkResponse(@ntRangefrom = 100, to = 699) int sipCode, @NonNull String reason)266 void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, 267 @NonNull String reason) throws ImsException; 268 269 /** 270 * Notify the framework of the response to the SUBSCRIBE request from 271 * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)} that also 272 * includes a reason provided in the “reason” header. See RFC3326 for more 273 * information. 274 * 275 * @param sipCode The SIP response code sent from the network, 276 * @param reasonPhrase The optional reason response from the network. If the 277 * network provided no reason with the sip code, the string should be empty. 278 * @param reasonHeaderCause The “cause” parameter of the “reason” header 279 * included in the SIP message. 280 * @param reasonHeaderText The “text” parameter of the “reason” header 281 * included in the SIP message. 282 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is 283 * not currently connected to the framework. This can happen if the 284 * {@link RcsFeature} is not 285 * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received 286 * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in 287 * rare cases when the Telephony stack has crashed. 288 */ onNetworkResponse(@ntRangefrom = 100, to = 699) int sipCode, @NonNull String reasonPhrase, @IntRange(from = 100, to = 699) int reasonHeaderCause, @NonNull String reasonHeaderText)289 void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode, 290 @NonNull String reasonPhrase, 291 @IntRange(from = 100, to = 699) int reasonHeaderCause, 292 @NonNull String reasonHeaderText) throws ImsException; 293 294 /** 295 * Notify the framework of the latest XML PIDF documents included in the network response 296 * for the requested contacts' capabilities requested by the Framework using 297 * {@link RcsUceAdapter#requestCapabilities(List, Executor, 298 * RcsUceAdapter.CapabilitiesCallback)}. 299 * <p> 300 * The expected format for the PIDF XML is defined in RFC3861. Each XML document must be a 301 * "application/pidf+xml" object and start with a root <presence> element. For NOTIFY 302 * responses that contain RLMI information and potentially multiple PIDF XMLs, each 303 * PIDF XML should be separated and added as a separate item in the List. This should be 304 * called every time a new NOTIFY event is received with new capability information. 305 * 306 * @param pidfXmls The list of the PIDF XML data for the contact URIs that it subscribed 307 * for. 308 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is 309 * not currently connected to the framework. 310 * This can happen if the {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the 311 * {@link RcsFeature} {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not 312 * received the {@link ImsFeature#onFeatureReady()} callback. This may also happen in 313 * rare cases when the Telephony stack has crashed. 314 */ onNotifyCapabilitiesUpdate(@onNull List<String> pidfXmls)315 void onNotifyCapabilitiesUpdate(@NonNull List<String> pidfXmls) throws ImsException; 316 317 /** 318 * Notify the framework that a resource in the RLMI XML contained in the NOTIFY response 319 * for the ongoing SUBSCRIBE dialog has been terminated. 320 * <p> 321 * This will be used to notify the framework that a contact URI that the IMS stack has 322 * subscribed to on the Resource List Server has been terminated as well as the reason why. 323 * Usually this means that there will not be any capability information for the contact URI 324 * that they subscribed for. See RFC 4662 for more information. 325 * 326 * @param uriTerminatedReason The contact URIs which have been terminated. Each pair in the 327 * list is the contact URI and its terminated reason. 328 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is 329 * not currently connected to the framework. 330 * This can happen if the {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the 331 * {@link RcsFeature} {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not 332 * received the {@link ImsFeature#onFeatureReady()} callback. This may also happen in 333 * rare cases when the Telephony stack has crashed. 334 */ onResourceTerminated( @onNull List<Pair<Uri, String>> uriTerminatedReason)335 void onResourceTerminated( 336 @NonNull List<Pair<Uri, String>> uriTerminatedReason) throws ImsException; 337 338 /** 339 * The subscription associated with a previous 340 * {@link RcsUceAdapter#requestCapabilities(List, Executor, 341 * RcsUceAdapter.CapabilitiesCallback)} 342 * operation has been terminated. This will mostly be due to the network sending a final 343 * NOTIFY response due to the subscription expiring, but this may also happen due to a 344 * network error. 345 * 346 * @param reason The reason for the request being unable to process. 347 * @param retryAfterMilliseconds The time in milliseconds the requesting application should 348 * wait before retrying, if non-zero. 349 * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is 350 * not currently connected to the framework. 351 * This can happen if the {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the 352 * {@link RcsFeature} {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not 353 * received the {@link ImsFeature#onFeatureReady()} callback. This may also happen in 354 * rare cases when the Telephony stack has crashed. 355 */ onTerminated(@onNull String reason, long retryAfterMilliseconds)356 void onTerminated(@NonNull String reason, long retryAfterMilliseconds) throws ImsException; 357 } 358 359 /** 360 * Create a new RcsCapabilityExchangeImplBase instance. 361 */ RcsCapabilityExchangeImplBase()362 public RcsCapabilityExchangeImplBase() { 363 } 364 365 /** 366 * The user capabilities of one or multiple contacts have been requested by the framework. 367 * <p> 368 * The implementer must follow up this call with an 369 * {@link SubscribeResponseCallback#onCommandError} call to indicate this operation has failed. 370 * The response from the network to the SUBSCRIBE request must be sent back to the framework 371 * using {@link SubscribeResponseCallback#onNetworkResponse(int, String)}. 372 * As NOTIFY requests come in from the network, the requested contact’s capabilities should be 373 * sent back to the framework using 374 * {@link SubscribeResponseCallback#onNotifyCapabilitiesUpdate(List<String>}) and 375 * {@link SubscribeResponseCallback#onResourceTerminated(List<Pair<Uri, String>>)} 376 * should be called with the presence information for the contacts specified. 377 * <p> 378 * Once the subscription is terminated, 379 * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the 380 * framework to finish listening for NOTIFY responses. 381 * 382 * @param uris A {@link Collection} of the {@link Uri}s that the framework is requesting the 383 * UCE capabilities for. 384 * @param cb The callback of the subscribe request. 385 */ 386 // executor used is defined in the constructor. 387 @SuppressLint("ExecutorRegistration") subscribeForCapabilities(@onNull Collection<Uri> uris, @NonNull SubscribeResponseCallback cb)388 public void subscribeForCapabilities(@NonNull Collection<Uri> uris, 389 @NonNull SubscribeResponseCallback cb) { 390 // Stub - to be implemented by service 391 Log.w(LOG_TAG, "subscribeForCapabilities called with no implementation."); 392 try { 393 cb.onCommandError(COMMAND_CODE_NOT_SUPPORTED); 394 } catch (ImsException e) { 395 // Do not do anything, this is a stub implementation. 396 } 397 } 398 399 /** 400 * The capabilities of this device have been updated and should be published to the network. 401 * <p> 402 * If this operation succeeds, network response updates should be sent to the framework using 403 * {@link PublishResponseCallback#onNetworkResponse(int, String)}. 404 * @param pidfXml The XML PIDF document containing the capabilities of this device to be sent 405 * to the carrier’s presence server. 406 * @param cb The callback of the publish request 407 */ 408 // executor used is defined in the constructor. 409 @SuppressLint("ExecutorRegistration") publishCapabilities(@onNull String pidfXml, @NonNull PublishResponseCallback cb)410 public void publishCapabilities(@NonNull String pidfXml, @NonNull PublishResponseCallback cb) { 411 // Stub - to be implemented by service 412 Log.w(LOG_TAG, "publishCapabilities called with no implementation."); 413 try { 414 cb.onCommandError(COMMAND_CODE_NOT_SUPPORTED); 415 } catch (ImsException e) { 416 // Do not do anything, this is a stub implementation. 417 } 418 } 419 420 /** 421 * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism 422 * in order to receive the capabilities of the remote user in response. 423 * <p> 424 * The implementer must use {@link OptionsResponseCallback} to send the response of 425 * this query from the network back to the framework. 426 * @param contactUri The URI of the remote user that we wish to get the capabilities of. 427 * @param myCapabilities The capabilities of this device to send to the remote user. 428 * @param callback The callback of this request which is sent from the remote user. 429 */ 430 // executor used is defined in the constructor. 431 @SuppressLint("ExecutorRegistration") sendOptionsCapabilityRequest(@onNull Uri contactUri, @NonNull Set<String> myCapabilities, @NonNull OptionsResponseCallback callback)432 public void sendOptionsCapabilityRequest(@NonNull Uri contactUri, 433 @NonNull Set<String> myCapabilities, @NonNull OptionsResponseCallback callback) { 434 // Stub - to be implemented by service 435 Log.w(LOG_TAG, "sendOptionsCapabilityRequest called with no implementation."); 436 try { 437 callback.onCommandError(COMMAND_CODE_NOT_SUPPORTED); 438 } catch (ImsException e) { 439 // Do not do anything, this is a stub implementation. 440 } 441 } 442 } 443