• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.IntRange;
21 import android.annotation.SystemApi;
22 import android.os.RemoteException;
23 import android.telephony.SmsManager;
24 import android.telephony.SmsMessage;
25 import android.telephony.ims.aidl.IImsSmsListener;
26 import android.util.Log;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 
31 /**
32  * Base implementation for SMS over IMS.
33  *
34  * Any service wishing to provide SMS over IMS should extend this class and implement all methods
35  * that the service supports.
36  *
37  * @hide
38  */
39 @SystemApi
40 public class ImsSmsImplBase {
41     private static final String LOG_TAG = "SmsImplBase";
42 
43     /** @hide */
44     @IntDef({
45             SEND_STATUS_OK,
46             SEND_STATUS_ERROR,
47             SEND_STATUS_ERROR_RETRY,
48             SEND_STATUS_ERROR_FALLBACK
49         })
50     @Retention(RetentionPolicy.SOURCE)
51     public @interface SendStatusResult {}
52     /**
53      * Message was sent successfully.
54      */
55     public static final int SEND_STATUS_OK = 1;
56 
57     /**
58      * IMS provider failed to send the message and platform should not retry falling back to sending
59      * the message using the radio.
60      */
61     public static final int SEND_STATUS_ERROR = 2;
62 
63     /**
64      * IMS provider failed to send the message and platform should retry again after setting TP-RD
65      * bit to high.
66      */
67     public static final int SEND_STATUS_ERROR_RETRY = 3;
68 
69     /**
70      * IMS provider failed to send the message and platform should retry falling back to sending
71      * the message using the radio.
72      */
73     public static final int SEND_STATUS_ERROR_FALLBACK = 4;
74 
75     /** @hide */
76     @IntDef({
77             DELIVER_STATUS_OK,
78             DELIVER_STATUS_ERROR_GENERIC,
79             DELIVER_STATUS_ERROR_NO_MEMORY,
80             DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED
81         })
82     @Retention(RetentionPolicy.SOURCE)
83     public @interface DeliverStatusResult {}
84     /**
85      * Message was delivered successfully.
86      */
87     public static final int DELIVER_STATUS_OK = 1;
88 
89     /**
90      * Message was not delivered.
91      */
92     public static final int DELIVER_STATUS_ERROR_GENERIC = 2;
93 
94     /**
95      * Message was not delivered due to lack of memory.
96      */
97     public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3;
98 
99     /**
100      * Message was not delivered as the request is not supported.
101      */
102     public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4;
103 
104     /** @hide */
105     @IntDef({
106             STATUS_REPORT_STATUS_OK,
107             STATUS_REPORT_STATUS_ERROR
108         })
109     @Retention(RetentionPolicy.SOURCE)
110     public @interface StatusReportResult {}
111 
112     /**
113      * Status Report was set successfully.
114      */
115     public static final int STATUS_REPORT_STATUS_OK = 1;
116 
117     /**
118      * Error while setting status report.
119      */
120     public static final int STATUS_REPORT_STATUS_ERROR = 2;
121 
122     /**
123      * No network error was generated while processing the SMS message.
124      */
125     // Should match SmsResponse.NO_ERROR_CODE
126     public static final int RESULT_NO_NETWORK_ERROR = -1;
127 
128     // Lock for feature synchronization
129     private final Object mLock = new Object();
130     private IImsSmsListener mListener;
131 
132     /**
133      * Registers a listener responsible for handling tasks like delivering messages.
134      *
135      * @param listener listener to register.
136      *
137      * @hide
138      */
registerSmsListener(IImsSmsListener listener)139     public final void registerSmsListener(IImsSmsListener listener) {
140         synchronized (mLock) {
141             mListener = listener;
142         }
143     }
144 
145     /**
146      * This method will be triggered by the platform when the user attempts to send an SMS. This
147      * method should be implemented by the IMS providers to provide implementation of sending an SMS
148      * over IMS.
149      *
150      * @param token unique token generated by the platform that should be used when triggering
151      *             callbacks for this specific message.
152      * @param messageRef the message reference, which may be 1 byte if it is in
153      *     {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
154      *     {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
155      * @param format the format of the message.
156      * @param smsc the Short Message Service Center address.
157      * @param isRetry whether it is a retry of an already attempted message or not.
158      * @param pdu PDU representing the contents of the message.
159      */
sendSms(int token, @IntRange(from = 0, to = 65535) int messageRef, @SmsMessage.Format String format, String smsc, boolean isRetry, byte[] pdu)160     public void sendSms(int token, @IntRange(from = 0, to = 65535) int messageRef,
161             @SmsMessage.Format String format, String smsc, boolean isRetry,
162             byte[] pdu) {
163         // Base implementation returns error. Should be overridden.
164         try {
165             onSendSmsResult(token, messageRef, SEND_STATUS_ERROR,
166                     SmsManager.RESULT_ERROR_GENERIC_FAILURE);
167         } catch (RuntimeException e) {
168             Log.e(LOG_TAG, "Can not send sms: " + e.getMessage());
169         }
170     }
171 
172     /**
173      * This method will be triggered by the platform after
174      * {@link #onSmsReceived(int, String, byte[])} has been called to deliver the result to the IMS
175      * provider.
176      *
177      * @param token token provided in {@link #onSmsReceived(int, String, byte[])}
178      * @param messageRef the message reference, which may be 1 byte if it is in
179      *     {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
180      *     {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
181      * @param result result of delivering the message.
182      */
acknowledgeSms(int token, @IntRange(from = 0, to = 65535) int messageRef, @DeliverStatusResult int result)183     public void acknowledgeSms(int token, @IntRange(from = 0, to = 65535)  int messageRef,
184             @DeliverStatusResult int result) {
185         Log.e(LOG_TAG, "acknowledgeSms() not implemented.");
186     }
187 
188     /**
189      * This method will be triggered by the platform after
190      * {@link #onSmsStatusReportReceived(int, int, String, byte[])} or
191      * {@link #onSmsStatusReportReceived(int, String, byte[])} has been called to provide the
192      * result to the IMS provider.
193      *
194      * @param token token provided in {@link #onSmsStatusReportReceived(int, int, String, byte[])}
195      *              or {@link #onSmsStatusReportReceived(int, String, byte[])}
196      * @param messageRef the message reference, which may be 1 byte if it is in
197      *     {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
198      *     {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
199      * @param result result of delivering the message.
200      */
acknowledgeSmsReport(int token, @IntRange(from = 0, to = 65535) int messageRef, @StatusReportResult int result)201     public void acknowledgeSmsReport(int token, @IntRange(from = 0, to = 65535) int messageRef,
202             @StatusReportResult int result) {
203         Log.e(LOG_TAG, "acknowledgeSmsReport() not implemented.");
204     }
205 
206     /**
207      * This method should be triggered by the IMS providers when there is an incoming message. The
208      * platform will deliver the message to the messages database and notify the IMS provider of the
209      * result by calling {@link #acknowledgeSms(int, int, int)}.
210      *
211      * This method must not be called before {@link #onReady()} is called or the call will fail. If
212      * the platform is not available, {@link #acknowledgeSms(int, int, int)} will be called with the
213      * {@link #DELIVER_STATUS_ERROR_GENERIC} result code.
214      * @param token unique token generated by IMS providers that the platform will use to trigger
215      *              callbacks for this message.
216      * @param format the format of the message.
217      * @param pdu PDU representing the contents of the message.
218      * @throws RuntimeException if called before {@link #onReady()} is triggered.
219      */
onSmsReceived(int token, @SmsMessage.Format String format, byte[] pdu)220     public final void onSmsReceived(int token, @SmsMessage.Format String format, byte[] pdu)
221             throws RuntimeException {
222         IImsSmsListener listener = null;
223         synchronized (mLock) {
224             listener = mListener;
225         }
226 
227         if (listener == null) {
228             throw new RuntimeException("Feature not ready.");
229         }
230         try {
231             listener.onSmsReceived(token, format, pdu);
232         } catch (RemoteException e) {
233             Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage());
234             SmsMessage message = SmsMessage.createFromPdu(pdu, format);
235             if (message != null && message.mWrappedSmsMessage != null) {
236                 acknowledgeSms(token, message.mWrappedSmsMessage.mMessageRef,
237                         DELIVER_STATUS_ERROR_GENERIC);
238             } else {
239                 Log.w(LOG_TAG, "onSmsReceived: Invalid pdu entered.");
240                 acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC);
241             }
242         }
243     }
244 
245     /**
246      * This method should be triggered by the IMS providers when an outgoing SMS message has been
247      * sent successfully.
248      *
249      * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
250      * @param messageRef the message reference, which may be 1 byte if it is in
251      *     {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
252      *     {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
253      *
254      * @throws RuntimeException if called before {@link #onReady()} is triggered or if the
255      * connection to the framework is not available. If this happens attempting to send the SMS
256      * should be aborted.
257      */
onSendSmsResultSuccess(int token, @IntRange(from = 0, to = 65535) int messageRef)258     public final void onSendSmsResultSuccess(int token,
259             @IntRange(from = 0, to = 65535) int messageRef) throws RuntimeException {
260         IImsSmsListener listener = null;
261         synchronized (mLock) {
262             listener = mListener;
263         }
264 
265         if (listener == null) {
266             throw new RuntimeException("Feature not ready.");
267         }
268         try {
269             listener.onSendSmsResult(token, messageRef, SEND_STATUS_OK,
270                     SmsManager.RESULT_ERROR_NONE, RESULT_NO_NETWORK_ERROR);
271         } catch (RemoteException e) {
272             e.rethrowFromSystemServer();
273         }
274     }
275 
276     /**
277      * This method should be triggered by the IMS providers to pass the result of the sent message
278      * to the platform.
279      *
280      * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
281      * @param messageRef the message reference, which may be 1 byte if it is in
282      *     {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
283      *     {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
284      * @param status result of sending the SMS.
285      * @param reason reason in case status is failure.
286      *
287      * @throws RuntimeException if called before {@link #onReady()} is triggered or if the
288      * connection to the framework is not available. If this happens attempting to send the SMS
289      * should be aborted.
290      * @deprecated Use {@link #onSendSmsResultSuccess(int, int)} or
291      * {@link #onSendSmsResultError(int, int, int, int, int)} to notify the framework of the SMS
292      * send result.
293      */
294     @Deprecated
onSendSmsResult(int token, @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status, @SmsManager.Result int reason)295     public final void onSendSmsResult(int token, @IntRange(from = 0, to = 65535) int messageRef,
296             @SendStatusResult int status, @SmsManager.Result int reason) throws RuntimeException {
297         IImsSmsListener listener = null;
298         synchronized (mLock) {
299             listener = mListener;
300         }
301 
302         if (listener == null) {
303             throw new RuntimeException("Feature not ready.");
304         }
305         try {
306             listener.onSendSmsResult(token, messageRef, status, reason,
307                     RESULT_NO_NETWORK_ERROR);
308         } catch (RemoteException e) {
309             e.rethrowFromSystemServer();
310         }
311     }
312 
313     /**
314      * This method should be triggered by the IMS providers when an outgoing message fails to be
315      * sent due to an error generated while processing the message or after being sent to the
316      * network.
317      *
318      * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
319      * @param messageRef the message reference, which may be 1 byte if it is in
320      *     {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
321      *     {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
322      * @param status result of sending the SMS.
323      * @param networkErrorCode the error code reported by the carrier network if sending this SMS
324      *  has resulted in an error or {@link #RESULT_NO_NETWORK_ERROR} if no network error was
325      *  generated. See 3GPP TS 24.011 Section 7.3.4 for valid error codes and more information.
326      *
327      * @throws RuntimeException if called before {@link #onReady()} is triggered or if the
328      * connection to the framework is not available. If this happens attempting to send the SMS
329      * should be aborted.
330      */
onSendSmsResultError(int token, @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status, @SmsManager.Result int reason, int networkErrorCode)331     public final void onSendSmsResultError(int token,
332             @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status,
333             @SmsManager.Result int reason, int networkErrorCode) throws RuntimeException {
334         IImsSmsListener listener = null;
335         synchronized (mLock) {
336             listener = mListener;
337         }
338 
339         if (listener == null) {
340             throw new RuntimeException("Feature not ready.");
341         }
342         try {
343             listener.onSendSmsResult(token, messageRef, status, reason, networkErrorCode);
344         } catch (RemoteException e) {
345             e.rethrowFromSystemServer();
346         }
347     }
348 
349     /**
350      * This method should be triggered by the IMS providers when the status report of the sent
351      * message is received. The platform will handle the report and notify the IMS provider of the
352      * result by calling {@link #acknowledgeSmsReport(int, int, int)}.
353      *
354      * This method must not be called before {@link #onReady()} is called or the call will fail. If
355      * the platform is not available, {@link #acknowledgeSmsReport(int, int, int)} will be called
356      * with the {@link #STATUS_REPORT_STATUS_ERROR} result code.
357      * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
358      * @param messageRef the message reference, which may be 1 byte if it is in
359      *     {@link SmsMessage#FORMAT_3GPP} format or 2 bytes if it is in
360      *     {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
361      * @param format the format of the message.
362      * @param pdu PDU representing the content of the status report.
363      * @throws RuntimeException if called before {@link #onReady()} is triggered
364      *
365      * @deprecated Use {@link #onSmsStatusReportReceived(int, String, byte[])} instead without the
366      * message reference.
367      */
368     @Deprecated
onSmsStatusReportReceived(int token, @IntRange(from = 0, to = 65535) int messageRef, @SmsMessage.Format String format, byte[] pdu)369     public final void onSmsStatusReportReceived(int token,
370             @IntRange(from = 0, to = 65535) int messageRef, @SmsMessage.Format String format,
371             byte[] pdu) throws RuntimeException {
372         IImsSmsListener listener = null;
373         synchronized (mLock) {
374             listener = mListener;
375         }
376 
377         if (listener == null) {
378             throw new RuntimeException("Feature not ready.");
379         }
380         try {
381             listener.onSmsStatusReportReceived(token, format, pdu);
382         } catch (RemoteException e) {
383             Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
384             acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR);
385         }
386     }
387 
388     /**
389      * This method should be triggered by the IMS providers when the status report of the sent
390      * message is received. The platform will handle the report and notify the IMS provider of the
391      * result by calling {@link #acknowledgeSmsReport(int, int, int)}.
392      *
393      * This method must not be called before {@link #onReady()} is called or the call will fail. If
394      * the platform is not available, {@link #acknowledgeSmsReport(int, int, int)} will be called
395      * with the {@link #STATUS_REPORT_STATUS_ERROR} result code.
396      * @param token unique token generated by IMS providers that the platform will use to trigger
397      *              callbacks for this message.
398      * @param format the format of the message.
399      * @param pdu PDU representing the content of the status report.
400      * @throws RuntimeException if called before {@link #onReady()} is triggered
401      */
onSmsStatusReportReceived(int token, @SmsMessage.Format String format, byte[] pdu)402     public final void onSmsStatusReportReceived(int token, @SmsMessage.Format String format,
403             byte[] pdu) throws RuntimeException {
404         IImsSmsListener listener = null;
405         synchronized (mLock) {
406             listener = mListener;
407         }
408 
409         if (listener == null) {
410             throw new RuntimeException("Feature not ready.");
411         }
412         try {
413             listener.onSmsStatusReportReceived(token, format, pdu);
414         } catch (RemoteException e) {
415             Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
416             SmsMessage message = SmsMessage.createFromPdu(pdu, format);
417             if (message != null && message.mWrappedSmsMessage != null) {
418                 acknowledgeSmsReport(
419                         token,
420                         message.mWrappedSmsMessage.mMessageRef,
421                         STATUS_REPORT_STATUS_ERROR);
422             } else {
423                 Log.w(LOG_TAG, "onSmsStatusReportReceived: Invalid pdu entered.");
424                 acknowledgeSmsReport(token, 0, STATUS_REPORT_STATUS_ERROR);
425             }
426         }
427     }
428 
429     /**
430      * Returns the SMS format that the ImsService expects.
431      *
432      * @return  The expected format of the SMS messages.
433      */
getSmsFormat()434     public @SmsMessage.Format String getSmsFormat() {
435       return SmsMessage.FORMAT_3GPP;
436     }
437 
438     /**
439      * Called when ImsSmsImpl has been initialized and communication with the framework is set up.
440      * Any attempt by this class to access the framework before this method is called will return
441      * with a {@link RuntimeException}.
442      */
onReady()443     public void onReady() {
444         // Base Implementation - Should be overridden
445     }
446 }
447