Loading src/java/com/android/internal/telephony/IccSmsInterfaceManager.java +11 −1 Original line number Diff line number Diff line Loading @@ -473,7 +473,17 @@ public class IccSmsInterfaceManager { "\n format=" + format + "\n receivedIntent=" + receivedIntent); } mDispatchersController.injectSmsPdu(pdu, format, receivedIntent); mDispatchersController.injectSmsPdu(pdu, format, result -> { if (receivedIntent != null) { try { receivedIntent.send(result); } catch (PendingIntent.CanceledException e) { Rlog.d(LOG_TAG, "receivedIntent cancelled."); } } } ); } /** Loading src/java/com/android/internal/telephony/ImsSmsDispatcher.java +164 −6 Original line number Diff line number Diff line Loading @@ -16,25 +16,134 @@ package com.android.internal.telephony; import android.app.Activity; import android.os.RemoteException; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.provider.Telephony.Sms; import android.content.Intent; import android.telephony.Rlog; import com.android.ims.ImsException; import com.android.ims.ImsManager; import com.android.ims.internal.IImsSmsListener; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; import com.android.internal.telephony.util.SMSDispatcherUtil; import com.android.internal.telephony.gsm.SmsMessage; import android.telephony.ims.internal.SmsImplBase; import android.telephony.ims.internal.SmsImplBase.SendStatusResult; import android.telephony.ims.internal.SmsImplBase.StatusReportResult; import android.provider.Telephony.Sms.Intents; import android.util.Pair; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import libcore.util.Nullable; /** * Responsible for communications with {@link com.android.ims.ImsManager} to send/receive messages * over IMS. * * TODO: implement */ public class ImsSmsDispatcher extends SMSDispatcher { @VisibleForTesting public Map<Integer, SmsTracker> mTrackers = new ConcurrentHashMap<>(); @VisibleForTesting public AtomicInteger mNextToken = new AtomicInteger(); private final IImsSmsListener mImsSmsListener = new IImsSmsListener.Stub() { @Override public void onSendSmsResult(int token, int messageRef, @SendStatusResult int status, int reason) throws RemoteException { SmsTracker tracker = mTrackers.get(token); if (tracker == null) { throw new IllegalArgumentException("Invalid token."); } switch(reason) { case SmsImplBase.SEND_STATUS_OK: tracker.onSent(mContext); break; case SmsImplBase.SEND_STATUS_ERROR: tracker.onFailed(mContext, reason, 0 /* errorCode */); mTrackers.remove(token); break; case SmsImplBase.SEND_STATUS_ERROR_RETRY: tracker.mRetryCount += 1; sendSms(tracker); break; case SmsImplBase.SEND_STATUS_ERROR_FALLBACK: fallbackToPstn(token, tracker); break; default: } } /** {@inheritDoc} */ protected ImsSmsDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) { @Override public void onSmsStatusReportReceived(int token, int messageRef, String format, byte[] pdu) throws RemoteException { Rlog.d(TAG, "Status report received."); SmsTracker tracker = mTrackers.get(token); if (tracker == null) { throw new RemoteException("Invalid token."); } Pair<Boolean, Boolean> result = mSmsDispatchersController.handleSmsStatusReport( tracker, format, pdu); Rlog.d(TAG, "Status report handle result, success: " + result.first + "complete: " + result.second); try { getImsManager().acknowledgeSmsReport( token, messageRef, result.first ? SmsImplBase.STATUS_REPORT_STATUS_OK : SmsImplBase.STATUS_REPORT_STATUS_ERROR); } catch (ImsException e) { Rlog.e(TAG, "Failed to acknowledgeSmsReport(). Error: " + e.getMessage()); } if (result.second) { mTrackers.remove(token); } } @Override public void onSmsReceived(int token, String format, byte[] pdu) throws RemoteException { Rlog.d(TAG, "SMS received."); mSmsDispatchersController.injectSmsPdu(pdu, format, result -> { Rlog.d(TAG, "SMS handled result: " + result); try { getImsManager().acknowledgeSms(token, 0, result == Intents.RESULT_SMS_HANDLED ? SmsImplBase.STATUS_REPORT_STATUS_OK : SmsImplBase.DELIVER_STATUS_ERROR); } catch (ImsException e) { Rlog.e(TAG, "Failed to acknowledgeSms(). Error: " + e.getMessage()); } }); } }; public ImsSmsDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) { super(phone, smsDispatchersController); } public boolean isAvailable() { // TODO: implement return false; } @Override protected String getFormat() { return null; try { return getImsManager().getSmsFormat(); } catch (ImsException e) { Rlog.e(TAG, "Failed to get sms format. Error: " + e.getMessage()); return SmsConstants.FORMAT_UNKNOWN; } } @Override Loading Loading @@ -62,7 +171,56 @@ public class ImsSmsDispatcher extends SMSDispatcher { } @Override protected void sendSms(SmsTracker tracker) { public void sendSms(SmsTracker tracker) { Rlog.d(TAG, "sendSms: " + " mRetryCount=" + tracker.mRetryCount + " mMessageRef=" + tracker.mMessageRef + " SS=" + mPhone.getServiceState().getState()); HashMap<String, Object> map = tracker.getData(); byte[] pdu = (byte[]) map.get(MAP_KEY_PDU); byte smsc[] = (byte[]) map.get(MAP_KEY_SMSC); boolean isRetry = tracker.mRetryCount > 0; if (SmsConstants.FORMAT_3GPP.equals(getFormat()) && tracker.mRetryCount > 0) { // per TS 23.040 Section 9.2.3.6: If TP-MTI SMS-SUBMIT (0x01) type // TP-RD (bit 2) is 1 for retry // and TP-MR is set to previously failed sms TP-MR if (((0x01 & pdu[0]) == 0x01)) { pdu[0] |= 0x04; // TP-RD pdu[1] = (byte) tracker.mMessageRef; // TP-MR } } int token = mNextToken.incrementAndGet(); mTrackers.put(token, tracker); try { getImsManager().sendSms( token, tracker.mMessageRef, getFormat(), smsc != null ? new String(smsc) : null, isRetry, pdu); } catch (ImsException e) { Rlog.e(TAG, "sendSms failed. Falling back to PSTN. Error: " + e.getMessage()); fallbackToPstn(token, tracker); } } private ImsManager getImsManager() { return ImsManager.getInstance(mContext, mPhone.getPhoneId()); } @VisibleForTesting public void fallbackToPstn(int token, SmsTracker tracker) { mSmsDispatchersController.sendRetrySms(tracker); mTrackers.remove(token); } @Override protected boolean isCdmaMo() { return mSmsDispatchersController.isCdmaFormat(getFormat()); } } src/java/com/android/internal/telephony/InboundSmsHandler.java +4 −6 Original line number Diff line number Diff line Loading @@ -603,9 +603,9 @@ public abstract class InboundSmsHandler extends StateMachine { */ private void handleInjectSms(AsyncResult ar) { int result; PendingIntent receivedIntent = null; SmsDispatchersController.SmsInjectionCallback callback = null; try { receivedIntent = (PendingIntent) ar.userObj; callback = (SmsDispatchersController.SmsInjectionCallback) ar.userObj; SmsMessage sms = (SmsMessage) ar.result; if (sms == null) { result = Intents.RESULT_SMS_GENERIC_ERROR; Loading @@ -617,10 +617,8 @@ public abstract class InboundSmsHandler extends StateMachine { result = Intents.RESULT_SMS_GENERIC_ERROR; } if (receivedIntent != null) { try { receivedIntent.send(result); } catch (CanceledException e) { } if (callback != null) { callback.onSmsInjectedResult(result); } } Loading src/java/com/android/internal/telephony/SMSDispatcher.java +24 −17 Original line number Diff line number Diff line Loading @@ -94,6 +94,13 @@ public abstract class SMSDispatcher extends Handler { static final String TAG = "SMSDispatcher"; // accessed from inner class static final boolean DBG = false; private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg"; protected static final String MAP_KEY_PDU = "pdu"; protected static final String MAP_KEY_SMSC = "smsc"; protected static final String MAP_KEY_DEST_ADDR = "destAddr"; protected static final String MAP_KEY_SC_ADDR = "scAddr"; protected static final String MAP_KEY_DEST_PORT = "destPort"; protected static final String MAP_KEY_DATA = "data"; protected static final String MAP_KEY_TEXT = "text"; private static final int PREMIUM_RULE_USE_SIM = 1; private static final int PREMIUM_RULE_USE_NETWORK = 2; Loading Loading @@ -152,7 +159,7 @@ public abstract class SMSDispatcher extends Handler { */ private static int sConcatenatedRef = new Random().nextInt(256); private SmsDispatchersController mSmsDispatchersController; protected SmsDispatchersController mSmsDispatchersController; /** Number of outgoing SmsTrackers waiting for user confirmation. */ private int mPendingTrackerCount; Loading Loading @@ -378,7 +385,7 @@ public abstract class SMSDispatcher extends Handler { @Override protected void onServiceReady(ICarrierMessagingService carrierMessagingService) { HashMap<String, Object> map = mTracker.getData(); String text = (String) map.get("text"); String text = (String) map.get(MAP_KEY_TEXT); if (text != null) { try { Loading Loading @@ -410,8 +417,8 @@ public abstract class SMSDispatcher extends Handler { @Override protected void onServiceReady(ICarrierMessagingService carrierMessagingService) { HashMap<String, Object> map = mTracker.getData(); byte[] data = (byte[]) map.get("data"); int destPort = (int) map.get("destPort"); byte[] data = (byte[]) map.get(MAP_KEY_DATA); int destPort = (int) map.get(MAP_KEY_DEST_PORT); if (data != null) { try { Loading Loading @@ -1076,7 +1083,7 @@ public abstract class SMSDispatcher extends Handler { @VisibleForTesting public void sendRawPdu(SmsTracker tracker) { HashMap map = tracker.getData(); byte pdu[] = (byte[]) map.get("pdu"); byte pdu[] = (byte[]) map.get(MAP_KEY_PDU); if (mSmsSendDisabled) { Rlog.e(TAG, "Device does not support sending sms."); Loading Loading @@ -1713,23 +1720,23 @@ public abstract class SMSDispatcher extends Handler { protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr, String text, SmsMessageBase.SubmitPduBase pdu) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("destAddr", destAddr); map.put("scAddr", scAddr); map.put("text", text); map.put("smsc", pdu.encodedScAddress); map.put("pdu", pdu.encodedMessage); map.put(MAP_KEY_DEST_ADDR, destAddr); map.put(MAP_KEY_SC_ADDR, scAddr); map.put(MAP_KEY_TEXT, text); map.put(MAP_KEY_SMSC, pdu.encodedScAddress); map.put(MAP_KEY_PDU, pdu.encodedMessage); return map; } protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr, int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("destAddr", destAddr); map.put("scAddr", scAddr); map.put("destPort", destPort); map.put("data", data); map.put("smsc", pdu.encodedScAddress); map.put("pdu", pdu.encodedMessage); map.put(MAP_KEY_DEST_ADDR, destAddr); map.put(MAP_KEY_SC_ADDR, scAddr); map.put(MAP_KEY_DEST_PORT, destPort); map.put(MAP_KEY_DATA, data); map.put(MAP_KEY_SMSC, pdu.encodedScAddress); map.put(MAP_KEY_PDU, pdu.encodedMessage); return map; } Loading Loading @@ -1886,7 +1893,7 @@ public abstract class SMSDispatcher extends Handler { } } protected final boolean isCdmaMo() { protected boolean isCdmaMo() { return mSmsDispatchersController.isCdmaMo(); } } src/java/com/android/internal/telephony/SmsDispatchersController.java +94 −27 Original line number Diff line number Diff line Loading @@ -16,17 +16,22 @@ package com.android.internal.telephony; import android.app.Activity; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.provider.Telephony.Sms; import android.provider.Telephony.Sms.Intents; import android.telephony.Rlog; import android.telephony.SmsManager; import android.util.Pair; import com.android.ims.ImsManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; import com.android.internal.telephony.cdma.CdmaSMSDispatcher; Loading @@ -40,7 +45,7 @@ import java.util.HashMap; * */ public class SmsDispatchersController extends Handler { private static final String TAG = "RIL_ImsSms"; private static final String TAG = "SmsDispatchersController"; /** Radio is ON */ private static final int EVENT_RADIO_ON = 11; Loading @@ -53,6 +58,7 @@ public class SmsDispatchersController extends Handler { private SMSDispatcher mCdmaDispatcher; private SMSDispatcher mGsmDispatcher; private ImsSmsDispatcher mImsSmsDispatcher; private GsmInboundSmsHandler mGsmInboundSmsHandler; private CdmaInboundSmsHandler mCdmaInboundSmsHandler; Loading @@ -78,6 +84,7 @@ public class SmsDispatchersController extends Handler { // Create dispatchers, inbound SMS handlers and // broadcast undelivered messages in raw table. mImsSmsDispatcher = new ImsSmsDispatcher(phone, this); mCdmaDispatcher = new CdmaSMSDispatcher(phone, this); mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), storageMonitor, phone); Loading Loading @@ -146,7 +153,6 @@ public class SmsDispatchersController extends Handler { } private void setImsSmsFormat(int format) { // valid format? switch (format) { case PhoneConstants.PHONE_TYPE_GSM: mImsSmsFormat = SmsConstants.FORMAT_3GPP; Loading @@ -172,13 +178,12 @@ public class SmsDispatchersController extends Handler { * * @param pdu is the byte array of pdu to be injected into android telephony layer * @param format is the format of SMS pdu (3gpp or 3gpp2) * @param receivedIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully received by the * android telephony layer. This intent is broadcasted at * @param callback if not NULL this callback is triggered when the message is successfully * received by the android telephony layer. This callback is triggered at * the same time an SMS received from radio is responded back. */ @VisibleForTesting public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) { public void injectSmsPdu(byte[] pdu, String format, SmsInjectionCallback callback) { Rlog.d(TAG, "SmsDispatchersController:injectSmsPdu"); try { // TODO We need to decide whether we should allow injecting GSM(3gpp) Loading @@ -192,13 +197,11 @@ public class SmsDispatchersController extends Handler { if (msg == null) { Rlog.e(TAG, "injectSmsPdu: createFromPdu returned null"); } if (receivedIntent != null) { receivedIntent.send(Intents.RESULT_SMS_GENERIC_ERROR); } callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); return; } AsyncResult ar = new AsyncResult(receivedIntent, msg, null); AsyncResult ar = new AsyncResult(callback, msg, null); if (format.equals(SmsConstants.FORMAT_3GPP)) { Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg Loading @@ -211,19 +214,11 @@ public class SmsDispatchersController extends Handler { } else { // Invalid pdu format. Rlog.e(TAG, "Invalid pdu format: " + format); if (receivedIntent != null) { receivedIntent.send(Intents.RESULT_SMS_GENERIC_ERROR); } callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); } } catch (Exception e) { Rlog.e(TAG, "injectSmsPdu failed: ", e); try { if (receivedIntent != null) { receivedIntent.send(Intents.RESULT_SMS_GENERIC_ERROR); } } catch (CanceledException ex) { Rlog.e(TAG, "Failed to send result"); } callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); } } Loading Loading @@ -307,8 +302,7 @@ public class SmsDispatchersController extends Handler { map.put("smsc", pdu.encodedScAddress); map.put("pdu", pdu.encodedMessage); SMSDispatcher dispatcher = (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher; SMSDispatcher dispatcher = (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher; tracker.mFormat = dispatcher.getFormat(); dispatcher.sendSms(tracker); Loading Loading @@ -344,7 +338,7 @@ public class SmsDispatchersController extends Handler { * @param format * @return true if format given is CDMA format, false otherwise. */ private boolean isCdmaFormat(String format) { public boolean isCdmaFormat(String format) { return (mCdmaDispatcher.getFormat().equals(format)); } Loading Loading @@ -376,7 +370,10 @@ public class SmsDispatchersController extends Handler { */ protected void sendData(String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { if (isCdmaMo()) { if (mImsSmsDispatcher.isAvailable()) { mImsSmsDispatcher.sendData(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent); } else if (isCdmaMo()) { mCdmaDispatcher.sendData(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent); } else { mGsmDispatcher.sendData(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent); Loading Loading @@ -413,7 +410,10 @@ public class SmsDispatchersController extends Handler { public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage) { if (isCdmaMo()) { if (mImsSmsDispatcher.isAvailable()) { mImsSmsDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage); } else if (isCdmaMo()) { mCdmaDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage); } else { Loading Loading @@ -454,7 +454,10 @@ public class SmsDispatchersController extends Handler { ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, boolean persistMessage) { if (isCdmaMo()) { if (mImsSmsDispatcher.isAvailable()) { mImsSmsDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri, callingPkg, persistMessage); } else if (isCdmaMo()) { mCdmaDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri, callingPkg, persistMessage); } else { Loading Loading @@ -492,4 +495,68 @@ public class SmsDispatchersController extends Handler { public SmsUsageMonitor getUsageMonitor() { return mUsageMonitor; } /** * Triggers the correct method for handling the sms status report based on the format. * * @param tracker the sms tracker. * @param format the format. * @param pdu the pdu of the report. * @return a Pair in which the first boolean is whether the report was handled successfully * or not and the second boolean is whether processing the sms is complete and the * tracker no longer need to be kept track of, false if we should expect more callbacks * and the tracker should be kept. */ public Pair<Boolean, Boolean> handleSmsStatusReport(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu) { if (isCdmaFormat(format)) { return handleCdmaStatusReport(tracker, format, pdu); } else { return handleGsmStatusReport(tracker, format, pdu); } } private Pair<Boolean, Boolean> handleCdmaStatusReport(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu) { tracker.updateSentMessageStatus(mContext, Sms.STATUS_COMPLETE); boolean success = triggerDeliveryIntent(tracker, format, pdu); return new Pair(success, true /* complete */); } private Pair<Boolean, Boolean> handleGsmStatusReport(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu) { com.android.internal.telephony.gsm.SmsMessage sms = com.android.internal.telephony.gsm.SmsMessage.newFromCDS(pdu); boolean complete = false; boolean success = false; if (sms != null) { int tpStatus = sms.getStatus(); if(tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING ) { // Update the message status (COMPLETE or FAILED) tracker.updateSentMessageStatus(mContext, tpStatus); complete = true; } success = triggerDeliveryIntent(tracker, format, pdu); } return new Pair(success, complete); } private boolean triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu) { PendingIntent intent = tracker.mDeliveryIntent; Intent fillIn = new Intent(); fillIn.putExtra("pdu", pdu); fillIn.putExtra("format", format); try { intent.send(mContext, Activity.RESULT_OK, fillIn); return true; } catch (CanceledException ex) { return false; } } public interface SmsInjectionCallback { void onSmsInjectedResult(int result); } } Loading
src/java/com/android/internal/telephony/IccSmsInterfaceManager.java +11 −1 Original line number Diff line number Diff line Loading @@ -473,7 +473,17 @@ public class IccSmsInterfaceManager { "\n format=" + format + "\n receivedIntent=" + receivedIntent); } mDispatchersController.injectSmsPdu(pdu, format, receivedIntent); mDispatchersController.injectSmsPdu(pdu, format, result -> { if (receivedIntent != null) { try { receivedIntent.send(result); } catch (PendingIntent.CanceledException e) { Rlog.d(LOG_TAG, "receivedIntent cancelled."); } } } ); } /** Loading
src/java/com/android/internal/telephony/ImsSmsDispatcher.java +164 −6 Original line number Diff line number Diff line Loading @@ -16,25 +16,134 @@ package com.android.internal.telephony; import android.app.Activity; import android.os.RemoteException; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.provider.Telephony.Sms; import android.content.Intent; import android.telephony.Rlog; import com.android.ims.ImsException; import com.android.ims.ImsManager; import com.android.ims.internal.IImsSmsListener; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; import com.android.internal.telephony.util.SMSDispatcherUtil; import com.android.internal.telephony.gsm.SmsMessage; import android.telephony.ims.internal.SmsImplBase; import android.telephony.ims.internal.SmsImplBase.SendStatusResult; import android.telephony.ims.internal.SmsImplBase.StatusReportResult; import android.provider.Telephony.Sms.Intents; import android.util.Pair; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import libcore.util.Nullable; /** * Responsible for communications with {@link com.android.ims.ImsManager} to send/receive messages * over IMS. * * TODO: implement */ public class ImsSmsDispatcher extends SMSDispatcher { @VisibleForTesting public Map<Integer, SmsTracker> mTrackers = new ConcurrentHashMap<>(); @VisibleForTesting public AtomicInteger mNextToken = new AtomicInteger(); private final IImsSmsListener mImsSmsListener = new IImsSmsListener.Stub() { @Override public void onSendSmsResult(int token, int messageRef, @SendStatusResult int status, int reason) throws RemoteException { SmsTracker tracker = mTrackers.get(token); if (tracker == null) { throw new IllegalArgumentException("Invalid token."); } switch(reason) { case SmsImplBase.SEND_STATUS_OK: tracker.onSent(mContext); break; case SmsImplBase.SEND_STATUS_ERROR: tracker.onFailed(mContext, reason, 0 /* errorCode */); mTrackers.remove(token); break; case SmsImplBase.SEND_STATUS_ERROR_RETRY: tracker.mRetryCount += 1; sendSms(tracker); break; case SmsImplBase.SEND_STATUS_ERROR_FALLBACK: fallbackToPstn(token, tracker); break; default: } } /** {@inheritDoc} */ protected ImsSmsDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) { @Override public void onSmsStatusReportReceived(int token, int messageRef, String format, byte[] pdu) throws RemoteException { Rlog.d(TAG, "Status report received."); SmsTracker tracker = mTrackers.get(token); if (tracker == null) { throw new RemoteException("Invalid token."); } Pair<Boolean, Boolean> result = mSmsDispatchersController.handleSmsStatusReport( tracker, format, pdu); Rlog.d(TAG, "Status report handle result, success: " + result.first + "complete: " + result.second); try { getImsManager().acknowledgeSmsReport( token, messageRef, result.first ? SmsImplBase.STATUS_REPORT_STATUS_OK : SmsImplBase.STATUS_REPORT_STATUS_ERROR); } catch (ImsException e) { Rlog.e(TAG, "Failed to acknowledgeSmsReport(). Error: " + e.getMessage()); } if (result.second) { mTrackers.remove(token); } } @Override public void onSmsReceived(int token, String format, byte[] pdu) throws RemoteException { Rlog.d(TAG, "SMS received."); mSmsDispatchersController.injectSmsPdu(pdu, format, result -> { Rlog.d(TAG, "SMS handled result: " + result); try { getImsManager().acknowledgeSms(token, 0, result == Intents.RESULT_SMS_HANDLED ? SmsImplBase.STATUS_REPORT_STATUS_OK : SmsImplBase.DELIVER_STATUS_ERROR); } catch (ImsException e) { Rlog.e(TAG, "Failed to acknowledgeSms(). Error: " + e.getMessage()); } }); } }; public ImsSmsDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) { super(phone, smsDispatchersController); } public boolean isAvailable() { // TODO: implement return false; } @Override protected String getFormat() { return null; try { return getImsManager().getSmsFormat(); } catch (ImsException e) { Rlog.e(TAG, "Failed to get sms format. Error: " + e.getMessage()); return SmsConstants.FORMAT_UNKNOWN; } } @Override Loading Loading @@ -62,7 +171,56 @@ public class ImsSmsDispatcher extends SMSDispatcher { } @Override protected void sendSms(SmsTracker tracker) { public void sendSms(SmsTracker tracker) { Rlog.d(TAG, "sendSms: " + " mRetryCount=" + tracker.mRetryCount + " mMessageRef=" + tracker.mMessageRef + " SS=" + mPhone.getServiceState().getState()); HashMap<String, Object> map = tracker.getData(); byte[] pdu = (byte[]) map.get(MAP_KEY_PDU); byte smsc[] = (byte[]) map.get(MAP_KEY_SMSC); boolean isRetry = tracker.mRetryCount > 0; if (SmsConstants.FORMAT_3GPP.equals(getFormat()) && tracker.mRetryCount > 0) { // per TS 23.040 Section 9.2.3.6: If TP-MTI SMS-SUBMIT (0x01) type // TP-RD (bit 2) is 1 for retry // and TP-MR is set to previously failed sms TP-MR if (((0x01 & pdu[0]) == 0x01)) { pdu[0] |= 0x04; // TP-RD pdu[1] = (byte) tracker.mMessageRef; // TP-MR } } int token = mNextToken.incrementAndGet(); mTrackers.put(token, tracker); try { getImsManager().sendSms( token, tracker.mMessageRef, getFormat(), smsc != null ? new String(smsc) : null, isRetry, pdu); } catch (ImsException e) { Rlog.e(TAG, "sendSms failed. Falling back to PSTN. Error: " + e.getMessage()); fallbackToPstn(token, tracker); } } private ImsManager getImsManager() { return ImsManager.getInstance(mContext, mPhone.getPhoneId()); } @VisibleForTesting public void fallbackToPstn(int token, SmsTracker tracker) { mSmsDispatchersController.sendRetrySms(tracker); mTrackers.remove(token); } @Override protected boolean isCdmaMo() { return mSmsDispatchersController.isCdmaFormat(getFormat()); } }
src/java/com/android/internal/telephony/InboundSmsHandler.java +4 −6 Original line number Diff line number Diff line Loading @@ -603,9 +603,9 @@ public abstract class InboundSmsHandler extends StateMachine { */ private void handleInjectSms(AsyncResult ar) { int result; PendingIntent receivedIntent = null; SmsDispatchersController.SmsInjectionCallback callback = null; try { receivedIntent = (PendingIntent) ar.userObj; callback = (SmsDispatchersController.SmsInjectionCallback) ar.userObj; SmsMessage sms = (SmsMessage) ar.result; if (sms == null) { result = Intents.RESULT_SMS_GENERIC_ERROR; Loading @@ -617,10 +617,8 @@ public abstract class InboundSmsHandler extends StateMachine { result = Intents.RESULT_SMS_GENERIC_ERROR; } if (receivedIntent != null) { try { receivedIntent.send(result); } catch (CanceledException e) { } if (callback != null) { callback.onSmsInjectedResult(result); } } Loading
src/java/com/android/internal/telephony/SMSDispatcher.java +24 −17 Original line number Diff line number Diff line Loading @@ -94,6 +94,13 @@ public abstract class SMSDispatcher extends Handler { static final String TAG = "SMSDispatcher"; // accessed from inner class static final boolean DBG = false; private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg"; protected static final String MAP_KEY_PDU = "pdu"; protected static final String MAP_KEY_SMSC = "smsc"; protected static final String MAP_KEY_DEST_ADDR = "destAddr"; protected static final String MAP_KEY_SC_ADDR = "scAddr"; protected static final String MAP_KEY_DEST_PORT = "destPort"; protected static final String MAP_KEY_DATA = "data"; protected static final String MAP_KEY_TEXT = "text"; private static final int PREMIUM_RULE_USE_SIM = 1; private static final int PREMIUM_RULE_USE_NETWORK = 2; Loading Loading @@ -152,7 +159,7 @@ public abstract class SMSDispatcher extends Handler { */ private static int sConcatenatedRef = new Random().nextInt(256); private SmsDispatchersController mSmsDispatchersController; protected SmsDispatchersController mSmsDispatchersController; /** Number of outgoing SmsTrackers waiting for user confirmation. */ private int mPendingTrackerCount; Loading Loading @@ -378,7 +385,7 @@ public abstract class SMSDispatcher extends Handler { @Override protected void onServiceReady(ICarrierMessagingService carrierMessagingService) { HashMap<String, Object> map = mTracker.getData(); String text = (String) map.get("text"); String text = (String) map.get(MAP_KEY_TEXT); if (text != null) { try { Loading Loading @@ -410,8 +417,8 @@ public abstract class SMSDispatcher extends Handler { @Override protected void onServiceReady(ICarrierMessagingService carrierMessagingService) { HashMap<String, Object> map = mTracker.getData(); byte[] data = (byte[]) map.get("data"); int destPort = (int) map.get("destPort"); byte[] data = (byte[]) map.get(MAP_KEY_DATA); int destPort = (int) map.get(MAP_KEY_DEST_PORT); if (data != null) { try { Loading Loading @@ -1076,7 +1083,7 @@ public abstract class SMSDispatcher extends Handler { @VisibleForTesting public void sendRawPdu(SmsTracker tracker) { HashMap map = tracker.getData(); byte pdu[] = (byte[]) map.get("pdu"); byte pdu[] = (byte[]) map.get(MAP_KEY_PDU); if (mSmsSendDisabled) { Rlog.e(TAG, "Device does not support sending sms."); Loading Loading @@ -1713,23 +1720,23 @@ public abstract class SMSDispatcher extends Handler { protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr, String text, SmsMessageBase.SubmitPduBase pdu) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("destAddr", destAddr); map.put("scAddr", scAddr); map.put("text", text); map.put("smsc", pdu.encodedScAddress); map.put("pdu", pdu.encodedMessage); map.put(MAP_KEY_DEST_ADDR, destAddr); map.put(MAP_KEY_SC_ADDR, scAddr); map.put(MAP_KEY_TEXT, text); map.put(MAP_KEY_SMSC, pdu.encodedScAddress); map.put(MAP_KEY_PDU, pdu.encodedMessage); return map; } protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr, int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("destAddr", destAddr); map.put("scAddr", scAddr); map.put("destPort", destPort); map.put("data", data); map.put("smsc", pdu.encodedScAddress); map.put("pdu", pdu.encodedMessage); map.put(MAP_KEY_DEST_ADDR, destAddr); map.put(MAP_KEY_SC_ADDR, scAddr); map.put(MAP_KEY_DEST_PORT, destPort); map.put(MAP_KEY_DATA, data); map.put(MAP_KEY_SMSC, pdu.encodedScAddress); map.put(MAP_KEY_PDU, pdu.encodedMessage); return map; } Loading Loading @@ -1886,7 +1893,7 @@ public abstract class SMSDispatcher extends Handler { } } protected final boolean isCdmaMo() { protected boolean isCdmaMo() { return mSmsDispatchersController.isCdmaMo(); } }
src/java/com/android/internal/telephony/SmsDispatchersController.java +94 −27 Original line number Diff line number Diff line Loading @@ -16,17 +16,22 @@ package com.android.internal.telephony; import android.app.Activity; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.provider.Telephony.Sms; import android.provider.Telephony.Sms.Intents; import android.telephony.Rlog; import android.telephony.SmsManager; import android.util.Pair; import com.android.ims.ImsManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; import com.android.internal.telephony.cdma.CdmaSMSDispatcher; Loading @@ -40,7 +45,7 @@ import java.util.HashMap; * */ public class SmsDispatchersController extends Handler { private static final String TAG = "RIL_ImsSms"; private static final String TAG = "SmsDispatchersController"; /** Radio is ON */ private static final int EVENT_RADIO_ON = 11; Loading @@ -53,6 +58,7 @@ public class SmsDispatchersController extends Handler { private SMSDispatcher mCdmaDispatcher; private SMSDispatcher mGsmDispatcher; private ImsSmsDispatcher mImsSmsDispatcher; private GsmInboundSmsHandler mGsmInboundSmsHandler; private CdmaInboundSmsHandler mCdmaInboundSmsHandler; Loading @@ -78,6 +84,7 @@ public class SmsDispatchersController extends Handler { // Create dispatchers, inbound SMS handlers and // broadcast undelivered messages in raw table. mImsSmsDispatcher = new ImsSmsDispatcher(phone, this); mCdmaDispatcher = new CdmaSMSDispatcher(phone, this); mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), storageMonitor, phone); Loading Loading @@ -146,7 +153,6 @@ public class SmsDispatchersController extends Handler { } private void setImsSmsFormat(int format) { // valid format? switch (format) { case PhoneConstants.PHONE_TYPE_GSM: mImsSmsFormat = SmsConstants.FORMAT_3GPP; Loading @@ -172,13 +178,12 @@ public class SmsDispatchersController extends Handler { * * @param pdu is the byte array of pdu to be injected into android telephony layer * @param format is the format of SMS pdu (3gpp or 3gpp2) * @param receivedIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully received by the * android telephony layer. This intent is broadcasted at * @param callback if not NULL this callback is triggered when the message is successfully * received by the android telephony layer. This callback is triggered at * the same time an SMS received from radio is responded back. */ @VisibleForTesting public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) { public void injectSmsPdu(byte[] pdu, String format, SmsInjectionCallback callback) { Rlog.d(TAG, "SmsDispatchersController:injectSmsPdu"); try { // TODO We need to decide whether we should allow injecting GSM(3gpp) Loading @@ -192,13 +197,11 @@ public class SmsDispatchersController extends Handler { if (msg == null) { Rlog.e(TAG, "injectSmsPdu: createFromPdu returned null"); } if (receivedIntent != null) { receivedIntent.send(Intents.RESULT_SMS_GENERIC_ERROR); } callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); return; } AsyncResult ar = new AsyncResult(receivedIntent, msg, null); AsyncResult ar = new AsyncResult(callback, msg, null); if (format.equals(SmsConstants.FORMAT_3GPP)) { Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg Loading @@ -211,19 +214,11 @@ public class SmsDispatchersController extends Handler { } else { // Invalid pdu format. Rlog.e(TAG, "Invalid pdu format: " + format); if (receivedIntent != null) { receivedIntent.send(Intents.RESULT_SMS_GENERIC_ERROR); } callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); } } catch (Exception e) { Rlog.e(TAG, "injectSmsPdu failed: ", e); try { if (receivedIntent != null) { receivedIntent.send(Intents.RESULT_SMS_GENERIC_ERROR); } } catch (CanceledException ex) { Rlog.e(TAG, "Failed to send result"); } callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); } } Loading Loading @@ -307,8 +302,7 @@ public class SmsDispatchersController extends Handler { map.put("smsc", pdu.encodedScAddress); map.put("pdu", pdu.encodedMessage); SMSDispatcher dispatcher = (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher; SMSDispatcher dispatcher = (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher; tracker.mFormat = dispatcher.getFormat(); dispatcher.sendSms(tracker); Loading Loading @@ -344,7 +338,7 @@ public class SmsDispatchersController extends Handler { * @param format * @return true if format given is CDMA format, false otherwise. */ private boolean isCdmaFormat(String format) { public boolean isCdmaFormat(String format) { return (mCdmaDispatcher.getFormat().equals(format)); } Loading Loading @@ -376,7 +370,10 @@ public class SmsDispatchersController extends Handler { */ protected void sendData(String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { if (isCdmaMo()) { if (mImsSmsDispatcher.isAvailable()) { mImsSmsDispatcher.sendData(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent); } else if (isCdmaMo()) { mCdmaDispatcher.sendData(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent); } else { mGsmDispatcher.sendData(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent); Loading Loading @@ -413,7 +410,10 @@ public class SmsDispatchersController extends Handler { public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage) { if (isCdmaMo()) { if (mImsSmsDispatcher.isAvailable()) { mImsSmsDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage); } else if (isCdmaMo()) { mCdmaDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage); } else { Loading Loading @@ -454,7 +454,10 @@ public class SmsDispatchersController extends Handler { ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, boolean persistMessage) { if (isCdmaMo()) { if (mImsSmsDispatcher.isAvailable()) { mImsSmsDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri, callingPkg, persistMessage); } else if (isCdmaMo()) { mCdmaDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri, callingPkg, persistMessage); } else { Loading Loading @@ -492,4 +495,68 @@ public class SmsDispatchersController extends Handler { public SmsUsageMonitor getUsageMonitor() { return mUsageMonitor; } /** * Triggers the correct method for handling the sms status report based on the format. * * @param tracker the sms tracker. * @param format the format. * @param pdu the pdu of the report. * @return a Pair in which the first boolean is whether the report was handled successfully * or not and the second boolean is whether processing the sms is complete and the * tracker no longer need to be kept track of, false if we should expect more callbacks * and the tracker should be kept. */ public Pair<Boolean, Boolean> handleSmsStatusReport(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu) { if (isCdmaFormat(format)) { return handleCdmaStatusReport(tracker, format, pdu); } else { return handleGsmStatusReport(tracker, format, pdu); } } private Pair<Boolean, Boolean> handleCdmaStatusReport(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu) { tracker.updateSentMessageStatus(mContext, Sms.STATUS_COMPLETE); boolean success = triggerDeliveryIntent(tracker, format, pdu); return new Pair(success, true /* complete */); } private Pair<Boolean, Boolean> handleGsmStatusReport(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu) { com.android.internal.telephony.gsm.SmsMessage sms = com.android.internal.telephony.gsm.SmsMessage.newFromCDS(pdu); boolean complete = false; boolean success = false; if (sms != null) { int tpStatus = sms.getStatus(); if(tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING ) { // Update the message status (COMPLETE or FAILED) tracker.updateSentMessageStatus(mContext, tpStatus); complete = true; } success = triggerDeliveryIntent(tracker, format, pdu); } return new Pair(success, complete); } private boolean triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu) { PendingIntent intent = tracker.mDeliveryIntent; Intent fillIn = new Intent(); fillIn.putExtra("pdu", pdu); fillIn.putExtra("format", format); try { intent.send(mContext, Activity.RESULT_OK, fillIn); return true; } catch (CanceledException ex) { return false; } } public interface SmsInjectionCallback { void onSmsInjectedResult(int result); } }