I am sending SMS through my application using a very common way that is explained in pretty much all tutorials. I use sendMultipartTextMessage with "sent Intents" and "delivery Intents", then a Broadcast receiver listen for the results and print things.
But, everytime I try to send a SMS, even with something like 10 characters, I always get a "Generic failure".
My default SMS app is working perfectly and I can send/receive SMS/MMS without any troubles so it can't be a network issue. I don't want my app to become my new default SMS app, I just want it to be able to send a short SMS sometimes.
I tried a lot of things but everything has failed.
What is that issue and what can I do to get rid of it ?
Utils :
public static void sendSMS(Context context, String destination) {
final String srcPhoneNumber = PreferenceManager.getDefaultSharedPreferences(context).getString(OptionsFragment.SMS_SRC_PHONE_NUMBER, null);
final String message = PreferenceManager.getDefaultSharedPreferences(context).getString(OptionsFragment.SMS_MESSAGE, null);
if (message == null || message.isEmpty() || destination == null || destination.isEmpty()) {
Console.log('e', "tag", "sms sending failure");
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("sms");
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra("sms", context.getString(R.string.empty_message));
MyApplication.getInstance().sendBroadcast(broadcastIntent);
return ;
}
final List<String> phoneNumbers = getPhoneNumbers();
removeEmptyElement(phoneNumbers);
SmsManager smsManager = SmsManager.getDefault();
ArrayList<String> parts = smsManager.divideMessage(message);
ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>();
ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
PendingIntent sentPI = PendingIntent.getBroadcast(MyApplication.getInstance(), 0, new Intent("sms"), 0);
PendingIntent deliveredPI = PendingIntent.getBroadcast(MyApplication.getInstance(), 0, new Intent("sms"), 0);
for (String part : parts) {
sentIntents.add(sentPI);
deliveryIntents.add(deliveredPI);
}
SmsManager.getDefault().sendMultipartTextMessage(destination, srcPhoneNumber, parts, sentIntents, deliveryIntents);
}
Receiver :
#Override
public void onReceive(Context context, Intent intent) {
String s = intent.getAction();
if (s.equals("sms")) {
String message = intent.getStringExtra("sms");
if (message != null) {
if (message.equals("OK")) {
AlertDialog.Builder builder = new AlertDialog.Builder(HomeFragment.this.getActivity());
builder.setMessage(context.getString(R.string.sms_send_success))
.setCancelable(true)
.setTitle("Success");
builder.create().show();
} else {
Utils.makeErrorDialog(HomeFragment.this.getActivity(), message);
}
}
else {
switch (getResultCode())
{
case Activity.RESULT_OK:
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Utils.makeErrorDialog(HomeFragment.this.getActivity(),context.getString(R.string.send_error) + "Generic failure");
progressDialog.dismiss();
return;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Utils.makeErrorDialog(HomeFragment.this.getActivity(),context.getString(R.string.send_error) + "No service");
progressDialog.dismiss();
return;
case SmsManager.RESULT_ERROR_NULL_PDU:
Utils.makeErrorDialog(HomeFragment.this.getActivity(),context.getString(R.string.send_error) + "Null PDU");
progressDialog.dismiss();
return;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Utils.makeErrorDialog(HomeFragment.this.getActivity(),context.getString(R.string.send_error) + "Radio off");
progressDialog.dismiss();
return;
}
...
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.
Related
I am trying to create a feature in my app which can send SMS to multiple contacts in background. I am using SMS Manager API to do the same. However, everytime RESULT_ERROR_GENERIC_FAILURE returns. I read lot of similar posts on stack overflow and tried all the solutions but none of them seems to work for me. To be specific, I have tried following:
Change phone number format to "+91xxxxxxxxxx", "9xxxxxxxxx", "91xxxxxxxxxx"
Checked the SIM balance
SMS Service centre number is also valid
SMS Message is well within 160 characters
Delay sending multiple SMS
Here is how I am sending SMS:
for (int index = 0; index < contactsList.size(); index++) {
final String phonenumber = contactsList.get(index).getPhone().substring(1);
if (index == 0) {
sendSMS(phonenumber.trim(), sms, contactsList);
} else {
new Handler().postDelayed(new Runnable() {
public void run() {
sendSMS(phonenumber.trim(), sms, contactsList);
}
}, 1000 * 20);
}
}
Here is sendSMS method:
private void sendSMS(String phoneNumber, final String message, final List<MyContactsActivity.ContactsRow> list) {
String SENT = "SMS_SENT";
String DELIVERED = "SMS_DELIVERED";
PendingIntent sentPI = PendingIntent.getBroadcast(context, 0, new Intent(
SENT), 0);
PendingIntent deliveredPI = PendingIntent.getBroadcast(context, 0,
new Intent(DELIVERED), 0);
// ---when the SMS has been sent---
context.registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
ContentValues values = new ContentValues();
for (int i = 0; i < list.size() - 1; i++) {
values.put("address", list.get(i).getPhone());
values.put("body", message);
}
context.getContentResolver().insert(
Uri.parse("content://sms/sent"), values);
Toast.makeText(context, "SMS sent", Toast.LENGTH_SHORT).show();
Log.e("Panic", "1");
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(context, "Generic failure", Toast.LENGTH_SHORT).show();
Log.e("Panic", "2");
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(context, "No service", Toast.LENGTH_SHORT).show();
Log.e("Panic", "3");
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(context, "Null PDU", Toast.LENGTH_SHORT).show();
Log.e("Panic", "4");
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(context, "Radio off", Toast.LENGTH_SHORT).show();
Log.e("Panic", "5");
break;
}
}
}, new IntentFilter(SENT));
// ---when the SMS has been delivered---
context.registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Toast.makeText(context, "SMS delivered", Toast.LENGTH_SHORT).show();
Log.e("Panic", "6");
break;
case Activity.RESULT_CANCELED:
Toast.makeText(context, "SMS not delivered", Toast.LENGTH_SHORT).show();
Log.e("Panic", "7");
break;
}
}
}, new IntentFilter(DELIVERED));
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI);
}
Here are my relevant manifest permissions:
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS" />
NOTE: I am testing my app on real device running Android 6. I have checked runtime permissions as well as they are enabled.
Can anyone please tell me what I am doing wrong??
I have found the solution to this problem. In case of dual sim phones, there is an option which specifies from which SIM to send SMS. If option has been set to "Ask everytime", generic failure occurs. Solution is to set this option to either of the SIM card. However, I have not yet found programmatic way to do that.
It is maybe due to a large message. Android supports multipart sms for long messages, Try using multipart sms.
SmsManager smsManager = SmsManager.getDefault();
ArrayList<String> parts = smsManager.divideMessage(message);
smsManager.sendMultipartTextMessage(phoneNo, null, parts, null, null);
(Solution for Flutter)
This solved issue with sending long SMS messages.
In your pubspec.yaml put this:
sms_maintained:
git:
url: https://github.com/andreimc/flutter_sms.git
I found it here: https://github.com/geordyvcErasmus/flutter_sms/pull/15
Your code is correct. check you have active SIM card and having balance in it. Because Generic failure is response from your service provider.
For me the problem was the content of the message, there was special characters (like /r /n)
I got the same problem with same above code
I tried restarted my phone once and try again it worked.
i was using "~" in my message. guess one must sanitize string before sending
I want to send to multiple number of recepients.
I also want to use the built in SMS mechanism without being prompt for a required App (Whatsapp, etc.)
In order to acomplish this, I am using Android's SmsManager.
The for loop iterates through the mobileList array of mobile numbers and send SMS to each one of them, one by one.
The indication for delivered SMS is retrieved by the BroadcastReceiver for the deliveredActionIntent intent.
I am popping a toast with the word "Delivered" and the index number of the message being delivered.
My questions are:
The actual index (idx) is not shown. I get for all toasts the same index number which is the number of mobileList items.
Why is this happening? I expected the index for each mobile by itself.
Is the number of mobileList items limited? Can I have 200 people for instance?
I tested this on a list of 4 mobile numbers but then I got 8-10 toasts. I expected one toast for one mobile delivery.
What is wrong here?
How can I get a notification when all SMSs are delivered? I guess this should be a background action like AsyncTask.
Can someone please show me how to do this?
The code of the SmsManager is shown below.
SmsManager smsManager = SmsManager.getDefault();
for(idx = 0; idx < mobileList.length; idx++) {
String toNumber = mobileList[idx];
String sms = message;
// SMS sent pending intent
Intent sentActionIntent = new Intent(SENT_ACTION);
sentActionIntent.putExtra(EXTRA_IDX, idx);
sentActionIntent.putExtra(EXTRA_TONUMBER, toNumber);
sentActionIntent.putExtra(EXTRA_SMS, sms);
PendingIntent sentPendingIntent = PendingIntent.getBroadcast(this, 0, sentActionIntent, PendingIntent.FLAG_UPDATE_CURRENT);
/* Register for SMS send action */
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String result = "";
switch (getResultCode()) {
case Activity.RESULT_OK:
result = "Transmission successful";
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
result = "Transmission failed";
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
result = "Radio off";
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
result = "No PDU defined";
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
result = "No service";
break;
}
// Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
}
}, new IntentFilter(SENT_ACTION));
// SMS delivered pending intent
Intent deliveredActionIntent = new Intent(DELIVERED_ACTION);
deliveredActionIntent.putExtra(EXTRA_IDX, idx);
deliveredActionIntent.putExtra(EXTRA_TONUMBER, toNumber);
deliveredActionIntent.putExtra(EXTRA_SMS, sms);
PendingIntent deliveredPendingIntent = PendingIntent.getBroadcast(this, 0, deliveredActionIntent, PendingIntent.FLAG_UPDATE_CURRENT);
/* Register for Delivery event */
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(getApplicationContext(), "Deliverd " + Integer.toString(idx), Toast.LENGTH_SHORT).show();
}
}, new IntentFilter(DELIVERED_ACTION));
//send
smsManager.sendTextMessage(toNumber, null, sms, sentPendingIntent, deliveredPendingIntent);
}
1) idx changes as you run through the for-loop. Thus, each time you toast, you're showing the current value for idx, which is the number of messages being shown. Since you've packed it in your intent, you can simply show the text "Delivered" + intent.getIntExtra(EXTRA_IDX, -1) in your onReceive method.
2) I'm not sure what you're asking.
3) I'm not sure off-hand, and can't currently debug.
4) You're going to have to keep track of which indices you've received. A HashSet<Integer> should do the trick.
Above your for loop, add this:
final HashSet<Integer> undelivered = new HashSet<Integer>();
In your for loop, add this:
undelivered.add(idx);
To answer your questions for 1, 3, and 4 at once, change your onReceived body to this:
// Get the index from the intent
int idx = intent.getIntExtra(EXTRA_IDX, -1);
if (undelivered.contains(idx)) {
// This index is now delivered. We remove it from the undelivered set, and Toast that it was delivered.
undelivered.remove(idx);
Toast.makeText(getApplicationContext(), "Delivered " + idx, Toast.LENGTH_SHORT).show();
if (undelivered.isEmpty() {
// We've delivered all of the messages ...
Toast.makeText(getApplicationContext(), "All messages were delivered.", Toast.LENGTH_SHORT).show();
}
}
We're using the SMSManager on Android to send a text message to someone else from the device.
We've had reports of a user not receiving an SMS that we thought was delivered based on the fact that the sentIntent got called with Activity.RESULT_OK - but that seems to happen when the local SMS service simply queues the message for delivery and not necessarily when it is truly sent.
So I thought we should make use of the deliveryIntent.
The problem here is that I always get the sentIntent callback, but never the deliveryIntent one.
Any ideas?
Code is below, thanks.
// The intent action to be unique so that we can have multiple
// concurrent pending intents.
// http://developer.android.com/reference/android/app/PendingIntent.html
String intentAction = TAG + "-" + callbackId; // callbackId is unique
Intent intent = new Intent(intentAction);
intent.putExtra("phoneNumber", phoneNumber);
intent.putExtra("callbackId", callbackId);
intent.putExtra("message", message);
PendingIntent sentPI = PendingIntent.getBroadcast(
cordova.getActivity(), 0, intent, 0);
cordova.getActivity().registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context ctx, Intent intent) {
String sentToPhoneNumber = intent.getStringExtra("phoneNumber");
String callbackId = intent.getStringExtra("callbackId");
String message = intent.getStringExtra("message");
int resultCode = getResultCode();
int status = -1;
String details = "";
logger.log(Level.INFO, TAG + " SENT intent!! to: " +
sentToPhoneNumber + ", resultCode: " + resultCode);
switch (resultCode) {
case Activity.RESULT_OK:
status = 0;
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
details = "No service";
case SmsManager.RESULT_ERROR_NULL_PDU:
details = "Null PDU";
case SmsManager.RESULT_ERROR_RADIO_OFF:
details = "Radio off";
status = 1;
break;
}
JSONObject obj = new JSONObject();
try {
obj.put("status", status);
obj.put("details", details);
obj.put("phone_number", sentToPhoneNumber);
obj.put("message", message);
} catch (JSONException e) {
throw new RuntimeException(e);
}
sendAsyncResultStatus(callbackId, obj);
ctx.unregisterReceiver(this);
}
}, new IntentFilter(intentAction));
// The intent action to be unique so that we can have multiple
// concurrent pending intents.
// http://developer.android.com/reference/android/app/PendingIntent.html
String deliveryIntentAction = TAG + "-Delivery-" + callbackId;
Intent deliveryIntent = new Intent(deliveryIntentAction);
deliveryIntent.putExtra("phoneNumber", phoneNumber);
deliveryIntent.putExtra("callbackId", callbackId);
deliveryIntent.putExtra("message", message);
PendingIntent deliveryPI = PendingIntent.getBroadcast(
cordova.getActivity(), 0, deliveryIntent, 0);
cordova.getActivity().registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context ctx, Intent intent) {
logger.log(Level.INFO, TAG + " DELIVERY intent YOYO!!");
String sentToPhoneNumber = intent.getStringExtra("phoneNumber");
String callbackId = intent.getStringExtra("callbackId");
String message = intent.getStringExtra("message");
String pdu = intent.getStringExtra("pdu");
logger.log(Level.INFO, TAG + " DELIVERY intent!! to: " +
sentToPhoneNumber + ", pdu: " + pdu);
JSONObject obj = new JSONObject();
try {
obj.put("pdu", pdu);
obj.put("phone_number", sentToPhoneNumber);
obj.put("message", message);
} catch (JSONException e) {
throw new RuntimeException(e);
}
sendAsyncResultStatus(callbackId, obj);
ctx.unregisterReceiver(this);
}
}, new IntentFilter(deliveryIntentAction));
smsManager.sendTextMessage(phoneNumber, null, message, sentPI, deliveryPI);
DeliveryIntent is dependent on DeliveryReports provided by some carriers.
Some Carriers do provide DeliveryReports and some don't. There are three categories in terms of carriers support of DliveryReports...
Provider does not provide DeliveryReport at all.
Provider always give a fake DeliveryReport (you will get an OK report even for invalid numbers)
Provider does provide the delivery report.
The Complication doesn't stop here... If your provider (sending provider) does support delivery reports, you will get the delivery reports mostly when you are sending messages to subscribers of the same carrier. But when you send the message outside this carrier you may or may not get the delivery report. In most cases you won't.
This can be caused by a verity of reasons e.g.
Destination provider doesn't support delivery reports
Some of the intermediate SMS gateway(s) do not support delivery reports
DeliveryReports of Destination carrier or some intermediate gateways are not compatible with those of Originating Carriers.
Delivery Reports in such case are not a guaranteed information in my knowledge so far.
I could imagine that delivery intents depend on the reception of Return Receipts. The network provider needs to send these in order to make your program work.
You can do this by opening the "settings menu", browse to "SMS settings" and tick the box "Return receipt".
I'm rather new to Android.
Im trying to send SMS from Android application.
When using the SMS Intent the SMS window opens and the user needs to approve the SMS and send it.
Is there a way to automatically send the SMS without the user confirming it?
Thanks,
Lior
You can use this method to send an sms. If the sms is greater than 160 character then sendMultipartTextMessage is used.
private void sendSms(String phonenumber,String message, boolean isBinary)
{
SmsManager manager = SmsManager.getDefault();
PendingIntent piSend = PendingIntent.getBroadcast(this, 0, new Intent(SMS_SENT), 0);
PendingIntent piDelivered = PendingIntent.getBroadcast(this, 0, new Intent(SMS_DELIVERED), 0);
if(isBinary)
{
byte[] data = new byte[message.length()];
for(int index=0; index<message.length() && index < MAX_SMS_MESSAGE_LENGTH; ++index)
{
data[index] = (byte)message.charAt(index);
}
manager.sendDataMessage(phonenumber, null, (short) SMS_PORT, data,piSend, piDelivered);
}
else
{
int length = message.length();
if(length > MAX_SMS_MESSAGE_LENGTH)
{
ArrayList<String> messagelist = manager.divideMessage(message);
manager.sendMultipartTextMessage(phonenumber, null, messagelist, null, null);
}
else
{
manager.sendTextMessage(phonenumber, null, message, piSend, piDelivered);
}
}
}
Update
piSend and piDelivered are Pending Intent They can trigger a broadcast when the method finish sending an SMS
Here is sample code for broadcast receiver
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = null;
switch (getResultCode()) {
case Activity.RESULT_OK:
message = "Message sent!";
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
message = "Error. Message not sent.";
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
message = "Error: No service.";
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
message = "Error: Null PDU.";
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
message = "Error: Radio off.";
break;
}
AppMsg.makeText(SendMessagesWindow.this, message,
AppMsg.STYLE_CONFIRM).setLayoutGravity(Gravity.BOTTOM)
.show();
}
};
and you can register it using below line in your Activity
registerReceiver(receiver, new IntentFilter(SMS_SENT)); // SMS_SENT is a constant
Also don't forget to unregister broadcast in onDestroy
#Override
protected void onDestroy() {
unregisterReceiver(receiver);
super.onDestroy();
}
If your application has in the AndroidManifest.xml the following permission
<uses-permission android:name="android.permission.SEND_SMS"/>
you can send as many SMS as you want with
SmsManager manager = SmsManager.getDefault();
manager.sendTextMessage(...);
and that is all.
Yes, you can send SMS using the SmsManager. Please keep in mind that your application will need the SEND_SMS permission for this to work.
Yes, you can send sms without making user interaction...But it works, when user wants to send sms only to a single number.
try {
SmsManager.getDefault().sendTextMessage(RecipientNumber, null,
"Hello SMS!", null, null);
} catch (Exception e) {
AlertDialog.Builder alertDialogBuilder = new
AlertDialog.Builder(this);
AlertDialog dialog = alertDialogBuilder.create();
dialog.setMessage(e.getMessage());
dialog.show();
}
Also, add manifest permission....
<uses-permission android:name="android.permission.SEND_SMS"/>
So i have tried for a long time to find a way to make a app that can send and receive sms in android. That works fine. Here is the code:
For sending:
#SuppressWarnings("deprecation")
public void sendSMS(String phoneNumber, String message) {
String SENT = "SMS_SENT";
String DELIVERED = "SMS_DELIVERED";
int unq = 0;
Intent sent = new Intent(SENT);
sent.putExtra("unq", unq);
Intent delivered = new Intent(DELIVERED);
delivered.putExtra("unq", unq);
PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, sent, 0);
PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0,delivered, 0);
// ---when the SMS has been sent---
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Toast.makeText(getBaseContext(), "SMS sent",
Toast.LENGTH_SHORT).show();
smsstatus = "0";
smserror = "noError";
//sendSmsStatus();
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(getBaseContext(), "Generic failure",
Toast.LENGTH_SHORT).show();
setSmsstatus("1");
setSmserror("Generic failure");
sendSmsStatus("Generic failure");
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(getBaseContext(), "No service",
Toast.LENGTH_SHORT).show();
setSmsstatus("2");
setSmserror("No service");
sendSmsStatus("No service");
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(getBaseContext(), "Null PDU",
Toast.LENGTH_SHORT).show();
setSmsstatus("3");
setSmserror("Null PDU");
sendSmsStatus("Null PDU");
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(getBaseContext(), "Radio off",
Toast.LENGTH_SHORT).show();
setSmsstatus("4");
setSmserror("Radio off");
sendSmsStatus("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();
break;
case Activity.RESULT_CANCELED:
Toast.makeText(getBaseContext(), "SMS not delivered",
Toast.LENGTH_SHORT).show();
break;
}
}
}, new IntentFilter(DELIVERED));
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI);
}
For receiving:
public class SmsReceiver extends BroadcastReceiver {
#SuppressWarnings("deprecation")
#Override
public void onReceive(Context context, Intent intent) {
// ---get the SMS message passed in---
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str = "";
Object sms = "";
ArrayList<String> s = new ArrayList<String>();
Manager m = Factory.getInstance().getManager();
if (bundle != null) {
// ---retrieve the SMS message received---
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for (int i = 0; i < msgs.length; i++) {
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
str += " SMS fra " + msgs[i].getOriginatingAddress() + "\n";
str += " Besked: ";
str += msgs[i].getMessageBody().toString();
str += "\n";
sms = "SMS = "+msgs[i].getOriginatingAddress()+","+msgs[i].getMessageBody().toString();
s.add(msgs[i].getOriginatingAddress());
s.add(msgs[i].getMessageBody().toString());
}
// ---display the new SMS message---
Toast.makeText(context, str, Toast.LENGTH_LONG).show();
Manager.toastIt(context, str);
// Send the sms to the server
//Connection.send(new Transmit("SmsReceived",s));
}
}
}
This works great!.
And here comes the question. Is it posible to refactore my code to achive the following:
Have a unique indentifier/flag on my send sms so i can make sure which sms i receive a status on. As you can see i have already tried to put extra on my 2 intents, and maybe that is the right way, but not only do i not now how to check/receive/extract the flag for the status, but also the flag really "unique" right now.
Its nice that I can revieve a sms, but when its more than 160 chars it only shows me the first 160 chars. I had looked at how GTalkSMS does it, but was hoping my code could just be refactored a bit :)
The last problem is, a mix of the 2 above. I cant send a sms thats more than 160 char. I know i have to use sendMultipartTextMessage, but i dont know how. My thought is that i could devide the "String message" by 100 to a Array but i dont know.
So feel free to refactore the code. I'm looking forward to see your replies! :D
Please ask if you need anything explained better or more code! :)
Not Android specific, but read about the "Concatenated SMS" standard. Basically it's multiple messages that each specify they go with the previous one, but it goes over the air as entirely independent SMS.
Most phones hide this fact from the user, of course, but if you're directly receiving SMS it's likely you'll need to deal with it yourself - sending and receiving. Assuming Android uses this standard, which seems like a safe bet.
Since it's so common, I'm sure you can find a library that somebody's already written.
http://en.wikipedia.org/wiki/Concatenated_SMS
Everything you asked for is in the GTalkSMS code (seems you have missed it). :-) But I will point you to the right snippets.
In order to use sendMultipartTextMessage() and distinguish the different sent/delivered notification intents you need first to split the message string via SmsManager.divideMessage(message) and create two, one for sent notifications and one for the delivered notifications, PendingIntents ArrayLists, where, and this is the important part, every PendingIntent has to be created with a a unique request int:
PendingIntent.getBroadcast(context, UNIQUE_ID, deliveredIntent, PendingIntent.FLAG_ONE_SHOT)
This assures that andoird will broadcast an unique intent for every sent delivered notification. You can also add some extras to the intent, which could later tell you for which SMS the notification was.
Code snippets can be found here: sendSMSByPhoneNumber()
Make sure that your SmsReceiver is aware that an incoming intent can contain more that one SMS for multiple senders, but a maximum of nbfOfpdus different senders. The GTalkSMS receiver will sure help you understand how to get this going. :)