CarrierMessagingService.java revision b72eb97e4bca1e4fd68e79f9d04e9a6a15aebd21
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
17package android.service.carrier;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.annotation.SdkConstant;
22import android.app.Service;
23import android.content.Intent;
24import android.net.Uri;
25import android.os.IBinder;
26import android.os.Parcel;
27import android.os.Parcelable;
28import android.os.RemoteException;
29
30import java.util.ArrayList;
31import 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 * &lt;service android:name=".MyMessagingService"
41 *          android:label="&#64;string/service_name"
42 *          android:permission="android.permission.BIND_CARRIER_MESSAGING_SERVICE">
43 *     &lt;intent-filter>
44 *         &lt;action android:name="android.service.carrier.CarrierMessagingService" />
45 *     &lt;/intent-filter>
46 * &lt;/service></pre>
47 */
48public 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