blob: e7e0ec212839e8bc14276ad7c5ff2d8d66e23bef [file] [log] [blame]
Aurimas Liutikas88c7ff12023-08-10 12:42:26 -07001/*
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
17package android.telephony.ims.stub;
18
19import android.annotation.IntDef;
20import android.annotation.IntRange;
21import android.annotation.NonNull;
22import android.annotation.SystemApi;
23import android.os.RemoteException;
24import android.telephony.SmsManager;
25import android.telephony.SmsMessage;
26import android.telephony.ims.aidl.IImsSmsListener;
27import android.util.Log;
28
29import java.lang.annotation.Retention;
30import java.lang.annotation.RetentionPolicy;
31import java.util.concurrent.Executor;
32
33/**
34 * Base implementation for SMS over IMS.
35 *
36 * Any service wishing to provide SMS over IMS should extend this class and implement all methods
37 * that the service supports.
38 *
39 * @hide
40 */
41@SystemApi
42public class ImsSmsImplBase {
43 private static final String LOG_TAG = "SmsImplBase";
44
45 /** @hide */
46 @IntDef({
47 SEND_STATUS_OK,
48 SEND_STATUS_ERROR,
49 SEND_STATUS_ERROR_RETRY,
50 SEND_STATUS_ERROR_FALLBACK
51 })
52 @Retention(RetentionPolicy.SOURCE)
53 public @interface SendStatusResult {}
54 /**
55 * Message was sent successfully.
56 */
57 public static final int SEND_STATUS_OK = 1;
58
59 /**
60 * IMS provider failed to send the message and platform should not retry falling back to sending
61 * the message using the radio.
62 */
63 public static final int SEND_STATUS_ERROR = 2;
64
65 /**
66 * IMS provider failed to send the message and platform should retry again after setting TP-RD
67 * bit to high.
68 */
69 public static final int SEND_STATUS_ERROR_RETRY = 3;
70
71 /**
72 * IMS provider failed to send the message and platform should retry falling back to sending
73 * the message using the radio.
74 */
75 public static final int SEND_STATUS_ERROR_FALLBACK = 4;
76
77 /** @hide */
78 @IntDef({
79 DELIVER_STATUS_OK,
80 DELIVER_STATUS_ERROR_GENERIC,
81 DELIVER_STATUS_ERROR_NO_MEMORY,
82 DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED
83 })
84 @Retention(RetentionPolicy.SOURCE)
85 public @interface DeliverStatusResult {}
86 /**
87 * Message was delivered successfully.
88 */
89 public static final int DELIVER_STATUS_OK = 1;
90
91 /**
92 * Message was not delivered.
93 */
94 public static final int DELIVER_STATUS_ERROR_GENERIC = 2;
95
96 /**
97 * Message was not delivered due to lack of memory.
98 */
99 public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3;
100
101 /**
102 * Message was not delivered as the request is not supported.
103 */
104 public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4;
105
106 /** @hide */
107 @IntDef({
108 STATUS_REPORT_STATUS_OK,
109 STATUS_REPORT_STATUS_ERROR
110 })
111 @Retention(RetentionPolicy.SOURCE)
112 public @interface StatusReportResult {}
113
114 /**
115 * Status Report was set successfully.
116 */
117 public static final int STATUS_REPORT_STATUS_OK = 1;
118
119 /**
120 * Error while setting status report.
121 */
122 public static final int STATUS_REPORT_STATUS_ERROR = 2;
123
124 /**
125 * No network error was generated while processing the SMS message.
126 */
127 // Should match SmsResponse.NO_ERROR_CODE
128 public static final int RESULT_NO_NETWORK_ERROR = -1;
129
130 // Lock for feature synchronization
131 private final Object mLock = new Object();
132 private IImsSmsListener mListener;
133 private Executor mExecutor;
134
135 /**
136 * Create a new ImsSmsImplBase using the Executor set in MmTelFeature
137 */
138 public ImsSmsImplBase() {
139 }
140
141 /**
142 * Create a new ImsSmsImplBase with specified executor.
143 * <p>
144 * @param executor Default executor for ImsSmsImplBase
145 */
146 public ImsSmsImplBase(@NonNull Executor executor) {
147 mExecutor = executor;
148 }
149
150 /**
151 * Registers a listener responsible for handling tasks like delivering messages.
152 *
153 * @param listener listener to register.
154 *
155 * @hide
156 */
157 public final void registerSmsListener(IImsSmsListener listener) {
158 synchronized (mLock) {
159 mListener = listener;
160 }
161 }
162
163 /**
164 * This method will be triggered by the platform when the user attempts to send an SMS. This
165 * method should be implemented by the IMS providers to provide implementation of sending an SMS
166 * over IMS.
167 *
168 * @param token unique token generated by the platform that should be used when triggering
169 * callbacks for this specific message.
170 * @param messageRef the message reference, which may be 1 byte if it is in
171 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
172 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
173 * @param format the format of the message.
174 * @param smsc the Short Message Service Center address.
175 * @param isRetry whether it is a retry of an already attempted message or not.
176 * @param pdu PDU representing the contents of the message.
177 */
178 public void sendSms(int token, @IntRange(from = 0, to = 65535) int messageRef,
179 @SmsMessage.Format String format, String smsc, boolean isRetry,
180 byte[] pdu) {
181 // Base implementation returns error. Should be overridden.
182 try {
183 onSendSmsResult(token, messageRef, SEND_STATUS_ERROR,
184 SmsManager.RESULT_ERROR_GENERIC_FAILURE);
185 } catch (RuntimeException e) {
186 Log.e(LOG_TAG, "Can not send sms: " + e.getMessage());
187 }
188 }
189
190 /**
191 * This method will be triggered by the platform when memory becomes available to receive SMS
192 * after a memory full event. This method should be implemented by IMS providers to
193 * send RP-SMMA notification from SMS Relay Layer to server over IMS as per section 7.3.2 of
194 * TS 124.11. Once the RP-SMMA Notification is sent to the network. The network will deliver all
195 * the pending messages which failed due to Unavailability of Memory.
196 *
197 * @param token unique token generated in {@link ImsSmsDispatcher#onMemoryAvailable(void)} that
198 * should be used when triggering callbacks for this specific message.
199 *
200 * @hide
201 */
202 public void onMemoryAvailable(int token) {
203 // Base Implementation - Should be overridden
204 }
205
206 /**
207 * This method will be triggered by the platform after
208 * {@link #onSmsReceived(int, String, byte[])} has been called to deliver the result to the IMS
209 * provider.
210 *
211 * If the framework needs to provide the PDU used to acknowledge the SMS,
212 * {@link #acknowledgeSms(int, int, int, byte[])} will be called.
213 *
214 * @param token token provided in {@link #onSmsReceived(int, String, byte[])}
215 * @param messageRef the message reference, which may be 1 byte if it is in
216 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
217 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
218 * @param result result of delivering the message.
219 */
220 public void acknowledgeSms(int token, @IntRange(from = 0, to = 65535) int messageRef,
221 @DeliverStatusResult int result) {
222 Log.e(LOG_TAG, "acknowledgeSms() not implemented.");
223 }
224
225 /**
226 * This method will be called by the platform after
227 * {@link #onSmsReceived(int, String, byte[])} has been called to acknowledge an incoming SMS.
228 *
229 * This method is only called in cases where the framework needs to provide the PDU such as the
230 * case where we provide the Short Message Transfer Layer PDU (see 3GPP TS 23.040). Otherwise,
231 * {@link #acknowledgeSms(int, int, int)} will be used.
232 *
233 * @param token token provided in {@link #onSmsReceived(int, String, byte[])}
234 * @param messageRef the message reference, which may be 1 byte if it is in
235 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
236 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
237 * @param result result of delivering the message.
238 * @param pdu PDU representing the contents of the message.
239 */
240 public void acknowledgeSms(int token, @IntRange(from = 0, to = 65535) int messageRef,
241 @DeliverStatusResult int result, @NonNull byte[] pdu) {
242 Log.e(LOG_TAG, "acknowledgeSms() not implemented. acknowledgeSms(int, int, int) called.");
243 acknowledgeSms(token, messageRef, result);
244 }
245
246 /**
247 * This method will be triggered by the platform after
248 * {@link #onSmsStatusReportReceived(int, int, String, byte[])} or
249 * {@link #onSmsStatusReportReceived(int, String, byte[])} has been called to provide the
250 * result to the IMS provider.
251 *
252 * @param token token provided in {@link #onSmsStatusReportReceived(int, int, String, byte[])}
253 * or {@link #onSmsStatusReportReceived(int, String, byte[])}
254 * @param messageRef the message reference, which may be 1 byte if it is in
255 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
256 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
257 * @param result result of delivering the message.
258 */
259 public void acknowledgeSmsReport(int token, @IntRange(from = 0, to = 65535) int messageRef,
260 @StatusReportResult int result) {
261 Log.e(LOG_TAG, "acknowledgeSmsReport() not implemented.");
262 }
263
264 /**
265 * This method should be triggered by the IMS providers when there is an incoming message. The
266 * platform will deliver the message to the messages database and notify the IMS provider of the
267 * result by calling {@link #acknowledgeSms(int, int, int)}.
268 *
269 * This method must not be called before {@link #onReady()} is called or the call will fail. If
270 * the platform is not available, {@link #acknowledgeSms(int, int, int)} will be called with the
271 * {@link #DELIVER_STATUS_ERROR_GENERIC} result code.
272 * @param token unique token generated by IMS providers that the platform will use to trigger
273 * callbacks for this message.
274 * @param format the format of the message.
275 * @param pdu PDU representing the contents of the message.
276 * @throws RuntimeException if called before {@link #onReady()} is triggered.
277 */
278 public final void onSmsReceived(int token, @SmsMessage.Format String format, byte[] pdu)
279 throws RuntimeException {
280 IImsSmsListener listener = null;
281 synchronized (mLock) {
282 listener = mListener;
283 }
284
285 if (listener == null) {
286 throw new RuntimeException("Feature not ready.");
287 }
288 try {
289 listener.onSmsReceived(token, format, pdu);
290 } catch (RemoteException e) {
291 Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage());
292 SmsMessage message = SmsMessage.createFromPdu(pdu, format);
293 if (message != null && message.mWrappedSmsMessage != null) {
294 acknowledgeSms(token, message.mWrappedSmsMessage.mMessageRef,
295 DELIVER_STATUS_ERROR_GENERIC);
296 } else {
297 Log.w(LOG_TAG, "onSmsReceived: Invalid pdu entered.");
298 acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC);
299 }
300 }
301 }
302
303 /**
304 * This method should be triggered by the IMS providers when an outgoing SMS message has been
305 * sent successfully.
306 *
307 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
308 * @param messageRef the message reference, which may be 1 byte if it is in
309 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
310 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
311 *
312 * @throws RuntimeException if called before {@link #onReady()} is triggered or if the
313 * connection to the framework is not available. If this happens attempting to send the SMS
314 * should be aborted.
315 */
316 public final void onSendSmsResultSuccess(int token,
317 @IntRange(from = 0, to = 65535) int messageRef) throws RuntimeException {
318 IImsSmsListener listener = null;
319 synchronized (mLock) {
320 listener = mListener;
321 }
322
323 if (listener == null) {
324 throw new RuntimeException("Feature not ready.");
325 }
326 try {
327 listener.onSendSmsResult(token, messageRef, SEND_STATUS_OK,
328 SmsManager.RESULT_ERROR_NONE, RESULT_NO_NETWORK_ERROR);
329 } catch (RemoteException e) {
330 e.rethrowFromSystemServer();
331 }
332 }
333
334 /**
335 * This method should be triggered by the IMS providers to pass the result of the sent message
336 * to the platform.
337 *
338 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
339 * @param messageRef the message reference, which may be 1 byte if it is in
340 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
341 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
342 * @param status result of sending the SMS.
343 * @param reason reason in case status is failure.
344 *
345 * @throws RuntimeException if called before {@link #onReady()} is triggered or if the
346 * connection to the framework is not available. If this happens attempting to send the SMS
347 * should be aborted.
348 * @deprecated Use {@link #onSendSmsResultSuccess(int, int)} or
349 * {@link #onSendSmsResultError(int, int, int, int, int)} to notify the framework of the SMS
350 * send result.
351 */
352 @Deprecated
353 public final void onSendSmsResult(int token, @IntRange(from = 0, to = 65535) int messageRef,
354 @SendStatusResult int status, @SmsManager.Result int reason) throws RuntimeException {
355 IImsSmsListener listener = null;
356 synchronized (mLock) {
357 listener = mListener;
358 }
359
360 if (listener == null) {
361 throw new RuntimeException("Feature not ready.");
362 }
363 try {
364 listener.onSendSmsResult(token, messageRef, status, reason,
365 RESULT_NO_NETWORK_ERROR);
366 } catch (RemoteException e) {
367 e.rethrowFromSystemServer();
368 }
369 }
370
371 /**
372 * This method should be triggered by the IMS providers when an outgoing message fails to be
373 * sent due to an error generated while processing the message or after being sent to the
374 * network.
375 *
376 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
377 * @param messageRef the message reference, which may be 1 byte if it is in
378 * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
379 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
380 * @param status result of sending the SMS.
381 * @param networkErrorCode the error code reported by the carrier network if sending this SMS
382 * has resulted in an error or {@link #RESULT_NO_NETWORK_ERROR} if no network error was
383 * generated. See 3GPP TS 24.011 Section 7.3.4 for valid error codes and more information.
384 *
385 * @throws RuntimeException if called before {@link #onReady()} is triggered or if the
386 * connection to the framework is not available. If this happens attempting to send the SMS
387 * should be aborted.
388 */
389 public final void onSendSmsResultError(int token,
390 @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status,
391 @SmsManager.Result int reason, int networkErrorCode) throws RuntimeException {
392 IImsSmsListener listener = null;
393 synchronized (mLock) {
394 listener = mListener;
395 }
396
397 if (listener == null) {
398 throw new RuntimeException("Feature not ready.");
399 }
400 try {
401 listener.onSendSmsResult(token, messageRef, status, reason, networkErrorCode);
402 } catch (RemoteException e) {
403 e.rethrowFromSystemServer();
404 }
405 }
406
407 /**
408 * This API is used to report the result of sending
409 * RP-SMMA to framework based on received network responses(RP-ACK,
410 * RP-ERROR or SIP error).
411 *
412 * @param token provided in {@link #onMemoryAvailable()}.
413 * @param result based on RP-ACK or RP_ERROR
414 * @param networkErrorCode the error code reported by the carrier
415 * network if sending this SMS has resulted in an error or
416 * {@link #RESULT_NO_NETWORK_ERROR} if no network error was generated. See
417 * 3GPP TS 24.011 Section 7.3.4 for valid error codes and more
418 * information.
419 *
420 * @hide
421 */
422 public final void onMemoryAvailableResult(int token, @SendStatusResult int result,
423 int networkErrorCode) throws RuntimeException {
424 IImsSmsListener listener = null;
425 synchronized (mLock) {
426 listener = mListener;
427 }
428
429 if (listener == null) {
430 throw new RuntimeException("Feature not ready.");
431 }
432 try {
433 listener.onMemoryAvailableResult(token, result, networkErrorCode);
434 } catch (RemoteException e) {
435 e.rethrowFromSystemServer();
436 }
437 }
438
439 /**
440 * This method should be triggered by the IMS providers when the status report of the sent
441 * message is received. The platform will handle the report and notify the IMS provider of the
442 * result by calling {@link #acknowledgeSmsReport(int, int, int)}.
443 *
444 * This method must not be called before {@link #onReady()} is called or the call will fail. If
445 * the platform is not available, {@link #acknowledgeSmsReport(int, int, int)} will be called
446 * with the {@link #STATUS_REPORT_STATUS_ERROR} result code.
447 * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])}
448 * @param messageRef the message reference, which may be 1 byte if it is in
449 * {@link SmsMessage#FORMAT_3GPP} format or 2 bytes if it is in
450 * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
451 * @param format the format of the message.
452 * @param pdu PDU representing the content of the status report.
453 * @throws RuntimeException if called before {@link #onReady()} is triggered
454 *
455 * @deprecated Use {@link #onSmsStatusReportReceived(int, String, byte[])} instead without the
456 * message reference.
457 */
458 @Deprecated
459 public final void onSmsStatusReportReceived(int token,
460 @IntRange(from = 0, to = 65535) int messageRef, @SmsMessage.Format String format,
461 byte[] pdu) throws RuntimeException {
462 IImsSmsListener listener = null;
463 synchronized (mLock) {
464 listener = mListener;
465 }
466
467 if (listener == null) {
468 throw new RuntimeException("Feature not ready.");
469 }
470 try {
471 listener.onSmsStatusReportReceived(token, format, pdu);
472 } catch (RemoteException e) {
473 Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
474 acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR);
475 }
476 }
477
478 /**
479 * This method should be triggered by the IMS providers when the status report of the sent
480 * message is received. The platform will handle the report and notify the IMS provider of the
481 * result by calling {@link #acknowledgeSmsReport(int, int, int)}.
482 *
483 * This method must not be called before {@link #onReady()} is called or the call will fail. If
484 * the platform is not available, {@link #acknowledgeSmsReport(int, int, int)} will be called
485 * with the {@link #STATUS_REPORT_STATUS_ERROR} result code.
486 * @param token unique token generated by IMS providers that the platform will use to trigger
487 * callbacks for this message.
488 * @param format the format of the message.
489 * @param pdu PDU representing the content of the status report.
490 * @throws RuntimeException if called before {@link #onReady()} is triggered
491 */
492 public final void onSmsStatusReportReceived(int token, @SmsMessage.Format String format,
493 byte[] pdu) throws RuntimeException {
494 IImsSmsListener listener = null;
495 synchronized (mLock) {
496 listener = mListener;
497 }
498
499 if (listener == null) {
500 throw new RuntimeException("Feature not ready.");
501 }
502 try {
503 listener.onSmsStatusReportReceived(token, format, pdu);
504 } catch (RemoteException e) {
505 Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
506 SmsMessage message = SmsMessage.createFromPdu(pdu, format);
507 if (message != null && message.mWrappedSmsMessage != null) {
508 acknowledgeSmsReport(
509 token,
510 message.mWrappedSmsMessage.mMessageRef,
511 STATUS_REPORT_STATUS_ERROR);
512 } else {
513 Log.w(LOG_TAG, "onSmsStatusReportReceived: Invalid pdu entered.");
514 acknowledgeSmsReport(token, 0, STATUS_REPORT_STATUS_ERROR);
515 }
516 }
517 }
518
519 /**
520 * Returns the SMS format that the ImsService expects.
521 *
522 * @return The expected format of the SMS messages.
523 */
524 public @SmsMessage.Format String getSmsFormat() {
525 return SmsMessage.FORMAT_3GPP;
526 }
527
528 /**
529 * Called when ImsSmsImpl has been initialized and communication with the framework is set up.
530 * Any attempt by this class to access the framework before this method is called will return
531 * with a {@link RuntimeException}.
532 */
533 public void onReady() {
534 // Base Implementation - Should be overridden
535 }
536
537 /**
538 * Set default Executor for ImsSmsImplBase.
539 *
540 * @param executor The default executor for the framework to use when executing the methods
541 * overridden by the implementation of ImsSms.
542 * @hide
543 */
544 public final void setDefaultExecutor(@NonNull Executor executor) {
545 if (mExecutor == null) {
546 mExecutor = executor;
547 }
548 }
549
550 /**
551 * Get Executor from ImsSmsImplBase.
552 * If there is no settings for the executor, all ImsSmsImplBase method calls will use
553 * Runnable::run as default
554 *
555 * @return an Executor used to execute methods in ImsSms called remotely by the framework.
556 * @hide
557 */
558 public @NonNull Executor getExecutor() {
559 return mExecutor != null ? mExecutor : Runnable::run;
560 }
561}