Android Question [Solved] Intercept incoming SMS and understand the SIM on which the SMS arrived on a Dual SIM Phone

Anser

Well-Known Member
Licensed User
Longtime User
Hi,

I can programmatically read the incoming SMS message and the sender's mobile number. It is working fine.

Here comes the problem, I have a dual SIM phone and the SMS can arrive on any of the 2 numbers. I want to interpret and understand on which number the SMS message arrived.

I am using the following code to intercept the incoming SMS. It is the same code provided in the post https://www.b4x.com/android/forum/t...cepting-sms-messages-in-the-background.20103/

B4X:
'Service module
Sub Process_Globals
   Type Message (Address As String, Body As String)
End Sub
Sub Service_Create

End Sub

Sub Service_Start(startingIntent As Intent)
   If startingIntent.Action = "android.provider.Telephony.SMS_RECEIVED" Then
      Dim messages() As Message
      messages = ParseSmsIntent(startingIntent)
      For i = 0 To messages.Length - 1
         Log(messages(i))
      Next
   End If
   Service.StopAutomaticForeground
End Sub

'Parses an SMS intent and returns an array of messages
Sub ParseSmsIntent (in As Intent) As Message()
   Dim messages() As Message
   If in.HasExtra("pdus") = False Then Return messages
   Dim pdus() As Object
   Dim r As Reflector
   pdus = in.GetExtra("pdus")
   If pdus.Length > 0 Then
      Dim messages(pdus.Length) As Message
      For i = 0 To pdus.Length - 1
         r.Target = r.RunStaticMethod("android.telephony.SmsMessage", "createFromPdu", _
            Array As Object(pdus(i)), Array As String("[B"))
         messages(i).Body = r.RunMethod("getMessageBody")
         messages(i).Address = r.RunMethod("getOriginatingAddress")
      Next
   End If
   Return messages
End Sub

From the above code, the Sub ParseSmsIntent() is used to identify the sender's number and the message body. I would like to know the number to which the SMS has arrived on a dual SIM phone.

Please help
 

drgottjr

Expert
Licensed User
Longtime User
when you say:
I want to interpret and understand on which number the SMS message arrived.
by "number", do you mean which sim? you say you already know the sender's mobile phone number.

if you mean which sim, that information should be available in the intent's extras. if you log intent.extrastostring, you can see all the available extras.
as far as the sim is considered, it is available under different names (depending on the device). you might see it as "slot" or "id" or "subscription".
if the app is intended for multiple devices, you will have to find out all the possibilities and test for them all when you handle the incoming sms.
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
by "number", do you mean which sim? you say you already know the sender's mobile phone number.
Yes, you are right. I meant the SIM on which the SMS received.

Your solution works. The phone that I tested is a Samsung phone. The following code serves my purpose. It will give you the SIM slot.
B4X:
in.GetExtra("android.telephony.extra.SLOT_INDEX")
Now the next task is to get the SIM numbers based on the SIM slot index number

Thank you
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
assuming your receiver looks more or less like this:

B4X:
Sub Process_Globals
    Private jo,smanager,sinfo As JavaObject
End Sub

'Called when an intent is received.
'Do not assume that anything else, including the starter service, has run before this method.
Private Sub Receiver_Receive (FirstTime As Boolean, StartingIntent As Intent)
    jo.initializecontext
    Log("Receiver started")
    Log( "started by: " & StartingIntent.Action)
    Log("extras: " & StartingIntent.ExtrasToString)
    Dim subid As Int = StartingIntent.GetExtra("subscription")
    
    smanager = jo.RunMethod("getSystemService",Array As String ("telephony_subscription_service"))
        
    sinfo = smanager.RunMethod("getActiveSubscriptionInfo",Array(subid))
    Log("your carrier: " & sinfo.runmethod("getCarrierName",Null))
End Sub

you can derive the carrier that handled the sms. i tried it on android 12 and 14.
 
Last edited:
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
assuming your receiver looks more or less like this:

B4X:
Sub Process_Globals
    Private jo,smanager,sinfo As JavaObject
End Sub

'Called when an intent is received.
'Do not assume that anything else, including the starter service, has run before this method.
Private Sub Receiver_Receive (FirstTime As Boolean, StartingIntent As Intent)
    jo.initializecontext
    Log("Receiver started")
    Log( "started by: " & StartingIntent.Action)
    Log("extras: " & StartingIntent.ExtrasToString)
    Dim subid As Int = StartingIntent.GetExtra("subscription")
 
    smanager = jo.RunMethod("getSystemService",Array As String ("telephony_subscription_service"))
    
    sinfo = smanager.RunMethod("getActiveSubscriptionInfo",Array(subid))
    Log("your carrier: " & sinfo.runmethod("getCarrierName",Null))
End Sub

you can derive the carrier that handled the sms. i tried it on android 12 and 14.
This is how I process the SMS. The Sub ParseSmsIntent is called from Service_Start

B4X:
Sub Service_Start (StartingIntent As Intent)
    Log("MySMSReader Service Started")
    If StartingIntent.Action = "android.provider.Telephony.SMS_RECEIVED" Then
        Dim messages() As Message
        messages = ParseSmsIntent(StartingIntent)
    End If
    Service.StopAutomaticForeground 'Call this when the background task completes (if there is one)
End Sub


B4X:
Sub ParseSmsIntent (in As Intent) As Message()
    Log("Inside ParseSmsIntent")
    Dim messages() As Message
    If in.HasExtra("pdus") = False Then Return messages
    Dim pdus() As Object
    Dim r As Reflector
    pdus = in.GetExtra("pdus")
    If pdus.Length > 0 Then
        Dim messages(pdus.Length) As Message
        For i = 0 To pdus.Length - 1
            r.Target = r.RunStaticMethod("android.telephony.SmsMessage", "createFromPdu", _
            Array As Object(pdus(i)), Array As String("[B"))
            messages(i).Body = r.RunMethod("getMessageBody")
            messages(i).Address = r.RunMethod("getOriginatingAddress")
            messages(i).SimIndex = in.GetExtra("android.telephony.extra.SLOT_INDEX")  'Here I get the SIM slot number
         
            Log("Sim Index is" & messages(i).SimIndex)

        Next
    End If
    Return messages
End Sub

This is the result of in.ExtrasToString
Intent Extras = Bundle[{android.telephony.extra.SUBSCRIPTION_INDEX=2, messageId=-3135271800800894780, format=3gpp, android.telephony.extra.SLOT_INDEX=0, pdus=[[7, -111, 25, -119, 4, 16, -111, 6, 4, 12, -111, 25, -119, 89, -112, 96, 32, 0, 0, 66, 32, 2, 113, 18, 33, 34, 9, -62, -80, -72, 14, -54, -27, 114, 57]], phone=0, subscription=2}]

I tried your code but I get a runtime error at the line
sinfo = smanager.RunMethod("getActiveSubscriptionInfo",Array(subid))

mysmsreceiver_parsesmsintent (java line: 232)
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:132)
at smsrdr.kkk.mysmsreceiver._parsesmsintent(mysmsreceiver.java:232)
at smsrdr.kkk.mysmsreceiver$ResumableSub_Service_Start.resume(mysmsreceiver.java:324)
at smsrdr.kkk.mysmsreceiver._service_start(mysmsreceiver.java:259)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:213)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:193)
at smsrdr.kkk.mysmsreceiver.handleStart(mysmsreceiver.java:100)
at smsrdr.kkk.mysmsreceiver.access$000(mysmsreceiver.java:8)
at smsrdr.kkk.mysmsreceiver$2.run(mysmsreceiver.java:80)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8663)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
Caused by: java.lang.SecurityException: getActiveSubscriptionInfo
at android.os.Parcel.createExceptionOrNull(Parcel.java:2438)
at android.os.Parcel.createException(Parcel.java:2422)
at android.os.Parcel.readException(Parcel.java:2405)
at android.os.Parcel.readException(Parcel.java:2347)
at com.android.internal.telephony.ISub$Stub$Proxy.getActiveSubscriptionInfo(ISub.java:1376)
at android.telephony.SubscriptionManager.getActiveSubscriptionInfo(SubscriptionManager.java:1411)
... 19 more
 
Last edited:
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
when you get errors like java.lang.SecurityException: getActiveSubscriptionInfo, you should get in the habit of passing the message to a google search.
it often leads right to the answer. do you have the right permissions? did you handle runtime the ones that are to be handled runtime?
 
Upvote 0

Anser

Well-Known Member
Licensed User
Longtime User
when you get errors like java.lang.SecurityException: getActiveSubscriptionInfo, you should get in the habit of passing the message to a google search.
it often leads right to the answer. do you have the right permissions? did you handle runtime the ones that are to be handled runtime?
You are right. It was a permission issue. The app requires the following runtime permission
B4X:
rp.CheckAndRequest(rp.PERMISSION_READ_PHONE_STATE)
Wait For Activity_PermissionResult (Permission As String, Result As Boolean)

All these are working
B4X:
sinfo = smanager.RunMethod("getActiveSubscriptionInfo",Array(subid))
Log("your carrier: " & sinfo.runmethod("getCarrierName",Null)) 'Returns provider name
Log("getMccString : " & sinfo.runmethod("getMccString",Null))
Log("MNCString : " & sinfo.runmethod("getMncString",Null))

Still struggling to identify the Mobile numbers of the SIM cards inserted on the phone ? Wonder how it's possible for some apps to display the mobile numbers available on a device as a List and ask the user to choose one.

My Samsung Phone itself shows the inserted SIM card numbers via Settings->Connections->SIM Card Manager
B4X:
Log("getNumber() : " & sinfo.runmethod("getNumber",Null)) 'Returns nothing

Maybe it is better to ask the user to enter the phone numbers by himself
 
Last edited:
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
this is a different issue. you should mark the initial thread as solved and start a new thread. i realize these are related
topics, but, eg, someone who might know about getting phone numbers might not see the question because the thread
has to do with identifying which sim handled the call.

official calling apps can pretty much do what they want. have your app made a calling app and see if things change.

i can obtain the phone number with android 14. the method was added for sdk34. i was surprised to see it. even more
surprised when it worked, given that google is making it more and more difficult with its various privacy rules. in my example
i don't think i used getNumber().
 
Upvote 0
Top