blob: 101f69b8001d6d5b5da914f6d0db807672ab715f [file] [log] [blame]
Cheuksan Wangf9c50c42014-10-21 15:58:23 -07001/*
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.carriermessaging;
18
19import android.annotation.Nullable;
20import android.annotation.SdkConstant;
21import android.app.Service;
22import android.content.Intent;
23import android.net.Uri;
24import android.os.IBinder;
25import android.os.Parcel;
26import android.os.Parcelable;
27import android.os.RemoteException;
28
29import java.util.List;
30
31/**
32 * A service that receives calls from the system when new SMS and MMS are
33 * sent or received.
34 * <p>To extend this class, you must declare the service in your manifest file with
35 * the {@link android.Manifest.permission#BIND_CARRIER_MESSAGING_SERVICE} permission
36 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
37 * <pre>
38 * &lt;service android:name=".MyMessagingService"
39 * android:label="&#64;string/service_name"
40 * android:permission="android.permission.BIND_CARRIER_MESSAGING_SERVICE">
41 * &lt;intent-filter>
42 * &lt;action android:name="android.service.carriermessaging.CarrierMessagingService" />
43 * &lt;/intent-filter>
44 * &lt;/service></pre>
45 */
46public abstract class CarrierMessagingService extends Service {
47 /**
48 * The {@link android.content.Intent} that must be declared as handled by the service.
49 */
50 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
51 public static final String SERVICE_INTERFACE
52 = "android.service.carriermessaging.CarrierMessagingService";
53
54 /**
55 * Indicates that an SMS or MMS message was successfully sent.
56 */
57 public static final int SEND_STATUS_OK = 0;
58
59 /**
60 * SMS/MMS sending failed. We should retry via the carrier network.
61 */
62 public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
63
64 /**
65 * SMS/MMS sending failed. We should not retry via the carrier network.
66 */
67 public static final int SEND_STATUS_ERROR = 2;
68
69 /**
70 * Successfully downloaded an MMS message.
71 */
72 public static final int DOWNLOAD_STATUS_OK = 0;
73
74 /**
75 * MMS downloading failed. We should retry via the carrier network.
76 */
77 public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
78
79 /**
80 * MMS downloading failed. We should not retry via the carrier network.
81 */
82 public static final int DOWNLOAD_STATUS_ERROR = 2;
83
84 private final ICarrierMessagingWrapper mWrapper = new ICarrierMessagingWrapper();
85
86 /**
87 * Implement this method to filter SMS messages.
88 *
89 * @param pdu the PDUs of the message
90 * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
91 * @param destPort the destination port of a binary SMS, this will be -1 for text SMS
92 *
93 * @return True to keep an inbound SMS message and delivered to SMS apps. False to
94 * drop the message.
95 */
96 public boolean onFilterSms(MessagePdu pdu, String format, int destPort) {
97 // optional
98 return true;
99 }
100
101 /**
102 * Implement this method to intercept text SMSs sent from the devcie.
103 *
104 * @param text the text to send
105 * @param format the format of the response PDU, typically "3gpp" or "3gpp2"
106 * @param destAddress phone number of the recipient of the message
107 *
108 * @return a {@link SendSmsResponse}.
109 */
110 public SendSmsResponse onSendTextSms(String text, String format, String destAddress) {
111 // optional
112 return null;
113 }
114
115 /**
116 * Implement this method to intercept binary SMSs sent from the device.
117 *
118 * @param data the binary content
119 * @param format format the format of the response PDU, typically "3gpp" or "3gpp2"
120 * @param destAddress phone number of the recipient of the message
121 * @param destPort the destination port
122 *
123 * @return a {@link SendSmsResponse}
124 */
125 public SendSmsResponse onSendDataSms(byte[] data, String format, String destAddress,
126 int destPort) {
127 // optional
128 return null;
129 }
130
131 /**
132 * Implement this method to intercept long SMSs sent from the device.
133 *
134 * @param parts a {@link List} of the message parts
135 * @param format format the format of the response PDU, typically "3gpp" or "3gpp2"
136 * @param destAddress phone number of the recipient of the message
137 *
138 * @return a {@link List} of {@link SendSmsResponse}, one for each message part.
139 */
140 public List<SendSmsResponse> onSendMultipartTextSms(List<String> parts, String format,
141 String destAddress) {
142 // optional
143 return null;
144 }
145
146 /**
147 * Implement this method to intercept MMSs sent from the device.
148 *
149 * @param pduUri the content provider URI of the PDU to send
150 * @param locationUrl the optional URL to send this MMS PDU. If this is not specified,
151 * the PDU should be sent to the default MMSC URL.
152 *
153 * @return a {@link SendMmsResult}.
154 */
155 public SendMmsResult onSendMms(Uri pduUri, @Nullable String locationUrl) {
156 // optional
157 return null;
158 }
159
160 /**
161 * Implement this method to download MMSs received.
162 *
163 * @param contentUri the content provider URI of the PDU to be downloaded.
164 * @param locationUrl the URL of the message to be downloaded.
165 *
166 * @return a {@link SendMmsResult}.
167 */
168 public int onDownloadMms(Uri contentUri, String locationUrl) {
169 // optional
170 return DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK;
171 }
172
173 @Override
174 public IBinder onBind(Intent intent) {
175 if (!SERVICE_INTERFACE.equals(intent.getAction())) {
176 return null;
177 }
178 return mWrapper;
179 }
180
181 /**
182 * The result of sending an MMS.
183 */
184 public static final class SendMmsResult {
185 private int mResult;
186 private byte[] mSendConfPdu;
187
188 public SendMmsResult(int result, byte[] sendConfPdu) {
189 mResult = result;
190 mSendConfPdu = sendConfPdu;
191 }
192
193 /**
194 * @return the result which is one of {@link #SEND_STATUS_OK},
195 * {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and {@link #SEND_STATUS_ERROR}
196 */
197 public int getResult() {
198 return mResult;
199 }
200
201 /**
202 * @return the SendConf PDU, which confirms that the message was sent.
203 */
204 public byte[] getSendConfPdu() {
205 return mSendConfPdu;
206 }
207 }
208
209 /**
210 * Object passed in callbacks upon successful completion of
211 * {@link ICarrierMessagingService#sendTextSms},
212 * {@link ICarrierMessagingService#sendDataSms}, and
213 * {@link ICarrierMessagingService#sendMultipartTextSms}.
214 * Contains message reference and ackPdu.
215 */
216 public static final class SendSmsResponse implements Parcelable {
217 private int mMessageRef;
218 private byte[] mAckPdu;
219 private int mErrorCode;
220
221 /**
222 * @param messageRef message reference of the just-sent SMS
223 * @param ackPdu ackPdu for the just-sent SMS
224 * @param errorCode error code. See 3GPP 27.005, 3.2.5 for GSM/UMTS,
225 * 3GPP2 N.S0005 (IS-41C) Table 171 for CDMA, -1 if unknown or not applicable.
226 */
227 public SendSmsResponse(int messageRef, byte[] ackPdu, int errorCode) {
228 mMessageRef = messageRef;
229 mAckPdu = ackPdu;
230 mErrorCode = errorCode;
231 }
232
233 /**
234 * Returns the message reference of the just-sent SMS.
235 *
236 * @return the message reference
237 */
238 public int getMessageRef() {
239 return mMessageRef;
240 }
241
242 /**
243 * Returns the ackPdu for the just-sent SMS.
244 *
245 * @return the ackPdu
246 */
247 public byte[] getAckPdu() {
248 return mAckPdu;
249 }
250
251 /**
252 * Returns the error code upon encountering an error while sending the SMS, -1 if unknown or
253 * not applicable.
254 *
255 * @return errorCode the errorCode as defined in 3GPP 27.005, 3.2.5 for GSM/UMTS, and 3GPP2
256 * N.S0005 (IS-41C) Table 171 for CDMA, -1 if unknown or not applicable.
257 */
258 public int getErrorCode() {
259 return mErrorCode;
260 }
261
262 @Override
263 public int describeContents() {
264 return 0;
265 }
266
267 @Override
268 public void writeToParcel(Parcel dest, int flags) {
269 dest.writeInt(mMessageRef);
270 dest.writeByteArray(mAckPdu);
271 dest.writeInt(mErrorCode);
272 }
273
274 public static final Parcelable.Creator<SendSmsResponse> CREATOR
275 = new Parcelable.Creator<SendSmsResponse>() {
276 @Override
277 public SendSmsResponse createFromParcel(Parcel source) {
278 return new SendSmsResponse(source.readInt(),
279 source.createByteArray(),
280 source.readInt());
281 }
282
283 @Override
284 public SendSmsResponse[] newArray(int size) {
285 return new SendSmsResponse[size];
286 }
287 };
288 }
289
290 /**
291 * A wrapper around ICarrierMessagingService to enable the carrier messaging APP to implement
292 * methods it cares about in the {@link ICarrierMessagingService} interface.
293 */
294 private class ICarrierMessagingWrapper extends ICarrierMessagingService.Stub {
295 @Override
296 public void filterSms(MessagePdu pdu, String format, int destPort,
297 ICarrierMessagingCallback callback) {
298 try {
299 callback.onFilterComplete(onFilterSms(pdu, format, destPort));
300 } catch (RemoteException ex) {
301 }
302 }
303
304 @Override
305 public void sendTextSms(String text, String format, String destAddress,
306 ICarrierMessagingCallback callback) {
307 try {
308 SendSmsResponse sendSmsResponse = onSendTextSms(text, format, destAddress);
309 if (sendSmsResponse == null) {
310 callback.onSendSmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
311 } else {
312 callback.onSendSmsComplete(SEND_STATUS_OK, sendSmsResponse);
313 }
314 } catch (RemoteException ex) {
315 }
316 }
317
318 @Override
319 public void sendDataSms(byte[] data, String format, String destAddress, int destPort,
320 ICarrierMessagingCallback callback) {
321 try {
322 SendSmsResponse sendSmsResponse = onSendDataSms(data, format, destAddress,
323 destPort);
324 if (sendSmsResponse == null) {
325 callback.onSendSmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
326 } else {
327 callback.onSendSmsComplete(SEND_STATUS_OK, sendSmsResponse);
328 }
329 } catch (RemoteException ex) {
330 }
331 }
332
333 @Override
334 public void sendMultipartTextSms(List<String> parts, String format, String destAddress,
335 ICarrierMessagingCallback callback) {
336 try {
337 List<SendSmsResponse> sendSmsResponses =
338 onSendMultipartTextSms(parts, format, destAddress);
339 if (sendSmsResponses == null) {
340 callback.onSendMultipartSmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
341 } else {
342 callback.onSendMultipartSmsComplete(SEND_STATUS_OK, sendSmsResponses);
343 }
344 } catch (RemoteException ex) {
345 }
346 }
347
348 @Override
349 public void sendMms(Uri pduUri, String locationUrl, ICarrierMessagingCallback callback) {
350 try {
351 SendMmsResult result = onSendMms(pduUri, locationUrl);
352 if (result == null) {
353 callback.onSendMmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
354 } else {
355 callback.onSendMmsComplete(SEND_STATUS_OK, result.getSendConfPdu());
356 }
357 } catch (RemoteException ex) {
358 }
359 }
360
361 @Override
362 public void downloadMms(Uri contentUri, String locationUrl,
363 ICarrierMessagingCallback callback) {
364 try {
365 callback.onDownloadMmsComplete(onDownloadMms(contentUri, locationUrl));
366 } catch (RemoteException ex) {
367 }
368 }
369 }
370}