Reputation: 8435
rite now i am trying to send SMS programmatically using following code , but i don't understand the behavior of SMS SENT Receiver.
1) for example if i send one SMS then
Activity.RESULT_OK
insideregisterReceiver
is being called 3 times. and if i send 3 SMS using for loopby callingsendSMS
thenActivity.RESULT_OK
is being called 9 times. now i really don't know for one sms to send why this registerReceiver is being called so many times?2) Moreover , when i run this code over emulator i passed emulator port to send SMS to other emulators which is natural but when i try to send SMS to a real number then i am not getting SMS delivery failure notification , as it notifies
Activity.RESULT_OK
only
code to send SMS
private void sendSMS(String phoneNumber, String message)
{
String SENT = "SMS_SENT";
String DELIVERED = "SMS_DELIVERED";
PendingIntent sentPI = PendingIntent.getBroadcast(this, 0,
new Intent(SENT), 0);
PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0,
new Intent(DELIVERED), 0);
Log.d("SMS Service", "SMS SEND CALLED");
//---when the SMS has been sent---
registerReceiver(new BroadcastReceiver(){
@Override
public void onReceive(Context arg0, Intent arg1) {
Log.d("SMS Service", "RECEIVE CALLED");
switch (getResultCode())
{
case Activity.RESULT_OK:
Toast.makeText(SMSService.this, "SMS sent",
Toast.LENGTH_SHORT).show();
System.out.println("SMSService " + "SMS SENT");
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(SMSService.this, "Generic failure",
Toast.LENGTH_SHORT).show();
System.out.println("SMSService " + "GENERIC FAILURE");
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(SMSService.this, "No service",
Toast.LENGTH_SHORT).show();
System.out.println("SMSService " + "NO SERVICE");
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(SMSService.this, "Null PDU",
Toast.LENGTH_SHORT).show();
System.out.println("SMSService " + "Null PDU");
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(SMSService.this, "Radio off",
Toast.LENGTH_SHORT).show();
System.out.println("SMSService " + "Radio Off");
break;
}
}
}, new IntentFilter(SENT));
//---when the SMS has been delivered---
registerReceiver(new BroadcastReceiver(){
@Override
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode())
{
case Activity.RESULT_OK:
Toast.makeText(getBaseContext(), "SMS delivered",
Toast.LENGTH_SHORT).show();
System.out.println("SMSService " + "SMS Delivered");
break;
case Activity.RESULT_CANCELED:
Toast.makeText(getBaseContext(), "SMS not delivered",
Toast.LENGTH_SHORT).show();
System.out.println("SMSService " + "SMS not delivered");
break;
}
}
}, new IntentFilter(DELIVERED));
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI);
}
Upvotes: 2
Views: 1951
Reputation: 11
Or you can do a singleton Class for the register:
public class RegisterReceiverSingleton {
private static RegisterReceiverSingleton rrS;
public static final String SENT = "SMS_SENT";
public static final String DELIVERED = "SMS_DELIVERED";
private RegisterReceiverSingleton(final Context ctx){
//when the SMS has been sent
ctx.registerReceiver(new BroadcastReceiver(){
@Override
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode())
{
case Activity.RESULT_OK:
Toast.makeText(ctx, "SMS Enviado",
Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(ctx, "Generic failure",
Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(ctx, "No service",
Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(ctx, "Null PDU",
Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(ctx, "Radio off",
Toast.LENGTH_SHORT).show();
break;
}
}
}, new IntentFilter(SENT));
//when the SMS has been delivered
ctx.registerReceiver(new BroadcastReceiver(){
@Override
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode())
{
case Activity.RESULT_OK:
Toast.makeText(ctx, "SMS Entregado",
Toast.LENGTH_SHORT).show();
break;
case Activity.RESULT_CANCELED:
Toast.makeText(ctx, "SMS No Entregado",
Toast.LENGTH_SHORT).show();
break;
}
}
}, new IntentFilter(DELIVERED));
}
public static RegisterReceiverSingleton getInstance(final Context ctx){
if(rrS==null){
rrS = new RegisterReceiverSingleton(ctx);
}
return rrS;
}
}
Upvotes: 1
Reputation: 2789
In general it depends on the size of message you are sending - if the message exceeds the single message limit (and in your case it sounds like it is about 3 times the single message limit) then you'll get a send and delivery report for each part of the message. Because you're not manually splitting the message you can't specify a different intent for each part.
It's worth taking a look at SmsManager.divideMessage() to split the message yourself and then at SmsManager.sendMultiPartTextMessage() to do the actual sending. This allows you to specify different pending intents for different parts of the message and so you can determine when the message has been finally sent.
I think the emulator is treating all message destinations as accurate and since there's no network to come back and say otherwise you probably won't get a failure to send from the emulator (unless you did something like put the emulator in airplane mode). From experience you certainly do get those error codes on a real device.
Edit: Thinking about it you're also registering the receiver each time you send the message, the code I use has a manifest registered receiver. There's a possibility that you've registered it multiple times (it lives as long as the context you're registering against) which would give it to you multiple times - this would also make it repeat probably 9 times for 3 messages (assuming the registration for the 3rd time made it before the send was completed for the first) - possible but I don't know how likely. You can test relatively well by logging the object in the registered receiver.
This is a cut down version of the code I use to send sms messages, it doesn't get repeated responses for messages:
ArrayList<String> split = SmsManager.getDefault().divideMessage(message);
ArrayList<PendingIntent> success = new ArrayList<PendingIntent>(partInfo.length);
Intent sendInt = null;
for (int i = 0; i < partInfo.length; i++)
{
sendInt = new Intent(context.getPackageName() + RELAY_INTERNAL_RESPONSE);
sendInt.putExtra(KEY_MESSAGEID, messageID);
sendInt.putExtra(KEY_PART_NUMBER, i);
sendInt.putExtra(KEY_REPLY_SEND_INTENT, sendIntAction);
sendInt.putExtra(KEY_NUMBER, number);
PendingIntent sendResult = PendingIntent.getBroadcast(context, i, sendInt, PendingIntent.FLAG_ONE_SHOT); //You have to use an incrementing request code to ensure you don't just get the same pending intent.
success.add(sendResult);
}
ArrayList<PendingIntent> receipt = new ArrayList<PendingIntent>(partInfo.length);
sendInt = new Intent(context.getPackageName() + RELAY_INTERNAL_RECEIPT);
sendInt.putExtra(KEY_MESSAGEID, messageID);
sendInt.putExtra(KEY_REPLY_RECEIPT_INTENT, receiptIntAction);
sendInt.putExtra(KEY_NUMBER, number);
PendingIntent sendResult = PendingIntent.getBroadcast(context, nextReceiptCounter(context), sendInt, PendingIntent.FLAG_ONE_SHOT);
for (int i = 0; i < partInfo.length; i++)
{
receipt.add(sendResult);
}
SmsManager sm = SmsManager.getDefault();
sm.sendMultipartTextMessage(target, null, split, success, receipt);
And my receiver definition:
<receiver android:name="<package>.SMSBroadcastModule"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="<package>.RELAY_INTERNAL_RESPONSE" />
<action android:name="<package>.RELAY_INTERNAL_RESPONSE_RECEIPT" />
</intent-filter>
</receiver>
Upvotes: 6