Send Sms Until It Is Successful

Send SMS until it is successful

Here is what I have done:

public class SMSSender extends IntentService {

public static final String INTENT_MESSAGE_SENT = "message.sent";
public static final String INTENT_MESSAGE_DELIVERED = "message.delivered";

public static final String EXTRA_MESSAGE = "extra.message";
public static final String EXTRA_RECEIVERS = "extra.receivers";

public SMSSender() {
super("SMSSender");
}

private final String TAG = "SendSMS";

private static class IDGenerator {

private static final AtomicInteger counter = new AtomicInteger();

public static int nextValue() {
return counter.getAndIncrement();
}
}

private void sendSMS(String message, String[] receivers) {

SmsManager sm = SmsManager.getDefault();

ArrayList<String> parts = sm.divideMessage(message);

PendingIntent sentPI = null;
PendingIntent deliveredPI = null;

Intent sentIntent = new Intent(INTENT_MESSAGE_SENT);

int sentID = IDGenerator.nextValue();
sentPI = PendingIntent.getBroadcast(SMSSender.this, sentID, sentIntent,
PendingIntent.FLAG_CANCEL_CURRENT);

Intent deliveryIntent = new Intent(INTENT_MESSAGE_DELIVERED);

int deliveredID = IDGenerator.nextValue();
deliveredPI = PendingIntent.getBroadcast(SMSSender.this, deliveredID,
deliveryIntent, PendingIntent.FLAG_CANCEL_CURRENT);

Log.i(TAG, "sending SMS: parts: " + parts.size() + " message: "
+ message);

if (parts.size() > 1) {
ArrayList<PendingIntent> sentIntents = null;
ArrayList<PendingIntent> deliveredIntents = null;

sentIntents = new ArrayList<PendingIntent>();
deliveredIntents = new ArrayList<PendingIntent>();

for (int i = 0; i < parts.size(); i++) {
sentIntents.add(sentPI);
deliveredIntents.add(deliveredPI);
}

for (String receiver : receivers) {
try {
sm.sendMultipartTextMessage(receiver, null, parts,
sentIntents, deliveredIntents);
} catch (IllegalArgumentException e) {
Log.e(TAG, "illegal receiver: " + receiver);
}

}
} else {
for (String receiver : receivers) {
try {
sm.sendTextMessage(receiver, null, parts.get(0), sentPI,
deliveredPI);
} catch (IllegalArgumentException e) {
Log.e(TAG, "illegal receiver: " + receiver);
}
}
}
}

@Override
protected void onHandleIntent(Intent intent) {
String message = intent.getStringExtra(EXTRA_MESSAGE);
String[] receivers = intent.getStringArrayExtra(EXTRA_RECEIVERS);

sendSMS(message, receivers);

}

And to use it:

    private void startMessageServiceIntent(String message, String receiver) {
Intent i = new Intent(context, SMSSender.class);
i.putExtra(SMSSender.EXTRA_MESSAGE, message);
i.putExtra(SMSSender.EXTRA_RECEIVERS, new String[] { receiver });
startService(i)
}

Notice it supports multiple receivers, which this method does not demonstrate/use.

Remember in your manifest:

<uses-permission android:name="android.permission.SEND_SMS" />

<service android:name="your.package.SMSSender" android:enabled="true" />

Optionally you can listen for when messages are sent and/or delivered:

@Override
protected void onCreate() {

...

// ---when the SMS has been sent---
private BroadcastReceiver messageSent; // <- stored as a field
messageSent = new SentMessage();
registerReceiver(messageSent, new IntentFilter(SMSSender.INTENT_MESSAGE_SENT));

// ---when the SMS has been delivered---
private BroadcastReceiver messageDelivered; // <- stored as a field
messageDelivered = new MessageDelivered();
registerReceiver(messageDelivered, new IntentFilter(
SMSSender.INTENT_MESSAGE_DELIVERED));
}

@Override
protected void onDestroy() { // remember to unregister
unregisterReceiver(messageSent);
unregisterReceiver(messageDelivered );
}

I know this does not demonstrate answers to all your questions but I hope that it is sufficient.

Edit: Added my implementations of messageSent and messageDelivered

These are specific to my implementation, so includes some code that you cannot use, it is simply for demonstration.

Message sent:

public class SentMessage extends BroadcastReceiver {

private final String TAG = "SentMessage";

@Override
public void onReceive(Context context, Intent intent) {
long _id = intent.getLongExtra(EXTRA_ID, -1);
long protocol_id = intent.getLongExtra(EXTRA_PROTOCOL, -1);
Log.d(TAG, "SentMessage");
switch (getResultCode()) {
case Activity.RESULT_OK:
Log.d(TAG, "RESULT_OK");
if (MessageData.sentMessage(_id, protocol_id)) {
try {
Database.messageSent(_id);
} catch (DatabaseRowNotFoundException e) {
Log.e(TAG, e.toString(), e);
}
}
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Log.d(TAG, "RESULT_ERROR_GENERIC_FAILURE");
MessageData.postponeMessage(_id);
ApplicationData.hasSignal(false);
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Log.d(TAG, "RESULT_ERROR_NO_SERVICE");
MessageData.postponeMessage(_id);
ApplicationData.hasSignal(false);
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Log.d(TAG, "RESULT_ERROR_NULL_PDU");
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Log.d(TAG, "RESULT_ERROR_RADIO_OFF");
MessageData.postponeMessage(_id);
ApplicationData.hasSignal(false);
break;
}

}

Message delivered:

public class DeliveredMessage extends BroadcastReceiver {

private final String TAG = "DeliveredMessage ";

@Override
public void onReceive(Context context, Intent intent) {

long _id = intent.getLongExtra(EXTRA_ID, -1);
long protocol_id = intent.getLongExtra(EXTRA_PROTOCOL, -1);
switch (getResultCode()) {
case Activity.RESULT_OK:
if (_id != -1 && MessageData.deliveredMessage(_id, protocol_id)) {
try {
Database.messageDelivered(_id);
Cursor messageCursor = Database.getCursorByID(MessageOutboxContentProvider.CONTENT_URI, MessageOutboxContentProvider._ID, _id);
messageCursor.close();
} catch (DatabaseRowNotFoundException e) {
Log.e(TAG, e.toString(), e);
}
}
break;
case Activity.RESULT_CANCELED:
break;
}
}

}

I was in the need for reliable sending too, so kept references to all pending messages in a database, which I would frequently scan for postponed messages. A message would get postponed if there is no radio, or the sending simply fails for whatever reason.

I also used GCM together with SMS to get the message delivered as fast as possible, sending messages using both channels at the same time.

Edit2: Oh well, might as well address the questions, we are almost there anyway:

Question 1: Since using IntentService the sending is done in the background.

You only want the sending to happen once after a delay so you should do this instead:

    new Handler().postDelayed(new Runnable() {

@Override
public void run() {
// send sms
}
}, delay);

Question 2: Easy, when your sent message broadcast detects an error do the above method. You could add an extra information, besides receiver and message, counting the number of retries up until now so you have a chance of stopping the send/retry loop.

Question 3: The sending stops by itself, as it is an Intent Service. As for the other service the most simple approach, I think, would be to send a common broadcast, which is picked up by your main activity. This way you can get a hold of the service the right place and stop it.

Send SMS leads to Generic Failure

The second parameter in the SmsManager#sendMultipartTextMessage() method (as well as the sendTextMessage() and sendDataMessage() methods) is for the number of your service center, not the sender's number. A service center is the part of your network that handles the storage, routing, and delivery of SMS messages, so passing an invalid number would result in the generic failure status you're getting. You simply need to pass null for this.

Sending SMS from Intent Service - Unable to recieve broadcast to check if sms was sent

An IntentService will stop itself as soon as it's finished its work, and any Receivers dynamically registered on it go away, as well. In your first snippet, the Receiver likely won't be alive to receive the broadcast when it's finally sent, as the sendTextMessage() call will return immediately, and the PendingIntent will be fired asynchronously.

Statically registering the Receiver class, as you've done in the second snippet, will allow the Receiver to get the broadcast even after the IntentService has died, as the resulting Receiver instance will not be tied to it. However, the Intent you've used for the PendingIntent does not correctly target the Receiver class. Change it to new Intent(this, smsSentReceiver.class).

Lastly, logs with certain tags are suppressed, for some reason, and the "SMS" tag (exactly) is one of those. Change that tag to something not listed there; e.g., "smsSentReceiver".

SMS sending to multiple numbers not being sent

I managed to do this - needed to turn off "Group Messaging" in AVD Settings. App was trying to send MMS and that's why it wasn't being sent.

Catching SMS send and deliver event

rowItem is my holder class for my listview. I am calling onItemSelectedListener on specific item, so for your tablet or any other device, my code works. If there is no support for SMS, then it show Toast.

if(rowItems.get(position).getTitle().endsWith("SMS"))
{
if (getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY))
{
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra("address", "0"+9999999999);
intent.setType("vnd.android-dir/mms-sms");
startActivity(intent);
}
else {
toast("No SMS Support");
}
}


Related Topics



Leave a reply



Submit