I am successfully sending multi-part (concatenated) messages through android using Xamarin Studio and the SMS.Telephony.SmsManager Android library.
To send a message I am doing the following:
var longMessage = "This is a cØncatenated message sent to you through an android. This should appear as a single message. Hopefully it's as easy as that. It even has a function to break the message up. It probably took me longer to install Xamarin then it did to write the code and send the actual message";
var smsMgr = Android.Telephony.SmsManager.Default;
System.Collections.Generic.IList<string> parts = smsMgr.DivideMessage(longMessage);
IList<PendingIntent> pendingIntents = new List<PendingIntent>(parts.Count);
for (int i = 0; i < parts.Count; i++)
{
var intent = new Intent(DeliveryIntentAction);
intent.PutExtra("MessagePartText", parts[i]);
intent.PutExtra("MessagePartId", i.ToString());
PendingIntent pi = PendingIntent.GetBroadcast(this, 0, intent, 0);
pendingIntents.Add(pi);
}
smsMgr.SendMultipartTextMessage("17057178131",null, parts, pendingIntents, null);
I then have a receiver for the pending Intents that looks like this:
[BroadcastReceiver(Enabled = true)] //(Exported = true, Permission = "//receiver/#android:android.permission.SEND_SMS")]
[IntentFilter(new[] { DeliveryIntentAction }, Priority = int.MaxValue)]
public class SMSSentReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
if (intent.GetStringExtra ("MessagePartId") != null)
lbl.Text += " Sent Response " + intent.GetStringExtra ("MessagePartId") + System.Environment.NewLine;
...
However, each time OnRecieve is called, intent.GetStringExtra("MessagePartId") has a value of "0" and the MessagePartText is the first part, not the part number/text that belongs to the message part sent.
Can anyone see why this may be the case?
Thank you
Using
PendingIntent pi = PendingIntent.GetBroadcast(this, 0, intent, 0);
attempts to override the existing pendingIntent.
To create a NEW intent and have it waiting, I had to change the requestCode parameter of GetBroadcast.
PendingIntent pi = PendingIntent.GetBroadcast(this, i, intent, 0);
Thanks
Related
I am developing an Android application in which I would like to receive a Push notification when application state is both in Foreground and Background.
It was working fine before the click_action is added but after adding it does not make the push notification received when the application is background or killed. After some research, I could understand that I will not be able to receive the Push in Background if the FCM is "notification" message type but only "data" message type.
As FCM provides click_action attribute by default and also provides the method getClickAction() to get it in onMessageReceived(), Should I really use click_action in data message ?
The bundle in onMessageReceived
Bundle[{
google.sent_time = 1521177008895,
google.ttl = 3600,
gcm.notification.e = 1,
lastName = Test,
profileUrl = ,
roleId = ,
userId = 140128,
gcm.notification.badge = 1,
gcm.notification.sound =
default,
gcm.notification.title = Someone
try to login with your credentials,
roleName = ,
userName = test,
flag = 0,
from = 612005318045,
type = 0,
gcm.notification.sound2 = simpleSound,
firstName = Test,
gcm.notification.notification_id = 1140,
google.message_id = 0: 1521177008900292 % c05b1316c05b1316,
notification = Someone
try to login with your credentials,
gcm.notification.body = Someone
try to login with your credentials,
gcm.notification.icon = myApp,
notificationId = 2047669,
gcm.notification.notification_type = 1,
gcm.notification.click_action = com.my.push.activities.OPEN_NOTIFICATION_LIST,
gcm.notification.notification_message = TEST MESSAGE,
notificationDate = Fri Mar 16 05: 10: 08 GMT 2018,
collapse_key = com.my.push,
gcm.notification.notification_title = APP
}]
The code snippet of the way it is handled in onMessageReceived
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
......
......
showNotification(remoteMessage);
}
public void showNotification(RemoteMessage remoteMessage) {
try {
Map<String, String> response = remoteMessage.getData();
Intent intent = prepareIntent(remoteMessage);
PendingIntent pIntent = PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "D4E_ANDROID")
.setContentTitle("New Notification")
.setContentText(response.get("notification"))
.setSmallIcon(R.drawable.d4e_logo)
.setContentIntent(pIntent)
.setAutoCancel(true)
.addAction(R.drawable.view_icon, "View", pIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(Integer.parseInt(response.get("notificationId")), builder.build());
} catch (Exception exception) {
Log.e("OnREC", exception.toString());
}
}
public Intent prepareIntent(RemoteMessage remoteMessage) {
Map<String, String> response = remoteMessage.getData();
Intent intent;
boolean isAppInBackground;
if (SessionContext.isLoggedIn()) {
isAppInBackground = SessionHelper.initializeSessionHelper().isAppInBackground(this);
Log.e("LOGGGGG", isAppInBackground + "");
if (isAppInBackground) {
intent = new Intent(this, SplashScreen.class);
} else {
intent = new Intent(remoteMessage.getNotification().getClickAction());
}
}
} else {
intent = new Intent(this, LoginActivity.class);
}
return intent;
}
Please anyone guide me to find the solution.
if you can receive FCM notification sent through console, then potentially something is wrong with build the notification. one suspect is that you are not using "icon" field.
If you can debug android device, set breakpoint here and see if you get error or missed some resource.
https://github.com/evollu/react-native-fcm/blob/master/android/src/main/java/com/evollu/react/fcm/SendNotificationTask.java#L46
I have android service written using Xamarin Studio and I'm trying to send sms message from this service automatically. For sending I use the following code:
SmsManager.Default.SendTextMessage("+7926736XXXX", null, "Simple Service sent you a message", null, null);
As a result SMS didn't sent to other mobile but left in SMS list marked by red triangle. I can send them later by hands without any problem. Can anybody know where may be my error?
Try this,
SmsManager sms = SmsManager.getDefault();
PendingIntent sentPI;
String SENT = "SMS_SENT";
sentPI = PendingIntent.getBroadcast(this, 0,new Intent(SENT), 0);
sms.sendTextMessage("+7926736XXXX", null, message, sentPI, null);
OR
send it in intent like this
var smsUri = Android.Net.Uri.Parse("smsto:7926736XXXX");
var smsIntent = new Intent (Intent.ActionSendto, smsUri);
smsIntent.PutExtra ("sms_body", "Hello from Xamarin.Android");
StartActivity (smsIntent);
hope this will help.
Try checking the SmsResultError and SmsStatus of the sent and delivered intents to determine why your SMS is not working.
Add BroadcastReceiver inner class to your Service:
public YourSMSService : Service
{
const string SentAction = "SentAction";
const string DeliveredAction = "DeliveredAction";
SmsReceiver smsReceiver;
~~~~
class SmsReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action == SentAction)
{
// `Log` it if needed...
Toast.MakeText(context, $"{(SmsResultError)ResultCode}", ToastLength.Long).Show();
}
if (intent.Action == DeliveredAction)
{
// `Log` it if needed...
Toast.MakeText(context, $"{(SmsStatus)ResultCode}", ToastLength.Long).Show();
}
}
}
~~~~
}
Create/Register the BroadcastReceiver (usually done in the Service .actor)
smsReceiver = new SmsReceiver();
RegisterReceiver(smsReceiver, new IntentFilter(SentAction));
RegisterReceiver(smsReceiver, new IntentFilter(DeliveredAction));
Supply sent and delivered PendingIntents to the SendTextMessage:
var sentIntent = PendingIntent.GetBroadcast(this, 0, new Intent(SentAction), 0);
var deliveredIntent = PendingIntent.GetBroadcast(this, 0, new Intent(DeliveredAction), 0);
SmsManager.Default.SendTextMessage("1234567890", null, "Simple Service sent you a message", sentIntent, deliveredIntent);
Now when you send an SMS in your service, you will get a Toast message of the status.
The question is closed. This is the hardware problem of the my phone. I connected my 10 yeas old chinese Samsung Galaxy copy and my application immediately started to work
I am currently trying to get the confirmation for each sended SMS. I need to be sure that my SMS are send, so I used a BroadCastReceived to get the information :
Intent sentIntent = new Intent(SMS_SEND);
sentIntent.putExtra("key", idSms);
PendingIntent sentPI = PendingIntent.getBroadcast(getApplicationContext(), 0, sentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
SmsManager manager = SmsManager.getDefault();
try{
manager.sendTextMessage(exp, null, sms, sentPI, null);
put("sending " + sms); //Just a method to print in a textview use has a console
} catch (IllegalArgumentException e){
put("Exception " + e.getMessage());
}
and use a broadcast receiver like this
public void onReceive(Context context, Intent intent){
String idsms = intent.getExtras().getString("key");
switch (getResultCode()) {
case Activity.RESULT_OK:
put("ACK : #" + idsms);
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
case SmsManager.RESULT_ERROR_RADIO_OFF:
case SmsManager.RESULT_ERROR_NULL_PDU:
case SmsManager.RESULT_ERROR_NO_SERVICE:
put("BOOM " + getResultCode() + "\n\tfrom sms #" + idsms);
break;
}
}
This work like a charm until I try to send multiple messages at the same time, the extra receive is always from the last SMS send, so I can't ID which text are send and which are not.
Here is a simple example of what will happen.
When I use a loop to send 3sms:
id : 1, message : SMS 1
id : 2, message : SMS 2
id : 3, message : SMS 3
And the received will get:
ACK : #3
ACK : #3
ACK : #3
I understand that this come from the PendingIntent.FLAG_UPDATE_CURRENT but I can't find a solution. Anyone can explain to me how I should use the PendingIntent.getBroadcast(..) to be able to manage this or at least to put me on the right track.
Your problem is due the fact that PendingIntents can be reused by the system, if certain things about the requests are not different. In your code, you're passing FLAG_UPDATE_CURRENT, which is causing the stored Intent and its extras to be updated each time a PendingIntent is requested. This is why you're getting id : 3 for each of the messages. To correct this, you can call getBroadcast() with a unique request code (the second parameter) each time, which will create a new PendingIntent for each request, each with a separate Intent with their own extras.
In your case, the fix should be simple, assuming that idSms is unique for each message.
PendingIntent sentPI = PendingIntent.getBroadcast(getApplicationContext(),
Integer.parseInt(idSms),
sentIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
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();
}
}
From android KitKat when my application is set as the default one, sent sms messages should not be written to the content provider by system:
Note: Beginning with Android 4.4 (API level 19), if and only if an app is not selected as the default SMS app, the system automatically writes messages sent using this method to the SMS Provider (the default SMS app is always responsible for writing its sent messages to the SMS Provider). For information about how to behave as the default SMS app, see Telephony.
But every message I send is automatically written without my interaction (I just call sendTextMessage() and it's taken care of)
May it be a bug in CyanogenMod or I am missing something?
Here is my Code:
#SuppressLint("NewApi")
public static void sendMessage(String messageBody, String phoneNumber,
Context context) {
if (messageBody.length() > 0 && phoneNumber.length() > 0) {
SmsManager sms = SmsManager.getDefault();
ArrayList<String> parts = sms.divideMessage(messageBody);
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
if (prefs.getBoolean(SettingsActivity.KEY_SPLIT, false)) {
for (String singlePart : parts) {
sms.sendTextMessage(phoneNumber, null, singlePart, null,
null);
}
} else {
sms.sendMultipartTextMessage(phoneNumber, null, parts, null,
null);
}
}
/**
* Add message to content provider (after KitKat)
*/
// if (android.os.Build.VERSION.SDK_INT >=
// android.os.Build.VERSION_CODES.KITKAT) {
// Log.d(null, "adding sms to content provider");
// ContentValues values = new ContentValues();
// values.put(Telephony.Sms.ADDRESS, phoneNumber);
// values.put(Telephony.Sms.BODY, messageBody);
// // values.put(Telephony.Sms.READ, 0);
// values.put(Telephony.Sms.DATE, System.currentTimeMillis());
// // values.put(Telephony.Sms._ID,
// // msgs[i].getIndexOnIcc());
// context.getContentResolver().insert(Telephony.Sms.Sent.CONTENT_URI,
// values);
// }
}
I don't know why, but when I added sent and delivered pending intent new sms is not automatically added to content provider. This solved my problem
PendingIntent sentPI = PendingIntent.getBroadcast(this, 0,
new Intent(SENT), 0);
PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0,
new Intent(DELIVERED), 0);
sms.sendTextMessage(phoneNo, null, singlePart, sentPI, deliveredPI);
Code from this question: Trouble with sendMultipartText in android
I noticed the same bug in my app on two devices. All with custom roms (CM based).
Try to use this library android smsmms sending library and if the issue persists, it may mean that there is something wrong with your manifest file.