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:
+ *
+ *
+ * - result - An int result code, eg,
+ *
{@link #RESULT_SMS_OUT_OF_MEMORY},
+ * indicating the error returned to the network.
+ *
+
+ */
+ @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)) {