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.SystemApi; 21 import android.os.RemoteException; 22 import android.telephony.SmsManager; 23 import android.telephony.SmsMessage; 24 import android.telephony.ims.aidl.IImsSmsListener; 25 import android.util.Log; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 30 /** 31 * Base implementation for SMS over IMS. 32 * 33 * Any service wishing to provide SMS over IMS should extend this class and implement all methods 34 * that the service supports. 35 * 36 * @hide 37 */ 38 @SystemApi 39 public class ImsSmsImplBase { 40 private static final String LOG_TAG = "SmsImplBase"; 41 42 /** @hide */ 43 @IntDef({ 44 SEND_STATUS_OK, 45 SEND_STATUS_ERROR, 46 SEND_STATUS_ERROR_RETRY, 47 SEND_STATUS_ERROR_FALLBACK 48 }) 49 @Retention(RetentionPolicy.SOURCE) 50 public @interface SendStatusResult {} 51 /** 52 * Message was sent successfully. 53 */ 54 public static final int SEND_STATUS_OK = 1; 55 56 /** 57 * IMS provider failed to send the message and platform should not retry falling back to sending 58 * the message using the radio. 59 */ 60 public static final int SEND_STATUS_ERROR = 2; 61 62 /** 63 * IMS provider failed to send the message and platform should retry again after setting TP-RD 64 * bit to high. 65 */ 66 public static final int SEND_STATUS_ERROR_RETRY = 3; 67 68 /** 69 * IMS provider failed to send the message and platform should retry falling back to sending 70 * the message using the radio. 71 */ 72 public static final int SEND_STATUS_ERROR_FALLBACK = 4; 73 74 /** @hide */ 75 @IntDef({ 76 DELIVER_STATUS_OK, 77 DELIVER_STATUS_ERROR_GENERIC, 78 DELIVER_STATUS_ERROR_NO_MEMORY, 79 DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED 80 }) 81 @Retention(RetentionPolicy.SOURCE) 82 public @interface DeliverStatusResult {} 83 /** 84 * Message was delivered successfully. 85 */ 86 public static final int DELIVER_STATUS_OK = 1; 87 88 /** 89 * Message was not delivered. 90 */ 91 public static final int DELIVER_STATUS_ERROR_GENERIC = 2; 92 93 /** 94 * Message was not delivered due to lack of memory. 95 */ 96 public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3; 97 98 /** 99 * Message was not delivered as the request is not supported. 100 */ 101 public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4; 102 103 /** @hide */ 104 @IntDef({ 105 STATUS_REPORT_STATUS_OK, 106 STATUS_REPORT_STATUS_ERROR 107 }) 108 @Retention(RetentionPolicy.SOURCE) 109 public @interface StatusReportResult {} 110 111 /** 112 * Status Report was set successfully. 113 */ 114 public static final int STATUS_REPORT_STATUS_OK = 1; 115 116 /** 117 * Error while setting status report. 118 */ 119 public static final int STATUS_REPORT_STATUS_ERROR = 2; 120 121 // Lock for feature synchronization 122 private final Object mLock = new Object(); 123 private IImsSmsListener mListener; 124 125 /** 126 * Registers a listener responsible for handling tasks like delivering messages. 127 * 128 * @param listener listener to register. 129 * 130 * @hide 131 */ registerSmsListener(IImsSmsListener listener)132 public final void registerSmsListener(IImsSmsListener listener) { 133 synchronized (mLock) { 134 mListener = listener; 135 } 136 } 137 138 /** 139 * This method will be triggered by the platform when the user attempts to send an SMS. This 140 * method should be implemented by the IMS providers to provide implementation of sending an SMS 141 * over IMS. 142 * 143 * @param token unique token generated by the platform that should be used when triggering 144 * callbacks for this specific message. 145 * @param messageRef the message reference. 146 * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and 147 * {@link SmsMessage#FORMAT_3GPP2}. 148 * @param smsc the Short Message Service Center address. 149 * @param isRetry whether it is a retry of an already attempted message or not. 150 * @param pdu PDUs representing the contents of the message. 151 */ sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, byte[] pdu)152 public void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, 153 byte[] pdu) { 154 // Base implementation returns error. Should be overridden. 155 try { 156 onSendSmsResult(token, messageRef, SEND_STATUS_ERROR, 157 SmsManager.RESULT_ERROR_GENERIC_FAILURE); 158 } catch (RuntimeException e) { 159 Log.e(LOG_TAG, "Can not send sms: " + e.getMessage()); 160 } 161 } 162 163 /** 164 * This method will be triggered by the platform after 165 * {@link #onSmsReceived(int, String, byte[])} has been called to deliver the result to the IMS 166 * provider. 167 * 168 * @param token token provided in {@link #onSmsReceived(int, String, byte[])} 169 * @param result result of delivering the message. Valid values are: 170 * {@link #DELIVER_STATUS_OK}, 171 * {@link #DELIVER_STATUS_ERROR_GENERIC}, 172 * {@link #DELIVER_STATUS_ERROR_NO_MEMORY}, 173 * {@link #DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED} 174 * @param messageRef the message reference 175 */ acknowledgeSms(int token, @DeliverStatusResult int messageRef, int result)176 public void acknowledgeSms(int token, @DeliverStatusResult int messageRef, int result) { 177 Log.e(LOG_TAG, "acknowledgeSms() not implemented."); 178 } 179 180 /** 181 * This method will be triggered by the platform after 182 * {@link #onSmsStatusReportReceived(int, int, String, byte[])} has been called to provide the 183 * result to the IMS provider. 184 * 185 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} 186 * @param result result of delivering the message. Valid values are: 187 * {@link #STATUS_REPORT_STATUS_OK}, 188 * {@link #STATUS_REPORT_STATUS_ERROR} 189 * @param messageRef the message reference 190 */ acknowledgeSmsReport(int token, int messageRef, @StatusReportResult int result)191 public void acknowledgeSmsReport(int token, int messageRef, @StatusReportResult int result) { 192 Log.e(LOG_TAG, "acknowledgeSmsReport() not implemented."); 193 } 194 195 /** 196 * This method should be triggered by the IMS providers when there is an incoming message. The 197 * platform will deliver the message to the messages database and notify the IMS provider of the 198 * result by calling {@link #acknowledgeSms(int, int, int)}. 199 * 200 * This method must not be called before {@link #onReady()} is called or the call will fail. If 201 * the platform is not available, {@link #acknowledgeSms(int, int, int)} will be called with the 202 * {@link #DELIVER_STATUS_ERROR_GENERIC} result code. 203 * @param token unique token generated by IMS providers that the platform will use to trigger 204 * callbacks for this message. 205 * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and 206 * {@link SmsMessage#FORMAT_3GPP2}. 207 * @param pdu PDUs representing the contents of the message. 208 * @throws RuntimeException if called before {@link #onReady()} is triggered. 209 */ onSmsReceived(int token, String format, byte[] pdu)210 public final void onSmsReceived(int token, String format, byte[] pdu) throws RuntimeException { 211 synchronized (mLock) { 212 if (mListener == null) { 213 throw new RuntimeException("Feature not ready."); 214 } 215 try { 216 mListener.onSmsReceived(token, format, pdu); 217 } catch (RemoteException e) { 218 Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage()); 219 SmsMessage message = SmsMessage.createFromPdu(pdu, format); 220 if (message != null && message.mWrappedSmsMessage != null) { 221 acknowledgeSms(token, message.mWrappedSmsMessage.mMessageRef, 222 DELIVER_STATUS_ERROR_GENERIC); 223 } else { 224 Log.w(LOG_TAG, "onSmsReceived: Invalid pdu entered."); 225 acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC); 226 } 227 } 228 } 229 } 230 231 /** 232 * This method should be triggered by the IMS providers to pass the result of the sent message 233 * to the platform. 234 * 235 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} 236 * @param messageRef the message reference. Should be between 0 and 255 per TS.123.040 237 * @param status result of sending the SMS. Valid values are: 238 * {@link #SEND_STATUS_OK}, 239 * {@link #SEND_STATUS_ERROR}, 240 * {@link #SEND_STATUS_ERROR_RETRY}, 241 * {@link #SEND_STATUS_ERROR_FALLBACK}, 242 * @param reason reason in case status is failure. Valid values are: 243 * {@link SmsManager#RESULT_ERROR_NONE}, 244 * {@link SmsManager#RESULT_ERROR_GENERIC_FAILURE}, 245 * {@link SmsManager#RESULT_ERROR_RADIO_OFF}, 246 * {@link SmsManager#RESULT_ERROR_NULL_PDU}, 247 * {@link SmsManager#RESULT_ERROR_NO_SERVICE}, 248 * {@link SmsManager#RESULT_ERROR_LIMIT_EXCEEDED}, 249 * {@link SmsManager#RESULT_ERROR_FDN_CHECK_FAILURE}, 250 * {@link SmsManager#RESULT_ERROR_SHORT_CODE_NOT_ALLOWED}, 251 * {@link SmsManager#RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED}, 252 * {@link SmsManager#RESULT_RADIO_NOT_AVAILABLE}, 253 * {@link SmsManager#RESULT_NETWORK_REJECT}, 254 * {@link SmsManager#RESULT_INVALID_ARGUMENTS}, 255 * {@link SmsManager#RESULT_INVALID_STATE}, 256 * {@link SmsManager#RESULT_NO_MEMORY}, 257 * {@link SmsManager#RESULT_INVALID_SMS_FORMAT}, 258 * {@link SmsManager#RESULT_SYSTEM_ERROR}, 259 * {@link SmsManager#RESULT_MODEM_ERROR}, 260 * {@link SmsManager#RESULT_NETWORK_ERROR}, 261 * {@link SmsManager#RESULT_ENCODING_ERROR}, 262 * {@link SmsManager#RESULT_INVALID_SMSC_ADDRESS}, 263 * {@link SmsManager#RESULT_OPERATION_NOT_ALLOWED}, 264 * {@link SmsManager#RESULT_INTERNAL_ERROR}, 265 * {@link SmsManager#RESULT_NO_RESOURCES}, 266 * {@link SmsManager#RESULT_CANCELLED}, 267 * {@link SmsManager#RESULT_REQUEST_NOT_SUPPORTED} 268 * 269 * @throws RuntimeException if called before {@link #onReady()} is triggered or if the 270 * connection to the framework is not available. If this happens attempting to send the SMS 271 * should be aborted. 272 */ onSendSmsResult(int token, int messageRef, @SendStatusResult int status, int reason)273 public final void onSendSmsResult(int token, int messageRef, @SendStatusResult int status, 274 int reason) throws RuntimeException { 275 synchronized (mLock) { 276 if (mListener == null) { 277 throw new RuntimeException("Feature not ready."); 278 } 279 try { 280 mListener.onSendSmsResult(token, messageRef, status, reason); 281 } catch (RemoteException e) { 282 e.rethrowFromSystemServer(); 283 } 284 } 285 } 286 287 /** 288 * Sets the status report of the sent message. 289 * 290 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} 291 * @param messageRef the message reference. 292 * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and 293 * {@link SmsMessage#FORMAT_3GPP2}. 294 * @param pdu PDUs representing the content of the status report. 295 * @throws RuntimeException if called before {@link #onReady()} is triggered 296 */ onSmsStatusReportReceived(int token, int messageRef, String format, byte[] pdu)297 public final void onSmsStatusReportReceived(int token, int messageRef, String format, 298 byte[] pdu) throws RuntimeException{ 299 synchronized (mLock) { 300 if (mListener == null) { 301 throw new RuntimeException("Feature not ready."); 302 } 303 try { 304 mListener.onSmsStatusReportReceived(token, messageRef, format, pdu); 305 } catch (RemoteException e) { 306 Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage()); 307 acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR); 308 } 309 } 310 } 311 312 /** 313 * Returns the SMS format. Default is {@link SmsMessage#FORMAT_3GPP} unless overridden by IMS 314 * Provider. 315 * 316 * @return the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and 317 * {@link SmsMessage#FORMAT_3GPP2}. 318 */ getSmsFormat()319 public String getSmsFormat() { 320 return SmsMessage.FORMAT_3GPP; 321 } 322 323 /** 324 * Called when ImsSmsImpl has been initialized and communication with the framework is set up. 325 * Any attempt by this class to access the framework before this method is called will return 326 * with a {@link RuntimeException}. 327 */ onReady()328 public void onReady() { 329 // Base Implementation - Should be overridden 330 } 331 } 332