diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 0207330259e60..0865b1d6eabca 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -557,6 +557,23 @@ public final class Telephony { public static final String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL"; + /** + * Broadcast Action: An incoming SMS has been rejected by the + * telephony framework. This intent is sent in lieu of any + * of the RECEIVED_ACTION intents. The intent will have the + * following extra value:

+ * + * + + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String SMS_REJECTED_ACTION = + "android.provider.Telephony.SMS_REJECTED"; + /** * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a * {@link #DATA_SMS_RECEIVED_ACTION} intent. diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index 7efaa2eb4b35b..d26a092f16a20 100644 --- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -150,7 +150,8 @@ public abstract class SMSDispatcher extends Handler { private static SmsMessage mSmsMessage; private static SmsMessageBase mSmsMessageBase; private SmsMessageBase.SubmitPduBase mSubmitPduBase; - private boolean mStorageAvailable = true; + + protected boolean mStorageAvailable = true; protected static int getNextConcatenatedRef() { sConcatenatedRef += 1; @@ -294,19 +295,15 @@ public abstract class SMSDispatcher extends Handler { sms = (SmsMessage) ar.result; try { - if (mStorageAvailable) { - int result = dispatchMessage(sms.mWrappedSmsMessage); - if (result != Activity.RESULT_OK) { - // RESULT_OK means that message was broadcast for app(s) to handle. - // Any other result, we should ack here. - boolean handled = (result == Intents.RESULT_SMS_HANDLED); - acknowledgeLastIncomingSms(handled, result, null); - } - } else { - acknowledgeLastIncomingSms(false, Intents.RESULT_SMS_OUT_OF_MEMORY, null); + int result = dispatchMessage(sms.mWrappedSmsMessage); + if (result != Activity.RESULT_OK) { + // RESULT_OK means that message was broadcast for app(s) to handle. + // Any other result, we should ack here. + boolean handled = (result == Intents.RESULT_SMS_HANDLED); + notifyAndAcknowledgeLastIncomingSms(handled, result, null); } } catch (RuntimeException ex) { - acknowledgeLastIncomingSms(false, Intents.RESULT_SMS_GENERIC_ERROR, null); + notifyAndAcknowledgeLastIncomingSms(false, Intents.RESULT_SMS_GENERIC_ERROR, null); } break; @@ -865,6 +862,25 @@ public abstract class SMSDispatcher extends Handler { protected abstract void acknowledgeLastIncomingSms(boolean success, int result, Message response); + /** + * Notify interested apps if the framework has rejected an incoming SMS, + * and send an acknowledge message to the network. + * @param success indicates that last message was successfully received. + * @param result result code indicating any error + * @param response callback message sent when operation completes. + */ + private void notifyAndAcknowledgeLastIncomingSms(boolean success, + int result, Message response) { + if (!success) { + // broadcast SMS_REJECTED_ACTION intent + Intent intent = new Intent(Intents.SMS_REJECTED_ACTION); + intent.putExtra("result", result); + mWakeLock.acquire(WAKE_LOCK_TIMEOUT); + mContext.sendBroadcast(intent, "android.permission.RECEIVE_SMS"); + } + acknowledgeLastIncomingSms(success, result, response); + } + /** * Check if a SmsTracker holds multi-part Sms * diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index ca15a03d6135b..1e3a2e192a978 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -33,6 +33,7 @@ import android.preference.PreferenceManager; import android.util.Config; import android.util.Log; import android.telephony.SmsManager; +import android.telephony.SmsMessage.MessageClass; import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.CommandsInterface; @@ -91,23 +92,8 @@ final class CdmaSMSDispatcher extends SMSDispatcher { int teleService = sms.getTeleService(); boolean handled = false; - if ((sms.getUserData() == null) && (SmsEnvelope.TELESERVICE_MWI != teleService) && - (SmsEnvelope.TELESERVICE_VMN != teleService)) { - if (Config.LOGD) { - Log.d(TAG, "Received SMS without user data"); - } - handled = true; - } - - if (handled) { - return Intents.RESULT_SMS_HANDLED; - } - - if (SmsEnvelope.TELESERVICE_WAP == teleService) { - return processCdmaWapPdu(sms.getUserData(), sms.messageRef, - sms.getOriginatingAddress()); - } else if ((SmsEnvelope.TELESERVICE_VMN == teleService) || - (SmsEnvelope.TELESERVICE_MWI == teleService)) { + if ((SmsEnvelope.TELESERVICE_VMN == teleService) || + (SmsEnvelope.TELESERVICE_MWI == teleService)) { // handling Voicemail int voicemailCount = sms.getNumOfVoicemails(); Log.d(TAG, "Voicemail count=" + voicemailCount); @@ -118,9 +104,30 @@ final class CdmaSMSDispatcher extends SMSDispatcher { editor.putInt(CDMAPhone.VM_COUNT_CDMA, voicemailCount); editor.commit(); ((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount); + handled = true; + } else if ((sms.getUserData() == null)) { + if (Config.LOGD) { + Log.d(TAG, "Received SMS without user data"); + } + handled = true; + } + + if (handled) { return Intents.RESULT_SMS_HANDLED; } + if (!mStorageAvailable && (sms.getMessageClass() != MessageClass.CLASS_0)) { + // It's a storable message and there's no storage available. Bail. + // (See C.S0015-B v2.0 for a description of "Immediate Display" + // messages, which we represent as CLASS_0.) + return Intents.RESULT_SMS_OUT_OF_MEMORY; + } + + if (SmsEnvelope.TELESERVICE_WAP == teleService) { + return processCdmaWapPdu(sms.getUserData(), sms.messageRef, + sms.getOriginatingAddress()); + } + /** * TODO(cleanup): Why are we using a getter method for this * (and for so many other sms fields)? Trivial getters and diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java index b412fec5bc459..0ca31488cc349 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -37,6 +37,7 @@ import com.android.internal.telephony.SmsMessageBase; import java.util.ArrayList; import java.util.HashMap; +import static android.telephony.SmsMessage.MessageClass; final class GsmSMSDispatcher extends SMSDispatcher { private static final String TAG = "GSM"; @@ -111,6 +112,12 @@ final class GsmSMSDispatcher extends SMSDispatcher { return Intents.RESULT_SMS_HANDLED; } + if (!mStorageAvailable && (sms.getMessageClass() != MessageClass.CLASS_0)) { + // It's a storable message and there's no storage available. Bail. + // (See TS 23.038 for a description of class 0 messages.) + return Intents.RESULT_SMS_OUT_OF_MEMORY; + } + SmsHeader smsHeader = sms.getUserDataHeader(); // See if message is partial or port addressed. if ((smsHeader == null) || (smsHeader.concatRef == null)) {