B4A Library PhoneLibrary: Updated PhoneSms.Send

Sorin Pohontu

Member
Licensed User
Hello Erel.

As seen on this forum post, SmsSentStatus / SmsDelivered might not return the correct PhoneNumber.
Also, current implementation of Send/Send2 will not work correctly is the message is longer than 160 chars.

I've seen somewhere a post from Erel about original Java function for Send/Send2 and I've tried to find a working solution.

1. Original function PhoneSms.Send2 is using the same requestCode for sending / pending Intent (0) with flag FLAG_UPDATE_CURRENT (134217728). On subsequent messages, the Intent data is updated / overwritten. The solution is to use an unique Intent requestCode for each message sent.

2. I needed a working solution for MultiPart Messages.

3. I needed additional data when sending a message. Current Send2 adds only PhoneNumber in Intent extra data:
B4X:
i1.putExtra("phone", PhoneNumber);
My current solution is using Java inline code (thanks for that in B4A since 4.30) and I think it would be nice to have this in official Phone library.

B4X:
#If JAVA
import java.util.Random;
import java.util.ArrayList;
import java.util.Map;
import android.content.Context;
import android.content.Intent;
import android.app.PendingIntent;
import android.telephony.SmsManager;

public static void Send3(String PhoneNumber, String Text, Map<String, String> Extra, boolean ReceiveSentNotification, boolean ReceiveDeliveredNotification) {
    SmsManager sm = SmsManager.getDefault();

    /* Generate a unique requestCode for each Intent */
    Random randomNo = new Random();
    int requestCode = (int)(System.currentTimeMillis()/1000) + randomNo.nextInt(1000);

    Intent mSendIntent = new Intent("b4a.smssent");
    mSendIntent.putExtra("phone", PhoneNumber);

    // Add additional Extra Data
    for (Map.Entry<String, String> entry : Extra.entrySet()) {
        mSendIntent.putExtra(entry.getKey(), entry.getValue());
    }
    PendingIntent sentIntent = ReceiveSentNotification ? PendingIntent.getBroadcast(BA.applicationContext, requestCode, mSendIntent, PendingIntent.FLAG_UPDATE_CURRENT) : null;

    Intent mDeliveryIntent = new Intent("b4a.smsdelivered");
    mDeliveryIntent.putExtra("phone", PhoneNumber);

    // Add additional Extra Data
    for (Map.Entry<String, String> entry : Extra.entrySet()) {
        mDeliveryIntent.putExtra(entry.getKey(), entry.getValue());
    }
    PendingIntent deliveryIntent = ReceiveDeliveredNotification ? PendingIntent.getBroadcast(BA.applicationContext, requestCode, mDeliveryIntent, PendingIntent.FLAG_UPDATE_CURRENT) : null;

    if (Text.length() > 160) {
        ArrayList<String> parts = sm.divideMessage(Text);
        int numParts = parts.size();
        ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
        ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>();
        for (int i = 0; i < numParts; i++) {
            if (ReceiveSentNotification) {
                sentIntents.add(PendingIntent.getBroadcast(BA.applicationContext, requestCode, mSendIntent, PendingIntent.FLAG_UPDATE_CURRENT));
            }
            if (ReceiveDeliveredNotification) {
                deliveryIntents.add(PendingIntent.getBroadcast(BA.applicationContext, requestCode, mDeliveryIntent, PendingIntent.FLAG_UPDATE_CURRENT));
            }
        }
        sm.sendMultipartTextMessage(PhoneNumber, null, parts, ReceiveSentNotification ? sentIntents : null, ReceiveDeliveredNotification ? deliveryIntents : null);
    }
    else {
        sm.sendTextMessage(PhoneNumber, null, Text, sentIntent, deliveryIntent);
    }
}
#End If
Usage with message as a Map:
B4X:
Sub SendSMS(Message As Map)
   Dim Extra As Map

   ' Extra Data
   Extra.Initialize
   Extra.Put("message_id", "xxxx")

   NativeMe.RunMethod("Send3", Array(Message.Get("to"), Message.Get("message"), Extra, true, true))
End Sub
Now, In SmsSentStatus / SmsDelivered, I can extract Extra info with:
B4X:
Log(Intent.GetExtra("phone"))
Log(Intent.GetExtra("message_id"))
I'm looking forward for feedback :)

Have a nice day,
/Sorin
 
Last edited:

Tayfur

Well-Known Member
Licensed User
I added something for fix

add lib : javaobject

B4X:
Sub Globals
     Public NativeMe As JavaObject
end sub

Sub SendSMS(Message As Map)
   Dim Extra As Map

   ' Extra Data
   Extra.Initialize
   Extra.Put("message_id", "msj_id_"&Message.Get("to"))
    NativeMe=Me ' >>> I add it
   NativeMe.RunMethod("Send3", Array(Message.Get("to"), Message.Get("message"), Extra, True, True))
End Sub
 

Tayfur

Well-Known Member
Licensed User
NativeMe Object should be initialized, I assumed in this example that is initialized before :)

it is work; I looked some error and i searched for fix (Because I am not expert, I dont know java).
I use your code.
finally your code is work. nice job.
thanks.
 

Jeffrey Cameron

Well-Known Member
Licensed User
Thank you Sorin! +1 for adding this to the Phone library as a PhoneSms method.

In the application I am developing I need to keep track of the messages I've sent (reply to middle-ware server that they were or were not sent out) and most likely I could have multiple messages to the same telephone number which would make knowing which exact message was sent impossible.

I remembered coming across this post some time ago while I was looking for something else. And while implementing Sorin's code it is not difficult, it did take me almost 40 minutes of searching through the forum to find this exact post (perhaps my search skills are just lacking). So, having a built-in .Send3 method would have been much easier ;)
 
Top