1 /* 2 * Copyright (C) 2018 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.NonNull; 21 import android.net.Uri; 22 import android.os.RemoteException; 23 import android.telephony.ims.ImsException; 24 import android.telephony.ims.RcsContactUceCapability; 25 import android.telephony.ims.feature.ImsFeature; 26 import android.telephony.ims.feature.RcsFeature; 27 import android.util.Log; 28 29 import java.lang.annotation.Retention; 30 import java.lang.annotation.RetentionPolicy; 31 import java.util.List; 32 33 /** 34 * Base implementation for RCS User Capability Exchange using Presence. Any ImsService implementing 35 * this service must implement the stub methods {@link #requestCapabilities(List, int)} and 36 * {@link #updateCapabilities(RcsContactUceCapability, int)}. 37 * 38 * @hide 39 */ 40 public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { 41 42 private static final String LOG_TAG = "RcsPresenceExchangeIB"; 43 44 /** 45 * The request has resulted in any other 4xx/5xx/6xx that is not covered below. No retry will be 46 * attempted. 47 */ 48 public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; 49 50 /** 51 * The request has succeeded with a “200” message from the network. 52 */ 53 public static final int RESPONSE_SUCCESS = 0; 54 55 /** 56 * The request has resulted in a “403” (User Not Registered) error from the network. Will retry 57 * capability polling with an exponential backoff. 58 */ 59 public static final int RESPONSE_NOT_REGISTERED = 1; 60 61 /** 62 * The request has resulted in a “403” (not authorized (Requestor)) error from the network. No 63 * retry will be attempted. 64 */ 65 public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; 66 67 /** 68 * The request has resulted in a "403” (Forbidden) or other “403” error from the network and 69 * will be handled the same as “404” Not found. No retry will be attempted. 70 */ 71 public static final int RESPONSE_FORBIDDEN = 3; 72 73 /** 74 * The request has resulted in a “404” (Not found) result from the network. No retry will be 75 * attempted. 76 */ 77 public static final int RESPONSE_NOT_FOUND = 4; 78 79 /** 80 * The request has resulted in a “408” response. Retry after exponential backoff. 81 */ 82 public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; 83 84 /** 85 * The network has responded with a “413” (Too Large) response from the network. Capability 86 * request contains too many items and must be shrunk before the request will be accepted. 87 */ 88 public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; 89 90 /** 91 * The request has resulted in a “423” response. Retry after exponential backoff. 92 */ 93 public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; 94 95 /** 96 * The request has resulted in a “503” response. Retry after exponential backoff. 97 */ 98 public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; 99 100 /** @hide*/ 101 @Retention(RetentionPolicy.SOURCE) 102 @IntDef(prefix = "RESPONSE_", value = { 103 RESPONSE_SUBSCRIBE_GENERIC_FAILURE, 104 RESPONSE_SUCCESS, 105 RESPONSE_NOT_REGISTERED, 106 RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE, 107 RESPONSE_FORBIDDEN, 108 RESPONSE_NOT_FOUND, 109 RESPONSE_SIP_REQUEST_TIMEOUT, 110 RESPONSE_SUBSCRIBE_TOO_LARGE, 111 RESPONSE_SIP_INTERVAL_TOO_SHORT, 112 RESPONSE_SIP_SERVICE_UNAVAILABLE 113 }) 114 public @interface PresenceResponseCode {} 115 116 117 /** A capability update has been requested due to the Entity Tag (ETag) expiring. */ 118 public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; 119 /** A capability update has been requested due to moving to LTE with VoPS disabled. */ 120 public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; 121 /** A capability update has been requested due to moving to LTE with VoPS enabled. */ 122 public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; 123 /** A capability update has been requested due to moving to eHRPD. */ 124 public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; 125 /** A capability update has been requested due to moving to HSPA+. */ 126 public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; 127 /** A capability update has been requested due to moving to 3G. */ 128 public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; 129 /** A capability update has been requested due to moving to 2G. */ 130 public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; 131 /** A capability update has been requested due to moving to WLAN */ 132 public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; 133 /** A capability update has been requested due to moving to IWLAN */ 134 public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; 135 /** A capability update has been requested but the reason is unknown. */ 136 public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; 137 /** A capability update has been requested due to moving to 5G NR with VoPS disabled. */ 138 public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; 139 /** A capability update has been requested due to moving to 5G NR with VoPS enabled. */ 140 public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; 141 142 /** @hide*/ 143 @IntDef(value = { 144 CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED, 145 CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED, 146 CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED, 147 CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD, 148 CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS, 149 CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G, 150 CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G, 151 CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN, 152 CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN, 153 CAPABILITY_UPDATE_TRIGGER_UNKNOWN, 154 CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED, 155 CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED 156 }, prefix = "CAPABILITY_UPDATE_TRIGGER_") 157 @Retention(RetentionPolicy.SOURCE) 158 public @interface StackPublishTriggerType { 159 } 160 161 /** 162 * Provide the framework with a subsequent network response update to 163 * {@link #updateCapabilities(RcsContactUceCapability, int)} and 164 * {@link #requestCapabilities(List, int)} operations. 165 * 166 * @param code The SIP response code sent from the network for the operation token specified. 167 * @param reason The optional reason response from the network. If the network provided no 168 * reason with the code, the string should be empty. 169 * @param operationToken The token associated with the operation this service is providing a 170 * response for. 171 * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently 172 * connected to the framework. This can happen if the {@link RcsFeature} is not 173 * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the 174 * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the 175 * Telephony stack has crashed. 176 */ onNetworkResponse(@resenceResponseCode int code, @NonNull String reason, int operationToken)177 public final void onNetworkResponse(@PresenceResponseCode int code, @NonNull String reason, 178 int operationToken) throws ImsException { 179 try { 180 getListener().onNetworkResponse(code, reason, operationToken); 181 } catch (RemoteException e) { 182 throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); 183 } 184 } 185 186 /** 187 * Provides the framework with the requested contacts’ capabilities requested by the framework 188 * using {@link #requestCapabilities(List, int)}. 189 * 190 * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently 191 * connected to the framework. This can happen if the {@link RcsFeature} is not 192 * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the 193 * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the 194 * Telephony stack has crashed. 195 */ onCapabilityRequestResponse(@onNull List<RcsContactUceCapability> infos, int operationToken)196 public final void onCapabilityRequestResponse(@NonNull List<RcsContactUceCapability> infos, 197 int operationToken) throws ImsException { 198 try { 199 getListener().onCapabilityRequestResponsePresence(infos, operationToken); 200 } catch (RemoteException e) { 201 throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); 202 } 203 } 204 205 /** 206 * Trigger the framework to provide a capability update using 207 * {@link #updateCapabilities(RcsContactUceCapability, int)}. 208 * <p> 209 * This is typically used when trying to generate an initial PUBLISH for a new subscription to 210 * the network. The device will cache all presence publications after boot until this method is 211 * called once. 212 * @param publishTriggerType {@link StackPublishTriggerType} The reason for the capability 213 * update request. 214 * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently 215 * connected to the framework. This can happen if the {@link RcsFeature} is not 216 * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the 217 * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the 218 * Telephony stack has crashed. 219 */ onNotifyUpdateCapabilites(@tackPublishTriggerType int publishTriggerType)220 public final void onNotifyUpdateCapabilites(@StackPublishTriggerType int publishTriggerType) 221 throws ImsException { 222 try { 223 getListener().onNotifyUpdateCapabilities(publishTriggerType); 224 } catch (RemoteException e) { 225 throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); 226 } 227 } 228 229 /** 230 * Notify the framework that the device’s capabilities have been unpublished from the network. 231 * 232 * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently 233 * connected to the framework. This can happen if the {@link RcsFeature} is not 234 * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the 235 * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the 236 * Telephony stack has crashed. 237 */ onUnpublish()238 public final void onUnpublish() throws ImsException { 239 try { 240 getListener().onUnpublish(); 241 } catch (RemoteException e) { 242 throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); 243 } 244 } 245 246 /** 247 * The user capabilities of one or multiple contacts have been requested by the framework. 248 * <p> 249 * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to 250 * indicate whether or not this operation succeeded. If this operation succeeds, network 251 * response updates should be sent to the framework using 252 * {@link #onNetworkResponse(int, String, int)}. When the operation is completed, 253 * {@link #onCapabilityRequestResponse(List, int)} should be called with the presence 254 * information for the contacts specified. 255 * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE 256 * capabilities for. 257 * @param operationToken The token associated with this operation. Updates to this request using 258 * {@link #onCommandUpdate(int, int)}, {@link #onNetworkResponse(int, String, int)}, and 259 * {@link #onCapabilityRequestResponse(List, int)} must use the same operation token 260 * in response. 261 */ requestCapabilities(@onNull List<Uri> uris, int operationToken)262 public void requestCapabilities(@NonNull List<Uri> uris, int operationToken) { 263 // Stub - to be implemented by service 264 Log.w(LOG_TAG, "requestCapabilities called with no implementation."); 265 try { 266 getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken); 267 } catch (RemoteException | ImsException e) { 268 // Do not do anything, this is a stub implementation. 269 } 270 } 271 272 /** 273 * The capabilities of this device have been updated and should be published to the network. 274 * <p> 275 * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to 276 * indicate whether or not this operation succeeded. If this operation succeeds, network 277 * response updates should be sent to the framework using 278 * {@link #onNetworkResponse(int, String, int)}. 279 * @param capabilities The capabilities for this device. 280 * @param operationToken The token associated with this operation. Any subsequent 281 * {@link #onCommandUpdate(int, int)} or {@link #onNetworkResponse(int, String, int)} 282 * calls regarding this update must use the same token. 283 */ updateCapabilities(@onNull RcsContactUceCapability capabilities, int operationToken)284 public void updateCapabilities(@NonNull RcsContactUceCapability capabilities, 285 int operationToken) { 286 // Stub - to be implemented by service 287 Log.w(LOG_TAG, "updateCapabilities called with no implementation."); 288 try { 289 getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken); 290 } catch (RemoteException | ImsException e) { 291 // Do not do anything, this is a stub implementation. 292 } 293 } 294 } 295