1 /* 2 * Copyright (C) 2014 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.service.carrier; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SdkConstant; 22 import android.app.Service; 23 import android.content.Intent; 24 import android.net.Uri; 25 import android.os.IBinder; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.os.RemoteException; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 33 /** 34 * A service that receives calls from the system when new SMS and MMS are 35 * sent or received. 36 * <p>To extend this class, you must declare the service in your manifest file with 37 * the {@link android.Manifest.permission#BIND_CARRIER_MESSAGING_SERVICE} permission 38 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p> 39 * <pre> 40 * <service android:name=".MyMessagingService" 41 * android:label="@string/service_name" 42 * android:permission="android.permission.BIND_CARRIER_MESSAGING_SERVICE"> 43 * <intent-filter> 44 * <action android:name="android.service.carrier.CarrierMessagingService" /> 45 * </intent-filter> 46 * </service></pre> 47 */ 48 public abstract class CarrierMessagingService extends Service { 49 /** 50 * The {@link android.content.Intent} that must be declared as handled by the service. 51 */ 52 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) 53 public static final String SERVICE_INTERFACE 54 = "android.service.carrier.CarrierMessagingService"; 55 56 /** 57 * Indicates that an SMS or MMS message was successfully sent. 58 */ 59 public static final int SEND_STATUS_OK = 0; 60 61 /** 62 * SMS/MMS sending failed. We should retry via the carrier network. 63 */ 64 public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1; 65 66 /** 67 * SMS/MMS sending failed. We should not retry via the carrier network. 68 */ 69 public static final int SEND_STATUS_ERROR = 2; 70 71 /** 72 * Successfully downloaded an MMS message. 73 */ 74 public static final int DOWNLOAD_STATUS_OK = 0; 75 76 /** 77 * MMS downloading failed. We should retry via the carrier network. 78 */ 79 public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; 80 81 /** 82 * MMS downloading failed. We should not retry via the carrier network. 83 */ 84 public static final int DOWNLOAD_STATUS_ERROR = 2; 85 86 private final ICarrierMessagingWrapper mWrapper = new ICarrierMessagingWrapper(); 87 88 /** 89 * Override this method to filter inbound SMS messages. 90 * 91 * @param pdu the PDUs of the message 92 * @param format the format of the PDUs, typically "3gpp" or "3gpp2" 93 * @param destPort the destination port of a binary SMS, this will be -1 for text SMS 94 * @param subId SMS subscription ID of the SIM 95 * @param callback result callback. Call with {@code true} to keep an inbound SMS message and 96 * deliver to SMS apps, and {@code false} to drop the message. 97 */ 98 public void onFilterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort, 99 int subId, @NonNull ResultCallback<Boolean> callback) { 100 // optional 101 try { 102 callback.onReceiveResult(true); 103 } catch (RemoteException ex) { 104 } 105 } 106 107 /** 108 * Override this method to intercept text SMSs sent from the device. 109 * 110 * @param text the text to send 111 * @param subId SMS subscription ID of the SIM 112 * @param destAddress phone number of the recipient of the message 113 * @param callback result callback. Call with a {@link SendSmsResult}. 114 */ 115 public void onSendTextSms( 116 @NonNull String text, int subId, @NonNull String destAddress, 117 @NonNull ResultCallback<SendSmsResult> callback) { 118 // optional 119 try { 120 callback.onReceiveResult(new SendSmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 0)); 121 } catch (RemoteException ex) { 122 } 123 } 124 125 /** 126 * Override this method to intercept binary SMSs sent from the device. 127 * 128 * @param data the binary content 129 * @param subId SMS subscription ID of the SIM 130 * @param destAddress phone number of the recipient of the message 131 * @param destPort the destination port 132 * @param callback result callback. Call with a {@link SendSmsResult}. 133 */ 134 public void onSendDataSms(@NonNull byte[] data, int subId, 135 @NonNull String destAddress, int destPort, 136 @NonNull ResultCallback<SendSmsResult> callback) { 137 // optional 138 try { 139 callback.onReceiveResult(new SendSmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 0)); 140 } catch (RemoteException ex) { 141 } 142 } 143 144 /** 145 * Override this method to intercept long SMSs sent from the device. 146 * 147 * @param parts a {@link List} of the message parts 148 * @param subId SMS subscription ID of the SIM 149 * @param destAddress phone number of the recipient of the message 150 * @param callback result callback. Call with a {@link SendMultipartSmsResult}. 151 */ 152 public void onSendMultipartTextSms(@NonNull List<String> parts, 153 int subId, @NonNull String destAddress, 154 @NonNull ResultCallback<SendMultipartSmsResult> callback) { 155 // optional 156 try { 157 callback.onReceiveResult( 158 new SendMultipartSmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null)); 159 } catch (RemoteException ex) { 160 } 161 } 162 163 /** 164 * Override this method to intercept MMSs sent from the device. 165 * 166 * @param pduUri the content provider URI of the PDU to send 167 * @param subId SMS subscription ID of the SIM 168 * @param location the optional URI to send this MMS PDU. If this is {code null}, 169 * the PDU should be sent to the default MMSC URL. 170 * @param callback result callback. Call with a {@link SendMmsResult}. 171 */ 172 public void onSendMms(@NonNull Uri pduUri, int subId, 173 @Nullable Uri location, @NonNull ResultCallback<SendMmsResult> callback) { 174 // optional 175 try { 176 callback.onReceiveResult(new SendMmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null)); 177 } catch (RemoteException ex) { 178 } 179 } 180 181 /** 182 * Override this method to download MMSs received. 183 * 184 * @param contentUri the content provider URI of the PDU to be downloaded. 185 * @param subId SMS subscription ID of the SIM 186 * @param location the URI of the message to be downloaded. 187 * @param callback result callback. Call with a status code which is one of 188 * {@link #DOWNLOAD_STATUS_OK}, 189 * {@link #DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK}, or {@link #DOWNLOAD_STATUS_ERROR}. 190 */ 191 public void onDownloadMms(@NonNull Uri contentUri, int subId, @NonNull Uri location, 192 @NonNull ResultCallback<Integer> callback) { 193 // optional 194 try { 195 callback.onReceiveResult(DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK); 196 } catch (RemoteException ex) { 197 } 198 } 199 200 @Override 201 public @Nullable IBinder onBind(@NonNull Intent intent) { 202 if (!SERVICE_INTERFACE.equals(intent.getAction())) { 203 return null; 204 } 205 return mWrapper; 206 } 207 208 /** 209 * The result of sending an MMS. 210 */ 211 public static final class SendMmsResult { 212 private int mSendStatus; 213 private byte[] mSendConfPdu; 214 215 /** 216 * Constructs a SendMmsResult with the MMS send result, and the SendConf PDU. 217 * 218 * @param sendStatus send status, one of {@link #SEND_STATUS_OK}, 219 * {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and 220 * {@link #SEND_STATUS_ERROR} 221 * @param sendConfPdu a possibly {code null} SendConf PDU, which confirms that the message 222 * was sent. sendConfPdu is ignored if the {@code result} is not 223 * {@link #SEND_STATUS_OK}. 224 */ 225 public SendMmsResult(int sendStatus, @Nullable byte[] sendConfPdu) { 226 mSendStatus = sendStatus; 227 mSendConfPdu = sendConfPdu; 228 } 229 230 /** 231 * Returns the send status of the just-sent MMS. 232 * 233 * @return the send status which is one of {@link #SEND_STATUS_OK}, 234 * {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and {@link #SEND_STATUS_ERROR} 235 */ 236 public int getSendStatus() { 237 return mSendStatus; 238 } 239 240 /** 241 * Returns the SendConf PDU, which confirms that the message was sent. 242 * 243 * @return the SendConf PDU 244 */ 245 public @Nullable byte[] getSendConfPdu() { 246 return mSendConfPdu; 247 } 248 } 249 250 /** 251 * The result of sending an SMS. 252 */ 253 public static final class SendSmsResult { 254 private final int mSendStatus; 255 private final int mMessageRef; 256 257 /** 258 * Constructs a SendSmsResult with the send status and message reference for the 259 * just-sent SMS. 260 * 261 * @param sendStatus send status, one of {@link #SEND_STATUS_OK}, 262 * {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and {@link #SEND_STATUS_ERROR}. 263 * @param messageRef message reference of the just-sent SMS. This field is applicable only 264 * if send status is {@link #SEND_STATUS_OK}. 265 */ 266 public SendSmsResult(int sendStatus, int messageRef) { 267 mSendStatus = sendStatus; 268 mMessageRef = messageRef; 269 } 270 271 /** 272 * Returns the message reference of the just-sent SMS. 273 * 274 * @return the message reference 275 */ 276 public int getMessageRef() { 277 return mMessageRef; 278 } 279 280 /** 281 * Returns the send status of the just-sent SMS. 282 * 283 * @return the send status 284 */ 285 public int getSendStatus() { 286 return mSendStatus; 287 } 288 } 289 290 /** 291 * The result of sending a multipart SMS. 292 */ 293 public static final class SendMultipartSmsResult { 294 private final int mSendStatus; 295 private final int[] mMessageRefs; 296 297 /** 298 * Constructs a SendMultipartSmsResult with the send status and message references for the 299 * just-sent multipart SMS. 300 * 301 * @param sendStatus send status, one of {@link #SEND_STATUS_OK}, 302 * {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and {@link #SEND_STATUS_ERROR}. 303 * @param messageRefs an array of message references, one for each part of the 304 * multipart SMS. This field is applicable only if send status is 305 * {@link #SEND_STATUS_OK}. 306 */ 307 public SendMultipartSmsResult(int sendStatus, @Nullable int[] messageRefs) { 308 mSendStatus = sendStatus; 309 mMessageRefs = messageRefs; 310 } 311 312 /** 313 * Returns the message references of the just-sent multipart SMS. 314 * 315 * @return the message references, one for each part of the multipart SMS 316 */ 317 public @Nullable int[] getMessageRefs() { 318 return mMessageRefs; 319 } 320 321 /** 322 * Returns the send status of the just-sent SMS. 323 * 324 * @return the send status 325 */ 326 public int getSendStatus() { 327 return mSendStatus; 328 } 329 } 330 331 /** 332 * A callback interface used to provide results asynchronously. 333 */ 334 public interface ResultCallback<T> { 335 /** 336 * Invoked when the result is available. 337 * 338 * @param result the result 339 */ 340 public void onReceiveResult(@NonNull T result) throws RemoteException; 341 }; 342 343 /** 344 * A wrapper around ICarrierMessagingService to enable the carrier messaging app to implement 345 * methods it cares about in the {@link ICarrierMessagingService} interface. 346 */ 347 private class ICarrierMessagingWrapper extends ICarrierMessagingService.Stub { 348 @Override 349 public void filterSms(MessagePdu pdu, String format, int destPort, 350 int subId, final ICarrierMessagingCallback callback) { 351 onFilterSms(pdu, format, destPort, subId, new ResultCallback<Boolean>() { 352 @Override 353 public void onReceiveResult(final Boolean result) throws RemoteException { 354 callback.onFilterComplete(result); 355 } 356 }); 357 } 358 359 @Override 360 public void sendTextSms(String text, int subId, String destAddress, 361 final ICarrierMessagingCallback callback) { 362 onSendTextSms(text, subId, destAddress, new ResultCallback<SendSmsResult>() { 363 @Override 364 public void onReceiveResult(final SendSmsResult result) throws RemoteException { 365 callback.onSendSmsComplete(result.getSendStatus(), result.getMessageRef()); 366 } 367 }); 368 } 369 370 @Override 371 public void sendDataSms(byte[] data, int subId, String destAddress, int destPort, 372 final ICarrierMessagingCallback callback) { 373 onSendDataSms(data, subId, destAddress, destPort, new ResultCallback<SendSmsResult>() { 374 @Override 375 public void onReceiveResult(final SendSmsResult result) throws RemoteException { 376 callback.onSendSmsComplete(result.getSendStatus(), result.getMessageRef()); 377 } 378 }); 379 } 380 381 @Override 382 public void sendMultipartTextSms(List<String> parts, int subId, String destAddress, 383 final ICarrierMessagingCallback callback) { 384 onSendMultipartTextSms(parts, subId, destAddress, 385 new ResultCallback<SendMultipartSmsResult>() { 386 @Override 387 public void onReceiveResult(final SendMultipartSmsResult result) 388 throws RemoteException { 389 callback.onSendMultipartSmsComplete( 390 result.getSendStatus(), result.getMessageRefs()); 391 } 392 }); 393 } 394 395 @Override 396 public void sendMms(Uri pduUri, int subId, Uri location, 397 final ICarrierMessagingCallback callback) { 398 onSendMms(pduUri, subId, location, new ResultCallback<SendMmsResult>() { 399 @Override 400 public void onReceiveResult(final SendMmsResult result) throws RemoteException { 401 callback.onSendMmsComplete(result.getSendStatus(), result.getSendConfPdu()); 402 } 403 }); 404 } 405 406 @Override 407 public void downloadMms(Uri pduUri, int subId, Uri location, 408 final ICarrierMessagingCallback callback) { 409 onDownloadMms(pduUri, subId, location, new ResultCallback<Integer>() { 410 @Override 411 public void onReceiveResult(Integer result) throws RemoteException { 412 callback.onDownloadMmsComplete(result); 413 } 414 }); 415 } 416 } 417 } 418