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.RemoteException;
27 
28 import java.util.List;
29 
30 /**
31  * A service that receives calls from the system when new SMS and MMS are
32  * sent or received.
33  * <p>To extend this class, you must declare the service in your manifest file with
34  * the {@link android.Manifest.permission#BIND_CARRIER_SERVICES} permission
35  * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
36  * <pre>
37  * &lt;service android:name=".MyMessagingService"
38  *          android:label="&#64;string/service_name"
39  *          android:permission="android.permission.BIND_CARRIER_SERVICES">
40  *     &lt;intent-filter>
41  *         &lt;action android:name="android.service.carrier.CarrierMessagingService" />
42  *     &lt;/intent-filter>
43  * &lt;/service></pre>
44  */
45 public abstract class CarrierMessagingService extends Service {
46     /**
47      * The {@link android.content.Intent} that must be declared as handled by the service.
48      */
49     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
50     public static final String SERVICE_INTERFACE
51             = "android.service.carrier.CarrierMessagingService";
52 
53     /**
54      * The default bitmask value passed to the callback of {@link #onReceiveTextSms} with all
55      * {@code RECEIVE_OPTIONS_x} flags cleared to indicate that the message should be kept and a
56      * new message notification should be shown.
57      *
58      * @see #RECEIVE_OPTIONS_DROP
59      * @see #RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE
60      */
61     public static final int RECEIVE_OPTIONS_DEFAULT = 0;
62 
63     /**
64      * Used to set the flag in the bitmask passed to the callback of {@link #onReceiveTextSms} to
65      * indicate that the inbound SMS should be dropped.
66      */
67     public static final int RECEIVE_OPTIONS_DROP = 0x1;
68 
69     /**
70      * Used to set the flag in the bitmask passed to the callback of {@link #onReceiveTextSms} to
71      * indicate that a new message notification should not be shown to the user when the
72      * credential-encrypted storage of the device is not available before the user unlocks the
73      * phone. It is only applicable to devices that support file-based encryption.
74      */
75     public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE = 0x2;
76 
77     /**
78      * Indicates that an SMS or MMS message was successfully sent.
79      */
80     public static final int SEND_STATUS_OK = 0;
81 
82     /**
83      * SMS/MMS sending failed. We should retry via the carrier network.
84      */
85     public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
86 
87     /**
88      * SMS/MMS sending failed. We should not retry via the carrier network.
89      */
90     public static final int SEND_STATUS_ERROR = 2;
91 
92     /**
93      * Successfully downloaded an MMS message.
94      */
95     public static final int DOWNLOAD_STATUS_OK = 0;
96 
97     /**
98      * MMS downloading failed. We should retry via the carrier network.
99      */
100     public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
101 
102     /**
103      * MMS downloading failed. We should not retry via the carrier network.
104      */
105     public static final int DOWNLOAD_STATUS_ERROR = 2;
106 
107     /**
108      * Flag to request SMS delivery status report.
109      */
110     public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1;
111 
112     private final ICarrierMessagingWrapper mWrapper = new ICarrierMessagingWrapper();
113 
114     /**
115      * Override this method to filter inbound SMS messages.
116      *
117      * @param pdu the PDUs of the message
118      * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
119      * @param destPort the destination port of a binary SMS, this will be -1 for text SMS
120      * @param subId SMS subscription ID of the SIM
121      * @param callback result callback. Call with {@code true} to keep an inbound SMS message and
122      *        deliver to SMS apps, and {@code false} to drop the message.
123      * @deprecated Use {@link #onReceiveTextSms} instead.
124      */
125     @Deprecated
onFilterSms(@onNull MessagePdu pdu, @NonNull String format, int destPort, int subId, @NonNull ResultCallback<Boolean> callback)126     public void onFilterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort,
127             int subId, @NonNull ResultCallback<Boolean> callback) {
128         // optional
129         try {
130             callback.onReceiveResult(true);
131         } catch (RemoteException ex) {
132         }
133     }
134 
135     /**
136      * Override this method to filter inbound SMS messages.
137      *
138      * <p>This method will be called once for every incoming text SMS. You can invoke the callback
139      * with a bitmask to tell the platform how to handle the SMS. For a SMS received on a
140      * file-based encryption capable device while the credential-encrypted storage is not available,
141      * this method will be called for the second time when the credential-encrypted storage becomes
142      * available after the user unlocks the phone, if the bit {@link #RECEIVE_OPTIONS_DROP} is not
143      * set when invoking the callback.
144      *
145      * @param pdu the PDUs of the message
146      * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
147      * @param destPort the destination port of a binary SMS, this will be -1 for text SMS
148      * @param subId SMS subscription ID of the SIM
149      * @param callback result callback. Call with a bitmask integer to indicate how the incoming
150      *        text SMS should be handled by the platform. Use {@link #RECEIVE_OPTIONS_DROP} and
151      *        {@link #RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE}
152      *        to set the flags in the bitmask.
153      */
onReceiveTextSms(@onNull MessagePdu pdu, @NonNull String format, int destPort, int subId, @NonNull final ResultCallback<Integer> callback)154     public void onReceiveTextSms(@NonNull MessagePdu pdu, @NonNull String format,
155             int destPort, int subId, @NonNull final ResultCallback<Integer> callback) {
156         onFilterSms(pdu, format, destPort, subId, new ResultCallback<Boolean>() {
157             @Override
158             public void onReceiveResult(Boolean result) throws RemoteException {
159                 callback.onReceiveResult(result ? RECEIVE_OPTIONS_DEFAULT : RECEIVE_OPTIONS_DROP
160                     | RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE);
161             }
162         });
163     }
164 
165     /**
166      * Override this method to intercept text SMSs sent from the device.
167      * @deprecated Override {@link #onSendTextSms} below instead.
168      *
169      * @param text the text to send
170      * @param subId SMS subscription ID of the SIM
171      * @param destAddress phone number of the recipient of the message
172      * @param callback result callback. Call with a {@link SendSmsResult}.
173      */
174     @Deprecated
onSendTextSms( @onNull String text, int subId, @NonNull String destAddress, @NonNull ResultCallback<SendSmsResult> callback)175     public void onSendTextSms(
176             @NonNull String text, int subId, @NonNull String destAddress,
177             @NonNull ResultCallback<SendSmsResult> callback) {
178         // optional
179         try {
180             callback.onReceiveResult(new SendSmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 0));
181         } catch (RemoteException ex) {
182         }
183     }
184 
185     /**
186      * Override this method to intercept text SMSs sent from the device.
187      *
188      * @param text the text to send
189      * @param subId SMS subscription ID of the SIM
190      * @param destAddress phone number of the recipient of the message
191      * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
192      *        {@link #SEND_FLAG_REQUEST_DELIVERY_STATUS}.
193      * @param callback result callback. Call with a {@link SendSmsResult}.
194      */
onSendTextSms( @onNull String text, int subId, @NonNull String destAddress, int sendSmsFlag, @NonNull ResultCallback<SendSmsResult> callback)195     public void onSendTextSms(
196             @NonNull String text, int subId, @NonNull String destAddress,
197             int sendSmsFlag, @NonNull ResultCallback<SendSmsResult> callback) {
198         // optional
199         onSendTextSms(text, subId, destAddress, callback);
200     }
201 
202     /**
203      * Override this method to intercept binary SMSs sent from the device.
204      * @deprecated Override {@link #onSendDataSms} below instead.
205      *
206      * @param data the binary content
207      * @param subId SMS subscription ID of the SIM
208      * @param destAddress phone number of the recipient of the message
209      * @param destPort the destination port
210      * @param callback result callback. Call with a {@link SendSmsResult}.
211      */
212     @Deprecated
onSendDataSms(@onNull byte[] data, int subId, @NonNull String destAddress, int destPort, @NonNull ResultCallback<SendSmsResult> callback)213     public void onSendDataSms(@NonNull byte[] data, int subId,
214             @NonNull String destAddress, int destPort,
215             @NonNull ResultCallback<SendSmsResult> callback) {
216         // optional
217         try {
218             callback.onReceiveResult(new SendSmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 0));
219         } catch (RemoteException ex) {
220         }
221     }
222 
223     /**
224      * Override this method to intercept binary SMSs sent from the device.
225      *
226      * @param data the binary content
227      * @param subId SMS subscription ID of the SIM
228      * @param destAddress phone number of the recipient of the message
229      * @param destPort the destination port
230      * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
231      *        {@link #SEND_FLAG_REQUEST_DELIVERY_STATUS}.
232      * @param callback result callback. Call with a {@link SendSmsResult}.
233      */
onSendDataSms(@onNull byte[] data, int subId, @NonNull String destAddress, int destPort, int sendSmsFlag, @NonNull ResultCallback<SendSmsResult> callback)234     public void onSendDataSms(@NonNull byte[] data, int subId,
235             @NonNull String destAddress, int destPort, int sendSmsFlag,
236             @NonNull ResultCallback<SendSmsResult> callback) {
237         // optional
238         onSendDataSms(data, subId, destAddress, destPort, callback);
239     }
240 
241     /**
242      * Override this method to intercept long SMSs sent from the device.
243      * @deprecated Override {@link #onSendMultipartTextSms} below instead.
244      *
245      * @param parts a {@link List} of the message parts
246      * @param subId SMS subscription ID of the SIM
247      * @param destAddress phone number of the recipient of the message
248      * @param callback result callback. Call with a {@link SendMultipartSmsResult}.
249      */
250     @Deprecated
onSendMultipartTextSms(@onNull List<String> parts, int subId, @NonNull String destAddress, @NonNull ResultCallback<SendMultipartSmsResult> callback)251     public void onSendMultipartTextSms(@NonNull List<String> parts,
252             int subId, @NonNull String destAddress,
253             @NonNull ResultCallback<SendMultipartSmsResult> callback) {
254         // optional
255         try {
256             callback.onReceiveResult(
257                     new SendMultipartSmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null));
258         } catch (RemoteException ex) {
259         }
260     }
261 
262     /**
263      * Override this method to intercept long SMSs sent from the device.
264      *
265      * @param parts a {@link List} of the message parts
266      * @param subId SMS subscription ID of the SIM
267      * @param destAddress phone number of the recipient of the message
268      * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
269      *        {@link #SEND_FLAG_REQUEST_DELIVERY_STATUS}.
270      * @param callback result callback. Call with a {@link SendMultipartSmsResult}.
271      */
onSendMultipartTextSms(@onNull List<String> parts, int subId, @NonNull String destAddress, int sendSmsFlag, @NonNull ResultCallback<SendMultipartSmsResult> callback)272     public void onSendMultipartTextSms(@NonNull List<String> parts,
273             int subId, @NonNull String destAddress, int sendSmsFlag,
274             @NonNull ResultCallback<SendMultipartSmsResult> callback) {
275         // optional
276         onSendMultipartTextSms(parts, subId, destAddress, callback);
277     }
278 
279     /**
280      * Override this method to intercept MMSs sent from the device.
281      *
282      * @param pduUri the content provider URI of the PDU to send
283      * @param subId SMS subscription ID of the SIM
284      * @param location the optional URI to send this MMS PDU. If this is {code null},
285      *        the PDU should be sent to the default MMSC URL.
286      * @param callback result callback. Call with a {@link SendMmsResult}.
287      */
onSendMms(@onNull Uri pduUri, int subId, @Nullable Uri location, @NonNull ResultCallback<SendMmsResult> callback)288     public void onSendMms(@NonNull Uri pduUri, int subId,
289             @Nullable Uri location, @NonNull ResultCallback<SendMmsResult> callback) {
290         // optional
291         try {
292             callback.onReceiveResult(new SendMmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null));
293         } catch (RemoteException ex) {
294         }
295     }
296 
297     /**
298      * Override this method to download MMSs received.
299      *
300      * @param contentUri the content provider URI of the PDU to be downloaded.
301      * @param subId SMS subscription ID of the SIM
302      * @param location the URI of the message to be downloaded.
303      * @param callback result callback. Call with a status code which is one of
304      *        {@link #DOWNLOAD_STATUS_OK},
305      *        {@link #DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK}, or {@link #DOWNLOAD_STATUS_ERROR}.
306      */
onDownloadMms(@onNull Uri contentUri, int subId, @NonNull Uri location, @NonNull ResultCallback<Integer> callback)307     public void onDownloadMms(@NonNull Uri contentUri, int subId, @NonNull Uri location,
308             @NonNull ResultCallback<Integer> callback) {
309         // optional
310         try {
311             callback.onReceiveResult(DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK);
312         } catch (RemoteException ex) {
313         }
314     }
315 
316     @Override
onBind(@onNull Intent intent)317     public @Nullable IBinder onBind(@NonNull Intent intent) {
318         if (!SERVICE_INTERFACE.equals(intent.getAction())) {
319             return null;
320         }
321         return mWrapper;
322     }
323 
324     /**
325      * The result of sending an MMS.
326      */
327     public static final class SendMmsResult {
328         private int mSendStatus;
329         private byte[] mSendConfPdu;
330 
331         /**
332          * Constructs a SendMmsResult with the MMS send result, and the SendConf PDU.
333          *
334          * @param sendStatus send status, one of {@link #SEND_STATUS_OK},
335          *        {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and
336          *        {@link #SEND_STATUS_ERROR}
337          * @param sendConfPdu a possibly {code null} SendConf PDU, which confirms that the message
338          *        was sent. sendConfPdu is ignored if the {@code result} is not
339          *        {@link #SEND_STATUS_OK}.
340          */
SendMmsResult(int sendStatus, @Nullable byte[] sendConfPdu)341         public SendMmsResult(int sendStatus, @Nullable byte[] sendConfPdu) {
342             mSendStatus = sendStatus;
343             mSendConfPdu = sendConfPdu;
344         }
345 
346         /**
347          * Returns the send status of the just-sent MMS.
348          *
349          * @return the send status which is one of {@link #SEND_STATUS_OK},
350          *         {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and {@link #SEND_STATUS_ERROR}
351          */
getSendStatus()352         public int getSendStatus() {
353             return mSendStatus;
354         }
355 
356         /**
357          * Returns the SendConf PDU, which confirms that the message was sent.
358          *
359          * @return the SendConf PDU
360          */
getSendConfPdu()361         public @Nullable byte[] getSendConfPdu() {
362             return mSendConfPdu;
363         }
364     }
365 
366     /**
367      * The result of sending an SMS.
368      */
369     public static final class SendSmsResult {
370         private final int mSendStatus;
371         private final int mMessageRef;
372 
373         /**
374          * Constructs a SendSmsResult with the send status and message reference for the
375          * just-sent SMS.
376          *
377          * @param sendStatus send status, one of {@link #SEND_STATUS_OK},
378          *        {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and {@link #SEND_STATUS_ERROR}.
379          * @param messageRef message reference of the just-sent SMS. This field is applicable only
380          *        if send status is {@link #SEND_STATUS_OK}.
381          */
SendSmsResult(int sendStatus, int messageRef)382         public SendSmsResult(int sendStatus, int messageRef) {
383             mSendStatus = sendStatus;
384             mMessageRef = messageRef;
385         }
386 
387         /**
388          * Returns the message reference of the just-sent SMS.
389          *
390          * @return the message reference
391          */
getMessageRef()392         public int getMessageRef() {
393             return mMessageRef;
394         }
395 
396         /**
397          * Returns the send status of the just-sent SMS.
398          *
399          * @return the send status
400          */
getSendStatus()401         public int getSendStatus() {
402             return mSendStatus;
403         }
404     }
405 
406     /**
407      * The result of sending a multipart SMS.
408      */
409     public static final class SendMultipartSmsResult {
410         private final int mSendStatus;
411         private final int[] mMessageRefs;
412 
413         /**
414          * Constructs a SendMultipartSmsResult with the send status and message references for the
415          * just-sent multipart SMS.
416          *
417          * @param sendStatus send status, one of {@link #SEND_STATUS_OK},
418          *        {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and {@link #SEND_STATUS_ERROR}.
419          * @param messageRefs an array of message references, one for each part of the
420          *        multipart SMS. This field is applicable only if send status is
421          *        {@link #SEND_STATUS_OK}.
422          */
SendMultipartSmsResult(int sendStatus, @Nullable int[] messageRefs)423         public SendMultipartSmsResult(int sendStatus, @Nullable int[] messageRefs) {
424             mSendStatus = sendStatus;
425             mMessageRefs = messageRefs;
426         }
427 
428         /**
429          * Returns the message references of the just-sent multipart SMS.
430          *
431          * @return the message references, one for each part of the multipart SMS
432          */
getMessageRefs()433         public @Nullable int[] getMessageRefs() {
434             return mMessageRefs;
435         }
436 
437         /**
438          * Returns the send status of the just-sent SMS.
439          *
440          * @return the send status
441          */
getSendStatus()442         public int getSendStatus() {
443             return mSendStatus;
444         }
445     }
446 
447     /**
448      * A callback interface used to provide results asynchronously.
449      */
450     public interface ResultCallback<T> {
451         /**
452          * Invoked when the result is available.
453          *
454          * @param result the result
455          */
onReceiveResult(@onNull T result)456         public void onReceiveResult(@NonNull T result) throws RemoteException;
457     };
458 
459     /**
460      * A wrapper around ICarrierMessagingService to enable the carrier messaging app to implement
461      * methods it cares about in the {@link ICarrierMessagingService} interface.
462      */
463     private class ICarrierMessagingWrapper extends ICarrierMessagingService.Stub {
464         @Override
filterSms(MessagePdu pdu, String format, int destPort, int subId, final ICarrierMessagingCallback callback)465         public void filterSms(MessagePdu pdu, String format, int destPort,
466                               int subId, final ICarrierMessagingCallback callback) {
467             onReceiveTextSms(pdu, format, destPort, subId,
468                 new ResultCallback<Integer>() {
469                     @Override
470                     public void onReceiveResult(Integer options) throws RemoteException {
471                         callback.onFilterComplete(options);
472                     }
473                 });
474         }
475 
476         @Override
sendTextSms(String text, int subId, String destAddress, int sendSmsFlag, final ICarrierMessagingCallback callback)477         public void sendTextSms(String text, int subId, String destAddress,
478                 int sendSmsFlag, final ICarrierMessagingCallback callback) {
479             onSendTextSms(text, subId, destAddress, sendSmsFlag,
480                     new ResultCallback<SendSmsResult>() {
481                     @Override
482                     public void onReceiveResult(final SendSmsResult result) throws RemoteException {
483                         callback.onSendSmsComplete(result.getSendStatus(), result.getMessageRef());
484                     }
485                 });
486         }
487 
488         @Override
sendDataSms(byte[] data, int subId, String destAddress, int destPort, int sendSmsFlag, final ICarrierMessagingCallback callback)489         public void sendDataSms(byte[] data, int subId, String destAddress, int destPort,
490                 int sendSmsFlag, final ICarrierMessagingCallback callback) {
491             onSendDataSms(data, subId, destAddress, destPort, sendSmsFlag,
492                     new ResultCallback<SendSmsResult>() {
493                     @Override
494                     public void onReceiveResult(final SendSmsResult result) throws RemoteException {
495                         callback.onSendSmsComplete(result.getSendStatus(), result.getMessageRef());
496                     }
497                 });
498         }
499 
500         @Override
sendMultipartTextSms(List<String> parts, int subId, String destAddress, int sendSmsFlag, final ICarrierMessagingCallback callback)501         public void sendMultipartTextSms(List<String> parts, int subId, String destAddress,
502                 int sendSmsFlag, final ICarrierMessagingCallback callback) {
503             onSendMultipartTextSms(parts, subId, destAddress, sendSmsFlag,
504                         new ResultCallback<SendMultipartSmsResult>() {
505                                 @Override
506                                 public void onReceiveResult(final SendMultipartSmsResult result)
507                                         throws RemoteException {
508                                     callback.onSendMultipartSmsComplete(
509                                             result.getSendStatus(), result.getMessageRefs());
510                                 }
511                             });
512         }
513 
514         @Override
sendMms(Uri pduUri, int subId, Uri location, final ICarrierMessagingCallback callback)515         public void sendMms(Uri pduUri, int subId, Uri location,
516                 final ICarrierMessagingCallback callback) {
517             onSendMms(pduUri, subId, location, new ResultCallback<SendMmsResult>() {
518                     @Override
519                     public void onReceiveResult(final SendMmsResult result) throws RemoteException {
520                         callback.onSendMmsComplete(result.getSendStatus(), result.getSendConfPdu());
521                     }
522                 });
523         }
524 
525         @Override
downloadMms(Uri pduUri, int subId, Uri location, final ICarrierMessagingCallback callback)526         public void downloadMms(Uri pduUri, int subId, Uri location,
527                 final ICarrierMessagingCallback callback) {
528             onDownloadMms(pduUri, subId, location, new ResultCallback<Integer>() {
529                     @Override
530                     public void onReceiveResult(Integer result) throws RemoteException {
531                         callback.onDownloadMmsComplete(result);
532                     }
533                 });
534         }
535     }
536 }
537