Hunt
Hunt

Reputation: 8435

Behavior of SMS Notifications

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 inside registerReceiver is being called 3 times. and if i send 3 SMS using for loopby calling sendSMS then Activity.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

Answers (2)

Kasu
Kasu

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

zeetoobiker
zeetoobiker

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

Related Questions