Android Tutorial Intent Filters - Intercepting SMS messages in the background

Status
Not open for further replies.
Old tutorial. Don't use services. Use receivers.
Broadcast receivers are program components that can handle broadcasted messages. These messages usually notify about a system event.

There are two types of receivers in Android: statically registered receivers and dynamically registered receivers.

Static registered receivers are receivers that are declared in the manifest file.
Dynamic registered receivers are registered at runtime by calling the Java registerReceiver method.

In Basic4android you can register dynamic receivers with the BroadcastReceiver library. PhoneEvents and SmsInterceptor objects from the Phone library also use dynamic registration to listen for common intents.

Difference between static and dynamic receivers
The main difference between the two types of receivers is that dynamic receivers listen to intents as long as the process is running.

Static receivers always work. If the process is not running then it will be created.

Normal processes eventually get killed. This means that you cannot rely on dynamic receivers to intercept intents when your application is in the background. A possible workaround is to call Service.StartForeground in the service. This will prevent the process from being killed. However this will also add an ongoing notification icon (see the Services tutorial for more information).

So if you need to always listen for a specific type of intents then you may prefer to use a static receiver. Note that some intents can only be intercepted with dynamic receivers.

Static receivers
Each service module in Basic4android is made of two components. The service and a receiver. The receiver responsibility is to delegate broadcast intents to the service. For example when you call StartServiceAt, it is the receiver that actually intercepts the intent and wakes the service.

If we want to listen for intents we need to define an intent filter in the manifest file. See this link for more information about intent filters.

For example if we want to listen for intents with the action: android.provider.Telephony.SMS_RECEIVED we will need to add the following manifest editor code:
B4X:
AddPermission(android.permission.RECEIVE_SMS)
AddReceiverText(s1,
<intent-filter>
    <action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>)
s1 is the name of the service module that the intent will be delegated to.
We also add the RECEIVE_SMS permission which is required in this case.

Once this program is installed the service will be started each time that an Sms message arrives. It doesn't matter whether the process is running or not.

In our Service_Start event we check the intent action. If it fits then the messages will be parsed from the intent. This is done with the help of the Reflection library:
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

Update 2018: Static intent filters will cause the service to start while the app is not in the foreground. This means that on newer devices it will only work with B4A v8+ and that we need to call Service.StopAutomaticForeground once the task has completed.
https://www.b4x.com/android/forum/threads/automatic-foreground-mode.90546/#post-572424
 
Last edited:

sconlon

Active Member
Licensed User
Longtime User
Thanks for the info Erel it seems to be what I need. However, when I added an S1 service module to my app with the code you gave and made the changes to the manifest file I got the following java error in the log:

java.lang.Exception: Sub service_create signature does not match expected signature.

and a msgbox on screen saying "Sorry!" The application has stopped unexpectedly, Please try again.

What have I done wrong or failed to do?

Thanks.
 

flyingbag

Member
Licensed User
Longtime User
Using this method of SMS interception: I am wondering if there is a way to "trap" the intercepted message and not display to the user in the SMS manager

Just like in SMS Interceptor, you can return "True" from the handling sub to prevent this SMS being shown to the user...

Thanks
flyingbag
 

lymey

Active Member
Licensed User
Longtime User
Intercepting multi part sms

I am working on a project that will receive large sms messages..i.e multipart messages.
Since the interceptor receives one part at a time as a separate SMS, is there a way of looking at the UDH so that I can piece the messages together or some way that the interceptor can concatenate the messages into a single message?

Thanks!
:sign0104:
 

asillato

New Member
Licensed User
Longtime User
SMS over 160 chars

Hi guys,

do you know if Phone Library implements SMS_Interceptor for sms with most of 160 chars?

TX
 

djpero

Member
Licensed User
Longtime User
Hi Erel,

it is late to initialize sms interceptor on intent action SMS_RECEIVED? I cannot get into SI_MessageReceived Sub.

Thnx
 

djpero

Member
Licensed User
Longtime User
Hi Erel,

it is late to initialize sms interceptor on intent action SMS_RECEIVED? I cannot get into SI_MessageReceived Sub.

Thnx

Yes it is possible but another app is blocking sms_intercept to work.
 

airblaster

Active Member
Licensed User
Longtime User
Hi Erel,

I'm trying to use your method to intercept Share Intents (android.intent.action.SEND) and search intents (android.intent.action.SEARCH).
But for some reason I don't get it working.

I've added the following Code to the manifest editor:
B4X:
AddReceiverText(SuchIntent, 
<intent-filter>
    <action android:name="android.intent.action.SEND" />
    <category android:name="android.intent.category.DEFAULT" />
   <data android:mimeType="text/plain" />
</intent-filter>)
AddReceiverText(SuchIntent, 
<intent-filter>
    <action android:name="android.intent.action.SEARCH" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>)

The service Module "SuchIntent" contains the following code:
B4X:
'Service module
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.
End Sub
Sub Service_Create

End Sub

Sub Service_Start (StartingIntent As Intent)
   Dim keyword As String
   If StartingIntent.Action = "android.intent.action.SEND" Then
      keyword = StartingIntent.GetExtra("android.intent.extra.TEXT")
       Log("Extras:"&StartingIntent.ExtrasToString)
      Log("GetData:"&StartingIntent.GetData)
      Log("GetExtra"&StartingIntent.GetExtra("android.intent.extra.TEXT"))
      Log(StartingIntent.HasExtra("EXTRA_TEXT"))
   Else If StartingIntent.Action = "android.intent.action.SEARCH" Then
      keyword = StartingIntent.GetExtra("query")
   Else
      Return
    End If   
   Suche.SearchState = Suche.SS_RESULT_SUCCESS
   Suche.SearchResult = keyword
   DB.AddVerlauf(keyword)
   StartActivity(Suche)   
End Sub

Sub Service_Destroy

End Sub
If I open the phones browser, select some text and the either click on Share or Search my Application isn't shown in the list.

Is there something wrong with my code, or is this a Bug in B4A?
 

airblaster

Active Member
Licensed User
Longtime User
Hi Erel,

thanks for pointing this out. I changed the Manifest text to:
B4X:
AddActivityText(SuchIntent, 
<intent-filter>
    <action android:name="android.intent.action.SEND" />
    <category android:name="android.intent.category.DEFAULT" />
   <data android:mimeType="text/plain" />
</intent-filter>)
AddActivityText(SuchIntent, 
<intent-filter>
    <action android:name="android.intent.action.SEARCH" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>)

For some reason, the Application still doesn't appear in the Share popup.
 

airblaster

Active Member
Licensed User
Longtime User
Just figured it out myself: The intent doesn't work in Service Modules, but it works in Activity Modules.
 

zekigultekin

Member
Licensed User
Longtime User
SmsInterceptor problem

when i received new sms i have this error. how can i solve it ??


java.lang.RuntimeException: Error receiving broadcast Intent { act=android.provider.Telephony.SMS_RECEIVED flg=0x30 (has extras) } in anywheresoftware.b4a.phone.PhoneEvents$SMSIntercep tor$1@426deee8

:sign0085:
 

guidoarfini

Member
Licensed User
Longtime User
android.provider.Telephony.SMS_SENT

i have add in manifest

<action android:name="android.provider.Telephony.SMS_SENT" />

AddPermission(android.permission.RECEIVE_SMS)
AddReceiverText(SerSMS,
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.provider.Telephony.SMS_SENT" />
</intent-filter>)

but.... how do intercept sms sent in Service?
 
Status
Not open for further replies.
Top