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.IntRange; 21 import android.annotation.SystemApi; 22 import android.os.RemoteException; 23 import android.telephony.SmsManager; 24 import android.telephony.SmsMessage; 25 import android.telephony.ims.aidl.IImsSmsListener; 26 import android.util.Log; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 31 /** 32 * Base implementation for SMS over IMS. 33 * 34 * Any service wishing to provide SMS over IMS should extend this class and implement all methods 35 * that the service supports. 36 * 37 * @hide 38 */ 39 @SystemApi 40 public class ImsSmsImplBase { 41 private static final String LOG_TAG = "SmsImplBase"; 42 43 /** @hide */ 44 @IntDef({ 45 SEND_STATUS_OK, 46 SEND_STATUS_ERROR, 47 SEND_STATUS_ERROR_RETRY, 48 SEND_STATUS_ERROR_FALLBACK 49 }) 50 @Retention(RetentionPolicy.SOURCE) 51 public @interface SendStatusResult {} 52 /** 53 * Message was sent successfully. 54 */ 55 public static final int SEND_STATUS_OK = 1; 56 57 /** 58 * IMS provider failed to send the message and platform should not retry falling back to sending 59 * the message using the radio. 60 */ 61 public static final int SEND_STATUS_ERROR = 2; 62 63 /** 64 * IMS provider failed to send the message and platform should retry again after setting TP-RD 65 * bit to high. 66 */ 67 public static final int SEND_STATUS_ERROR_RETRY = 3; 68 69 /** 70 * IMS provider failed to send the message and platform should retry falling back to sending 71 * the message using the radio. 72 */ 73 public static final int SEND_STATUS_ERROR_FALLBACK = 4; 74 75 /** @hide */ 76 @IntDef({ 77 DELIVER_STATUS_OK, 78 DELIVER_STATUS_ERROR_GENERIC, 79 DELIVER_STATUS_ERROR_NO_MEMORY, 80 DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED 81 }) 82 @Retention(RetentionPolicy.SOURCE) 83 public @interface DeliverStatusResult {} 84 /** 85 * Message was delivered successfully. 86 */ 87 public static final int DELIVER_STATUS_OK = 1; 88 89 /** 90 * Message was not delivered. 91 */ 92 public static final int DELIVER_STATUS_ERROR_GENERIC = 2; 93 94 /** 95 * Message was not delivered due to lack of memory. 96 */ 97 public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3; 98 99 /** 100 * Message was not delivered as the request is not supported. 101 */ 102 public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4; 103 104 /** @hide */ 105 @IntDef({ 106 STATUS_REPORT_STATUS_OK, 107 STATUS_REPORT_STATUS_ERROR 108 }) 109 @Retention(RetentionPolicy.SOURCE) 110 public @interface StatusReportResult {} 111 112 /** 113 * Status Report was set successfully. 114 */ 115 public static final int STATUS_REPORT_STATUS_OK = 1; 116 117 /** 118 * Error while setting status report. 119 */ 120 public static final int STATUS_REPORT_STATUS_ERROR = 2; 121 122 /** 123 * No network error was generated while processing the SMS message. 124 */ 125 // Should match SmsResponse.NO_ERROR_CODE 126 public static final int RESULT_NO_NETWORK_ERROR = -1; 127 128 // Lock for feature synchronization 129 private final Object mLock = new Object(); 130 private IImsSmsListener mListener; 131 132 /** 133 * Registers a listener responsible for handling tasks like delivering messages. 134 * 135 * @param listener listener to register. 136 * 137 * @hide 138 */ registerSmsListener(IImsSmsListener listener)139 public final void registerSmsListener(IImsSmsListener listener) { 140 synchronized (mLock) { 141 mListener = listener; 142 } 143 } 144 145 /** 146 * This method will be triggered by the platform when the user attempts to send an SMS. This 147 * method should be implemented by the IMS providers to provide implementation of sending an SMS 148 * over IMS. 149 * 150 * @param token unique token generated by the platform that should be used when triggering 151 * callbacks for this specific message. 152 * @param messageRef the message reference, which may be 1 byte if it is in 153 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in 154 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). 155 * @param format the format of the message. 156 * @param smsc the Short Message Service Center address. 157 * @param isRetry whether it is a retry of an already attempted message or not. 158 * @param pdu PDU representing the contents of the message. 159 */ sendSms(int token, @IntRange(from = 0, to = 65535) int messageRef, @SmsMessage.Format String format, String smsc, boolean isRetry, byte[] pdu)160 public void sendSms(int token, @IntRange(from = 0, to = 65535) int messageRef, 161 @SmsMessage.Format String format, String smsc, boolean isRetry, 162 byte[] pdu) { 163 // Base implementation returns error. Should be overridden. 164 try { 165 onSendSmsResult(token, messageRef, SEND_STATUS_ERROR, 166 SmsManager.RESULT_ERROR_GENERIC_FAILURE); 167 } catch (RuntimeException e) { 168 Log.e(LOG_TAG, "Can not send sms: " + e.getMessage()); 169 } 170 } 171 172 /** 173 * This method will be triggered by the platform after 174 * {@link #onSmsReceived(int, String, byte[])} has been called to deliver the result to the IMS 175 * provider. 176 * 177 * @param token token provided in {@link #onSmsReceived(int, String, byte[])} 178 * @param messageRef the message reference, which may be 1 byte if it is in 179 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in 180 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). 181 * @param result result of delivering the message. 182 */ acknowledgeSms(int token, @IntRange(from = 0, to = 65535) int messageRef, @DeliverStatusResult int result)183 public void acknowledgeSms(int token, @IntRange(from = 0, to = 65535) int messageRef, 184 @DeliverStatusResult int result) { 185 Log.e(LOG_TAG, "acknowledgeSms() not implemented."); 186 } 187 188 /** 189 * This method will be triggered by the platform after 190 * {@link #onSmsStatusReportReceived(int, int, String, byte[])} or 191 * {@link #onSmsStatusReportReceived(int, String, byte[])} has been called to provide the 192 * result to the IMS provider. 193 * 194 * @param token token provided in {@link #onSmsStatusReportReceived(int, int, String, byte[])} 195 * or {@link #onSmsStatusReportReceived(int, String, byte[])} 196 * @param messageRef the message reference, which may be 1 byte if it is in 197 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in 198 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). 199 * @param result result of delivering the message. 200 */ acknowledgeSmsReport(int token, @IntRange(from = 0, to = 65535) int messageRef, @StatusReportResult int result)201 public void acknowledgeSmsReport(int token, @IntRange(from = 0, to = 65535) int messageRef, 202 @StatusReportResult int result) { 203 Log.e(LOG_TAG, "acknowledgeSmsReport() not implemented."); 204 } 205 206 /** 207 * This method should be triggered by the IMS providers when there is an incoming message. The 208 * platform will deliver the message to the messages database and notify the IMS provider of the 209 * result by calling {@link #acknowledgeSms(int, int, int)}. 210 * 211 * This method must not be called before {@link #onReady()} is called or the call will fail. If 212 * the platform is not available, {@link #acknowledgeSms(int, int, int)} will be called with the 213 * {@link #DELIVER_STATUS_ERROR_GENERIC} result code. 214 * @param token unique token generated by IMS providers that the platform will use to trigger 215 * callbacks for this message. 216 * @param format the format of the message. 217 * @param pdu PDU representing the contents of the message. 218 * @throws RuntimeException if called before {@link #onReady()} is triggered. 219 */ onSmsReceived(int token, @SmsMessage.Format String format, byte[] pdu)220 public final void onSmsReceived(int token, @SmsMessage.Format String format, byte[] pdu) 221 throws RuntimeException { 222 synchronized (mLock) { 223 if (mListener == null) { 224 throw new RuntimeException("Feature not ready."); 225 } 226 try { 227 mListener.onSmsReceived(token, format, pdu); 228 } catch (RemoteException e) { 229 Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage()); 230 SmsMessage message = SmsMessage.createFromPdu(pdu, format); 231 if (message != null && message.mWrappedSmsMessage != null) { 232 acknowledgeSms(token, message.mWrappedSmsMessage.mMessageRef, 233 DELIVER_STATUS_ERROR_GENERIC); 234 } else { 235 Log.w(LOG_TAG, "onSmsReceived: Invalid pdu entered."); 236 acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC); 237 } 238 } 239 } 240 } 241 242 /** 243 * This method should be triggered by the IMS providers when an outgoing SMS message has been 244 * sent successfully. 245 * 246 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} 247 * @param messageRef the message reference, which may be 1 byte if it is in 248 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in 249 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). 250 * 251 * @throws RuntimeException if called before {@link #onReady()} is triggered or if the 252 * connection to the framework is not available. If this happens attempting to send the SMS 253 * should be aborted. 254 */ onSendSmsResultSuccess(int token, @IntRange(from = 0, to = 65535) int messageRef)255 public final void onSendSmsResultSuccess(int token, 256 @IntRange(from = 0, to = 65535) int messageRef) throws RuntimeException { 257 synchronized (mLock) { 258 if (mListener == null) { 259 throw new RuntimeException("Feature not ready."); 260 } 261 try { 262 mListener.onSendSmsResult(token, messageRef, SEND_STATUS_OK, 263 SmsManager.RESULT_ERROR_NONE, RESULT_NO_NETWORK_ERROR); 264 } catch (RemoteException e) { 265 e.rethrowFromSystemServer(); 266 } 267 } 268 } 269 270 /** 271 * This method should be triggered by the IMS providers to pass the result of the sent message 272 * to the platform. 273 * 274 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} 275 * @param messageRef the message reference, which may be 1 byte if it is in 276 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in 277 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). 278 * @param status result of sending the SMS. 279 * @param reason reason in case status is failure. 280 * 281 * @throws RuntimeException if called before {@link #onReady()} is triggered or if the 282 * connection to the framework is not available. If this happens attempting to send the SMS 283 * should be aborted. 284 * @deprecated Use {@link #onSendSmsResultSuccess(int, int)} or 285 * {@link #onSendSmsResultError(int, int, int, int, int)} to notify the framework of the SMS 286 * send result. 287 */ 288 @Deprecated onSendSmsResult(int token, @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status, @SmsManager.Result int reason)289 public final void onSendSmsResult(int token, @IntRange(from = 0, to = 65535) int messageRef, 290 @SendStatusResult int status, @SmsManager.Result int reason) throws RuntimeException { 291 synchronized (mLock) { 292 if (mListener == null) { 293 throw new RuntimeException("Feature not ready."); 294 } 295 try { 296 mListener.onSendSmsResult(token, messageRef, status, reason, 297 RESULT_NO_NETWORK_ERROR); 298 } catch (RemoteException e) { 299 e.rethrowFromSystemServer(); 300 } 301 } 302 } 303 304 /** 305 * This method should be triggered by the IMS providers when an outgoing message fails to be 306 * sent due to an error generated while processing the message or after being sent to the 307 * network. 308 * 309 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} 310 * @param messageRef the message reference, which may be 1 byte if it is in 311 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in 312 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). 313 * @param status result of sending the SMS. 314 * @param networkErrorCode the error code reported by the carrier network if sending this SMS 315 * has resulted in an error or {@link #RESULT_NO_NETWORK_ERROR} if no network error was 316 * generated. See 3GPP TS 24.011 Section 7.3.4 for valid error codes and more information. 317 * 318 * @throws RuntimeException if called before {@link #onReady()} is triggered or if the 319 * connection to the framework is not available. If this happens attempting to send the SMS 320 * should be aborted. 321 */ onSendSmsResultError(int token, @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status, @SmsManager.Result int reason, int networkErrorCode)322 public final void onSendSmsResultError(int token, 323 @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status, 324 @SmsManager.Result int reason, int networkErrorCode) throws RuntimeException { 325 synchronized (mLock) { 326 if (mListener == null) { 327 throw new RuntimeException("Feature not ready."); 328 } 329 try { 330 mListener.onSendSmsResult(token, messageRef, status, reason, networkErrorCode); 331 } catch (RemoteException e) { 332 e.rethrowFromSystemServer(); 333 } 334 } 335 } 336 337 /** 338 * This method should be triggered by the IMS providers when the status report of the sent 339 * message is received. The platform will handle the report and notify the IMS provider of the 340 * result by calling {@link #acknowledgeSmsReport(int, int, int)}. 341 * 342 * This method must not be called before {@link #onReady()} is called or the call will fail. If 343 * the platform is not available, {@link #acknowledgeSmsReport(int, int, int)} will be called 344 * with the {@link #STATUS_REPORT_STATUS_ERROR} result code. 345 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} 346 * @param messageRef the message reference, which may be 1 byte if it is in 347 * {@link SmsMessage#FORMAT_3GPP} format or 2 bytes if it is in 348 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). 349 * @param format the format of the message. 350 * @param pdu PDU representing the content of the status report. 351 * @throws RuntimeException if called before {@link #onReady()} is triggered 352 * 353 * @deprecated Use {@link #onSmsStatusReportReceived(int, String, byte[])} instead without the 354 * message reference. 355 */ 356 @Deprecated onSmsStatusReportReceived(int token, @IntRange(from = 0, to = 65535) int messageRef, @SmsMessage.Format String format, byte[] pdu)357 public final void onSmsStatusReportReceived(int token, 358 @IntRange(from = 0, to = 65535) int messageRef, @SmsMessage.Format String format, 359 byte[] pdu) throws RuntimeException { 360 synchronized (mLock) { 361 if (mListener == null) { 362 throw new RuntimeException("Feature not ready."); 363 } 364 try { 365 mListener.onSmsStatusReportReceived(token, format, pdu); 366 } catch (RemoteException e) { 367 Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage()); 368 acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR); 369 } 370 } 371 } 372 373 /** 374 * This method should be triggered by the IMS providers when the status report of the sent 375 * message is received. The platform will handle the report and notify the IMS provider of the 376 * result by calling {@link #acknowledgeSmsReport(int, int, int)}. 377 * 378 * This method must not be called before {@link #onReady()} is called or the call will fail. If 379 * the platform is not available, {@link #acknowledgeSmsReport(int, int, int)} will be called 380 * with the {@link #STATUS_REPORT_STATUS_ERROR} result code. 381 * @param token unique token generated by IMS providers that the platform will use to trigger 382 * callbacks for this message. 383 * @param format the format of the message. 384 * @param pdu PDU representing the content of the status report. 385 * @throws RuntimeException if called before {@link #onReady()} is triggered 386 */ onSmsStatusReportReceived(int token, @SmsMessage.Format String format, byte[] pdu)387 public final void onSmsStatusReportReceived(int token, @SmsMessage.Format String format, 388 byte[] pdu) throws RuntimeException { 389 synchronized (mLock) { 390 if (mListener == null) { 391 throw new RuntimeException("Feature not ready."); 392 } 393 try { 394 mListener.onSmsStatusReportReceived(token, format, pdu); 395 } catch (RemoteException e) { 396 Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage()); 397 SmsMessage message = SmsMessage.createFromPdu(pdu, format); 398 if (message != null && message.mWrappedSmsMessage != null) { 399 acknowledgeSmsReport( 400 token, 401 message.mWrappedSmsMessage.mMessageRef, 402 STATUS_REPORT_STATUS_ERROR); 403 } else { 404 Log.w(LOG_TAG, "onSmsStatusReportReceived: Invalid pdu entered."); 405 acknowledgeSmsReport(token, 0, STATUS_REPORT_STATUS_ERROR); 406 } 407 } 408 } 409 } 410 411 /** 412 * Returns the SMS format that the ImsService expects. 413 * 414 * @return The expected format of the SMS messages. 415 */ getSmsFormat()416 public @SmsMessage.Format String getSmsFormat() { 417 return SmsMessage.FORMAT_3GPP; 418 } 419 420 /** 421 * Called when ImsSmsImpl has been initialized and communication with the framework is set up. 422 * Any attempt by this class to access the framework before this method is called will return 423 * with a {@link RuntimeException}. 424 */ onReady()425 public void onReady() { 426 // Base Implementation - Should be overridden 427 } 428 } 429