| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package android.telephony.ims.stub; |
| |
| import android.annotation.IntDef; |
| import android.annotation.IntRange; |
| import android.annotation.SystemApi; |
| import android.annotation.TestApi; |
| import android.os.RemoteException; |
| import android.telephony.SmsManager; |
| import android.telephony.SmsMessage; |
| import android.telephony.ims.aidl.IImsSmsListener; |
| import android.util.Log; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| |
| /** |
| * Base implementation for SMS over IMS. |
| * |
| * Any service wishing to provide SMS over IMS should extend this class and implement all methods |
| * that the service supports. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @TestApi |
| public class ImsSmsImplBase { |
| private static final String LOG_TAG = "SmsImplBase"; |
| |
| /** @hide */ |
| @IntDef({ |
| SEND_STATUS_OK, |
| SEND_STATUS_ERROR, |
| SEND_STATUS_ERROR_RETRY, |
| SEND_STATUS_ERROR_FALLBACK |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface SendStatusResult {} |
| /** |
| * Message was sent successfully. |
| */ |
| public static final int SEND_STATUS_OK = 1; |
| |
| /** |
| * IMS provider failed to send the message and platform should not retry falling back to sending |
| * the message using the radio. |
| */ |
| public static final int SEND_STATUS_ERROR = 2; |
| |
| /** |
| * IMS provider failed to send the message and platform should retry again after setting TP-RD |
| * bit to high. |
| */ |
| public static final int SEND_STATUS_ERROR_RETRY = 3; |
| |
| /** |
| * IMS provider failed to send the message and platform should retry falling back to sending |
| * the message using the radio. |
| */ |
| public static final int SEND_STATUS_ERROR_FALLBACK = 4; |
| |
| /** @hide */ |
| @IntDef({ |
| DELIVER_STATUS_OK, |
| DELIVER_STATUS_ERROR_GENERIC, |
| DELIVER_STATUS_ERROR_NO_MEMORY, |
| DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface DeliverStatusResult {} |
| /** |
| * Message was delivered successfully. |
| */ |
| public static final int DELIVER_STATUS_OK = 1; |
| |
| /** |
| * Message was not delivered. |
| */ |
| public static final int DELIVER_STATUS_ERROR_GENERIC = 2; |
| |
| /** |
| * Message was not delivered due to lack of memory. |
| */ |
| public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3; |
| |
| /** |
| * Message was not delivered as the request is not supported. |
| */ |
| public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4; |
| |
| /** @hide */ |
| @IntDef({ |
| STATUS_REPORT_STATUS_OK, |
| STATUS_REPORT_STATUS_ERROR |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface StatusReportResult {} |
| |
| /** |
| * Status Report was set successfully. |
| */ |
| public static final int STATUS_REPORT_STATUS_OK = 1; |
| |
| /** |
| * Error while setting status report. |
| */ |
| public static final int STATUS_REPORT_STATUS_ERROR = 2; |
| |
| /** |
| * No network error was generated while processing the SMS message. |
| */ |
| // Should match SmsResponse.NO_ERROR_CODE |
| public static final int RESULT_NO_NETWORK_ERROR = -1; |
| |
| // Lock for feature synchronization |
| private final Object mLock = new Object(); |
| private IImsSmsListener mListener; |
| |
| /** |
| * Registers a listener responsible for handling tasks like delivering messages. |
| * |
| * @param listener listener to register. |
| * |
| * @hide |
| */ |
| public final void registerSmsListener(IImsSmsListener listener) { |
| synchronized (mLock) { |
| mListener = listener; |
| } |
| } |
| |
| /** |
| * This method will be triggered by the platform when the user attempts to send an SMS. This |
| * method should be implemented by the IMS providers to provide implementation of sending an SMS |
| * over IMS. |
| * |
| * @param token unique token generated by the platform that should be used when triggering |
| * callbacks for this specific message. |
| * @param messageRef the message reference, which may be 1 byte if it is in |
| * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in |
| * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). |
| * @param format the format of the message. |
| * @param smsc the Short Message Service Center address. |
| * @param isRetry whether it is a retry of an already attempted message or not. |
| * @param pdu PDU representing the contents of the message. |
| */ |
| public void sendSms(int token, @IntRange(from = 0, to = 65535) int messageRef, |
| @SmsMessage.Format String format, String smsc, boolean isRetry, |
| byte[] pdu) { |
| // Base implementation returns error. Should be overridden. |
| try { |
| onSendSmsResult(token, messageRef, SEND_STATUS_ERROR, |
| SmsManager.RESULT_ERROR_GENERIC_FAILURE); |
| } catch (RuntimeException e) { |
| Log.e(LOG_TAG, "Can not send sms: " + e.getMessage()); |
| } |
| } |
| |
| /** |
| * This method will be triggered by the platform after |
| * {@link #onSmsReceived(int, String, byte[])} has been called to deliver the result to the IMS |
| * provider. |
| * |
| * @param token token provided in {@link #onSmsReceived(int, String, byte[])} |
| * @param messageRef the message reference, which may be 1 byte if it is in |
| * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in |
| * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). |
| * @param result result of delivering the message. |
| */ |
| public void acknowledgeSms(int token, @IntRange(from = 0, to = 65535) int messageRef, |
| @DeliverStatusResult int result) { |
| Log.e(LOG_TAG, "acknowledgeSms() not implemented."); |
| } |
| |
| /** |
| * This method will be triggered by the platform after |
| * {@link #onSmsStatusReportReceived(int, int, String, byte[])} or |
| * {@link #onSmsStatusReportReceived(int, String, byte[])} has been called to provide the |
| * result to the IMS provider. |
| * |
| * @param token token provided in {@link #onSmsStatusReportReceived(int, int, String, byte[])} |
| * or {@link #onSmsStatusReportReceived(int, String, byte[])} |
| * @param messageRef the message reference, which may be 1 byte if it is in |
| * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in |
| * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). |
| * @param result result of delivering the message. |
| */ |
| public void acknowledgeSmsReport(int token, @IntRange(from = 0, to = 65535) int messageRef, |
| @StatusReportResult int result) { |
| Log.e(LOG_TAG, "acknowledgeSmsReport() not implemented."); |
| } |
| |
| /** |
| * This method should be triggered by the IMS providers when there is an incoming message. The |
| * platform will deliver the message to the messages database and notify the IMS provider of the |
| * result by calling {@link #acknowledgeSms(int, int, int)}. |
| * |
| * This method must not be called before {@link #onReady()} is called or the call will fail. If |
| * the platform is not available, {@link #acknowledgeSms(int, int, int)} will be called with the |
| * {@link #DELIVER_STATUS_ERROR_GENERIC} result code. |
| * @param token unique token generated by IMS providers that the platform will use to trigger |
| * callbacks for this message. |
| * @param format the format of the message. |
| * @param pdu PDU representing the contents of the message. |
| * @throws RuntimeException if called before {@link #onReady()} is triggered. |
| */ |
| public final void onSmsReceived(int token, @SmsMessage.Format String format, byte[] pdu) |
| throws RuntimeException { |
| synchronized (mLock) { |
| if (mListener == null) { |
| throw new RuntimeException("Feature not ready."); |
| } |
| try { |
| mListener.onSmsReceived(token, format, pdu); |
| } catch (RemoteException e) { |
| Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage()); |
| SmsMessage message = SmsMessage.createFromPdu(pdu, format); |
| if (message != null && message.mWrappedSmsMessage != null) { |
| acknowledgeSms(token, message.mWrappedSmsMessage.mMessageRef, |
| DELIVER_STATUS_ERROR_GENERIC); |
| } else { |
| Log.w(LOG_TAG, "onSmsReceived: Invalid pdu entered."); |
| acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC); |
| } |
| } |
| } |
| } |
| |
| /** |
| * This method should be triggered by the IMS providers when an outgoing SMS message has been |
| * sent successfully. |
| * |
| * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} |
| * @param messageRef the message reference, which may be 1 byte if it is in |
| * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in |
| * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). |
| * |
| * @throws RuntimeException if called before {@link #onReady()} is triggered or if the |
| * connection to the framework is not available. If this happens attempting to send the SMS |
| * should be aborted. |
| */ |
| public final void onSendSmsResultSuccess(int token, |
| @IntRange(from = 0, to = 65535) int messageRef) throws RuntimeException { |
| synchronized (mLock) { |
| if (mListener == null) { |
| throw new RuntimeException("Feature not ready."); |
| } |
| try { |
| mListener.onSendSmsResult(token, messageRef, SEND_STATUS_OK, |
| SmsManager.RESULT_ERROR_NONE, RESULT_NO_NETWORK_ERROR); |
| } catch (RemoteException e) { |
| e.rethrowFromSystemServer(); |
| } |
| } |
| } |
| |
| /** |
| * This method should be triggered by the IMS providers to pass the result of the sent message |
| * to the platform. |
| * |
| * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} |
| * @param messageRef the message reference, which may be 1 byte if it is in |
| * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in |
| * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). |
| * @param status result of sending the SMS. |
| * @param reason reason in case status is failure. |
| * |
| * @throws RuntimeException if called before {@link #onReady()} is triggered or if the |
| * connection to the framework is not available. If this happens attempting to send the SMS |
| * should be aborted. |
| * @deprecated Use {@link #onSendSmsResultSuccess(int, int)} or |
| * {@link #onSendSmsResultError(int, int, int, int, int)} to notify the framework of the SMS |
| * send result. |
| */ |
| @Deprecated |
| public final void onSendSmsResult(int token, @IntRange(from = 0, to = 65535) int messageRef, |
| @SendStatusResult int status, @SmsManager.Result int reason) throws RuntimeException { |
| synchronized (mLock) { |
| if (mListener == null) { |
| throw new RuntimeException("Feature not ready."); |
| } |
| try { |
| mListener.onSendSmsResult(token, messageRef, status, reason, |
| RESULT_NO_NETWORK_ERROR); |
| } catch (RemoteException e) { |
| e.rethrowFromSystemServer(); |
| } |
| } |
| } |
| |
| /** |
| * This method should be triggered by the IMS providers when an outgoing message fails to be |
| * sent due to an error generated while processing the message or after being sent to the |
| * network. |
| * |
| * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} |
| * @param messageRef the message reference, which may be 1 byte if it is in |
| * {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in |
| * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). |
| * @param status result of sending the SMS. |
| * @param networkErrorCode the error code reported by the carrier network if sending this SMS |
| * has resulted in an error or {@link #RESULT_NO_NETWORK_ERROR} if no network error was |
| * generated. See 3GPP TS 24.011 Section 7.3.4 for valid error codes and more information. |
| * |
| * @throws RuntimeException if called before {@link #onReady()} is triggered or if the |
| * connection to the framework is not available. If this happens attempting to send the SMS |
| * should be aborted. |
| */ |
| public final void onSendSmsResultError(int token, |
| @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status, |
| @SmsManager.Result int reason, int networkErrorCode) throws RuntimeException { |
| synchronized (mLock) { |
| if (mListener == null) { |
| throw new RuntimeException("Feature not ready."); |
| } |
| try { |
| mListener.onSendSmsResult(token, messageRef, status, reason, networkErrorCode); |
| } catch (RemoteException e) { |
| e.rethrowFromSystemServer(); |
| } |
| } |
| } |
| |
| /** |
| * This method should be triggered by the IMS providers when the status report of the sent |
| * message is received. The platform will handle the report and notify the IMS provider of the |
| * result by calling {@link #acknowledgeSmsReport(int, int, int)}. |
| * |
| * This method must not be called before {@link #onReady()} is called or the call will fail. If |
| * the platform is not available, {@link #acknowledgeSmsReport(int, int, int)} will be called |
| * with the {@link #STATUS_REPORT_STATUS_ERROR} result code. |
| * @param token token provided in {@link #sendSms(int, int, String, String, boolean, byte[])} |
| * @param messageRef the message reference, which may be 1 byte if it is in |
| * {@link SmsMessage#FORMAT_3GPP} format or 2 bytes if it is in |
| * {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B). |
| * @param format the format of the message. |
| * @param pdu PDU representing the content of the status report. |
| * @throws RuntimeException if called before {@link #onReady()} is triggered |
| * |
| * @deprecated Use {@link #onSmsStatusReportReceived(int, String, byte[])} instead without the |
| * message reference. |
| */ |
| @Deprecated |
| public final void onSmsStatusReportReceived(int token, |
| @IntRange(from = 0, to = 65535) int messageRef, @SmsMessage.Format String format, |
| byte[] pdu) throws RuntimeException { |
| synchronized (mLock) { |
| if (mListener == null) { |
| throw new RuntimeException("Feature not ready."); |
| } |
| try { |
| mListener.onSmsStatusReportReceived(token, format, pdu); |
| } catch (RemoteException e) { |
| Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage()); |
| acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR); |
| } |
| } |
| } |
| |
| /** |
| * This method should be triggered by the IMS providers when the status report of the sent |
| * message is received. The platform will handle the report and notify the IMS provider of the |
| * result by calling {@link #acknowledgeSmsReport(int, int, int)}. |
| * |
| * This method must not be called before {@link #onReady()} is called or the call will fail. If |
| * the platform is not available, {@link #acknowledgeSmsReport(int, int, int)} will be called |
| * with the {@link #STATUS_REPORT_STATUS_ERROR} result code. |
| * @param token unique token generated by IMS providers that the platform will use to trigger |
| * callbacks for this message. |
| * @param format the format of the message. |
| * @param pdu PDU representing the content of the status report. |
| * @throws RuntimeException if called before {@link #onReady()} is triggered |
| */ |
| public final void onSmsStatusReportReceived(int token, @SmsMessage.Format String format, |
| byte[] pdu) throws RuntimeException { |
| synchronized (mLock) { |
| if (mListener == null) { |
| throw new RuntimeException("Feature not ready."); |
| } |
| try { |
| mListener.onSmsStatusReportReceived(token, format, pdu); |
| } catch (RemoteException e) { |
| Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage()); |
| SmsMessage message = SmsMessage.createFromPdu(pdu, format); |
| if (message != null && message.mWrappedSmsMessage != null) { |
| acknowledgeSmsReport( |
| token, |
| message.mWrappedSmsMessage.mMessageRef, |
| STATUS_REPORT_STATUS_ERROR); |
| } else { |
| Log.w(LOG_TAG, |
| "onSmsStatusReportReceivedWithoutMessageRef: Invalid pdu entered."); |
| acknowledgeSmsReport(token, 0, STATUS_REPORT_STATUS_ERROR); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns the SMS format that the ImsService expects. |
| * |
| * @return The expected format of the SMS messages. |
| */ |
| public @SmsMessage.Format String getSmsFormat() { |
| return SmsMessage.FORMAT_3GPP; |
| } |
| |
| /** |
| * Called when ImsSmsImpl has been initialized and communication with the framework is set up. |
| * Any attempt by this class to access the framework before this method is called will return |
| * with a {@link RuntimeException}. |
| */ |
| public void onReady() { |
| // Base Implementation - Should be overridden |
| } |
| } |