XPA 3.2b Android SMS Listener


Todd Baremore
 

I need my Android app to listen for SMS/Text messages from one or more sources.
The only SMS samples or documentation I can find is for sending.

Has anyone had luck with this?

Todd


Brenda Bullorini
 

Hi Todd, just tested in Android Studio and also in Magic.

package com.magicsoftware.magicdev;
 
import com.magicsoftware.core.CoreApplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.widget.Toast;
 
public class MySmsListener extends BroadcastReceiver {
    
    final SmsManager sms = SmsManager.getDefault();
 
    public void onReceive(Context context, Intent intent) {
 
//Toast.makeText(context, "I got to onReceive", Toast.LENGTH_SHORT).show();
 
        final Bundle bundle = intent.getExtras();
 
        try {
 
            if (bundle != null) {
 
                final Object[] pdusObj = (Object[]) bundle.get("pdus");
 
                for (int i = 0; i < pdusObj.length; i++) {
 
                    SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
                    String phoneNumber = currentMessage.getDisplayOriginatingAddress();
                    String senderNum = phoneNumber;
                    String message = currentMessage.getDisplayMessageBody();                    
CoreApplication.getInstance().invokeExternalEvent("SMSRECEIVED:" + message);
 
                } 
            } 
 
        } catch (Exception e) {
            // Error
//Toast.makeText(context, "Exception" + e.getMessage(), Toast.LENGTH_SHORT).show();
CoreApplication.getInstance().invokeExternalEvent("SMSERROR:" + e.getMessage());
        }
    }
}

On the AndroidManifest.xml add the following lines:
<receiver android:name=".MySmsListener">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
 </receiver>

Build apk.


Then in Magic:



Thinks to keep in mind:

- I added a Toast in the java class, uncomment if you need to see if the sms gets to the android java class.
- Since android >= API 23 needs a different type way of requestion permissions, I use targetSdkVersion 22 on the app build.gradle. I tested this on my cellphone that has android 6.0 and it's working.
- I think that's all!

Let me know if you need any help!!

Brenda


 


Brenda Bullorini
 

Forgot:
I don't know if it works when the app is closed, I'll have to test that out.
I know that everything you put on the java class it will work even with the app closed,
but I don't know if the External Event from Magic will still raise.


Todd Baremore
 

Brenda,
WOW!  What a great way to start a Monday.  Give me a few days to try it and I'll let you know if I run into any problems.
Thank you very much  -  Muchas Gracias

If I ever find myself in Buenos Aires, pick a nice restaurant, dinner is on me.  Bring Nicolas.

Todd


On 6/11/2017 8:59 PM, Brenda Bullorini wrote:

Hi Todd, just tested in Android Studio and also in Magic.

package com.magicsoftware.magicdev;
 
import com.magicsoftware.core.CoreApplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.widget.Toast;
 
public class MySmsListener extends BroadcastReceiver {
    
    final SmsManager sms = SmsManager.getDefault();
 
    public void onReceive(Context context, Intent intent) {
 
//Toast.makeText(context, "I got to onReceive", Toast.LENGTH_SHORT).show();
 
        final Bundle bundle = intent.getExtras();
 
        try {
 
            if (bundle != null) {
 
                final Object[] pdusObj = (Object[]) bundle.get("pdus");
 
                for (int i = 0; i < pdusObj.length; i++) {
 
                    SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
                    String phoneNumber = currentMessage.getDisplayOriginatingAddress();
                    String senderNum = phoneNumber;
                    String message = currentMessage.getDisplayMessageBody();                    
CoreApplication.getInstance().invokeExternalEvent("SMSRECEIVED:" + message);
 
                } 
            } 
 
        } catch (Exception e) {
            // Error
//Toast.makeText(context, "Exception" + e.getMessage(), Toast.LENGTH_SHORT).show();
CoreApplication.getInstance().invokeExternalEvent("SMSERROR:" + e.getMessage());
        }
    }
}

On the AndroidManifest.xml add the following lines:
<receiver android:name=".MySmsListener">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
 </receiver>

Build apk.


Then in Magic:



Thinks to keep in mind:

- I added a Toast in the java class, uncomment if you need to see if the sms gets to the android java class.
- Since android >= API 23 needs a different type way of requestion permissions, I use targetSdkVersion 22 on the app build.gradle. I tested this on my cellphone that has android 6.0 and it's working.
- I think that's all!

Let me know if you need any help!!

Brenda


 


Brenda Bullorini
 

You are welcome! Glad to help.

If I ever find myself in Buenos Aires, pick a nice restaurant, dinner is on me.  Bring Nicolas
Sure!! Just let us know and we'll be waiting!

:)
Brenda


Todd Baremore
 

Brenda,

Its not working.....yet.

I saved your java code to:
C:\mse\xpa_32\RIAModules\Android\Source\app\src\main\java\com\magicsoftware\magicdev\MySmsListener.java

I have two questions that should narrow down the problem:
1.  Where exactly should I update AndroidManifest.xml?  I placed your update at the bottom of the file.  Should it be within an Activity? I bolded your content below
      ...............      
       <activity android:name="SettingsActivity"/>
        <!-- [START firebase_service] -->
        <service
            android:name=".MyFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>
        <receiver
            android:name=".MyFirebaseNotificationDismissReceiver"
            android:exported="false" >
        </receiver>

        <receiver
            android:name=".MyFirebaseNotificationClickReceiver"
            android:exported="false" >
        </receiver>
        <!-- [END firebase_service] -->
        <!-- [START firebase_iid_service] -->
        <service
            android:name=".MyFirebaseInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
            </intent-filter>
        </service>
        <!-- [END firebase_iid_service] -->

<receiver android:name=".MySmsListener">

            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
</receiver>

    </application>
</manifest>

2.  I am able to successfully compile an APK using SDK 21, 22 and 23 but I receive the message below for all 3:
Note: C:\mse\xpa_32\PublishedApplications\EMP_Mobile\Android\source\TEMP_BUILD_FOLDER\app\src\main\java\com\todd\emp\MySmsListener.java uses or overrides a deprecated API.

Let me know if you need any more info.

Thanks

Todd


On 6/11/2017 8:59 PM, Brenda Bullorini wrote:

Hi Todd, just tested in Android Studio and also in Magic.

package com.magicsoftware.magicdev;
 
import com.magicsoftware.core.CoreApplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.widget.Toast;
 
public class MySmsListener extends BroadcastReceiver {
    
    final SmsManager sms = SmsManager.getDefault();
 
    public void onReceive(Context context, Intent intent) {
 
//Toast.makeText(context, "I got to onReceive", Toast.LENGTH_SHORT).show();
 
        final Bundle bundle = intent.getExtras();
 
        try {
 
            if (bundle != null) {
 
                final Object[] pdusObj = (Object[]) bundle.get("pdus");
 
                for (int i = 0; i < pdusObj.length; i++) {
 
                    SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
                    String phoneNumber = currentMessage.getDisplayOriginatingAddress();
                    String senderNum = phoneNumber;
                    String message = currentMessage.getDisplayMessageBody();                    
CoreApplication.getInstance().invokeExternalEvent("SMSRECEIVED:" + message);
 
                } 
            } 
 
        } catch (Exception e) {
            // Error
//Toast.makeText(context, "Exception" + e.getMessage(), Toast.LENGTH_SHORT).show();
CoreApplication.getInstance().invokeExternalEvent("SMSERROR:" + e.getMessage());
        }
    }
}

On the AndroidManifest.xml add the following lines:
<receiver android:name=".MySmsListener">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
 </receiver>

Build apk.


Then in Magic:



Thinks to keep in mind:

- I added a Toast in the java class, uncomment if you need to see if the sms gets to the android java class.
- Since android >= API 23 needs a different type way of requestion permissions, I use targetSdkVersion 22 on the app build.gradle. I tested this on my cellphone that has android 6.0 and it's working.
- I think that's all!

Let me know if you need any help!!

Brenda


 


Brenda Bullorini
 

Hi Todd!
 
I don't have my laptop with me but,
1. Yes, it goes there, sorry I forgot to tell you before!
2. Compile version can be 21, 22, 23 or whatever. But, check the targetSdkVersion, I tried it with 22. 
If you use 23 in targetsdkversion you'll have to add some code to ask for permission to use the Telephony service when api >= 23. 
I think that Magic in the help explains how to do that, but I didn't test it so I'm keeping api 22 in targetsdkversion for now. My cellphone uses api 23 and it worked with targetsdkversion 22.
 
And the message you see is just a warning but is still works.
 
Oh, wait!!! I think I forgot to tell you something, I knew something was missing when I wrote you.
Add to the AndroidManifest file:
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
Where the other permission lines are.
 
Check the targetsdkversion, set it to 22 and try again.
 
If it's still not working, what I would try is:
- Uncomment this line 
//Toast.makeText(context, "I got to onReceive", Toast.LENGTH_SHORT).show();
Just remove the "//"
- Generate new apk. 
- Run app and see if the Toast shows up when sms arrives. Then we can see if it's not getting to java or not getting to magic.
 
Good luck !!!
(And if it's still not working I'll be happy to help through teamviewer or something)


Todd Baremore
 

Brenda,

Hmmmmm....seems like you're holding out for dessert (:-)

I'll give it a try

Thanks

Todd


On 6/13/2017 9:36 AM, Brenda Bullorini wrote:

Hi Todd!
 
I don't have my laptop with me but,
1. Yes, it goes there, sorry I forgot to tell you before!
2. Compile version can be 21, 22, 23 or whatever. But, check the targetSdkVersion, I tried it with 22. 
If you use 23 in targetsdkversion you'll have to add some code to ask for permission to use the Telephony service when api >= 23. 
I think that Magic in the help explains how to do that, but I didn't test it so I'm keeping api 22 in targetsdkversion for now. My cellphone uses api 23 and it worked with targetsdkversion 22.
 
And the message you see is just a warning but is still works.
 
Oh, wait!!! I think I forgot to tell you something, I knew something was missing when I wrote you.
Add to the AndroidManifest file:
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
Where the other permission lines are.
 
Check the targetsdkversion, set it to 22 and try again.
 
If it's still not working, what I would try is:
- Uncomment this line 
//Toast.makeText(context, "I got to onReceive", Toast.LENGTH_SHORT).show();
Just remove the "//"
- Generate new apk. 
- Run app and see if the Toast shows up when sms arrives. Then we can see if it's not getting to java or not getting to magic.
 
Good luck !!!
(And if it's still not working I'll be happy to help through teamviewer or something)


Todd Baremore
 

Brenda,

It works! Just needed to add the permissions. I used SDK 23 on my Android 7 phone. 

You are a lady and a scholar.  I'm throwing in a bottle of champagne to express my gratitude.

Thanks again for all your help.  This adds a whole new dimension of capability to my application.

Todd


On 6/13/2017 9:36 AM, Brenda Bullorini wrote:

Hi Todd!
 
I don't have my laptop with me but,
1. Yes, it goes there, sorry I forgot to tell you before!
2. Compile version can be 21, 22, 23 or whatever. But, check the targetSdkVersion, I tried it with 22. 
If you use 23 in targetsdkversion you'll have to add some code to ask for permission to use the Telephony service when api >= 23. 
I think that Magic in the help explains how to do that, but I didn't test it so I'm keeping api 22 in targetsdkversion for now. My cellphone uses api 23 and it worked with targetsdkversion 22.
 
And the message you see is just a warning but is still works.
 
Oh, wait!!! I think I forgot to tell you something, I knew something was missing when I wrote you.
Add to the AndroidManifest file:
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
Where the other permission lines are.
 
Check the targetsdkversion, set it to 22 and try again.
 
If it's still not working, what I would try is:
- Uncomment this line 
//Toast.makeText(context, "I got to onReceive", Toast.LENGTH_SHORT).show();
Just remove the "//"
- Generate new apk. 
- Run app and see if the Toast shows up when sms arrives. Then we can see if it's not getting to java or not getting to magic.
 
Good luck !!!
(And if it's still not working I'll be happy to help through teamviewer or something)


Brenda Bullorini
 

Great news, Todd!

Really glad it worked :)

Brenda


Tim Downie
 


Hi Brenda/Todd - Im curious as to what this is actually doing - triggering an event in magic when and SMS hits the device?


From: main@magicu-l.groups.io <main@magicu-l.groups.io> on behalf of Brenda Bullorini <bbullorini@...>
Sent: Tuesday, 13 June 2017 3:28 PM
To: main@magicu-l.groups.io
Subject: Re: [magicu-l] XPA 3.2b Android SMS Listener
 
Great news, Todd!

Really glad it worked :)

Brenda


Todd Baremore
 

Tim,


Exactly.   This is the line in Brenda's java code:

CoreApplication.getInstance().invokeExternalEvent("SMSRECEIVED:" + message);

 
In the Main Program add a handler for Event Type: Internal  -  Event: ExternalEvent
The ExternalEvent parameter is a single BLOB. 

You may need to have your mobile app respond to multiple ExternalEvents, each with a different purpose.  This is why Brenda prefaced the parameter with "SMSRECEIVED:" .  In the event handler, this allows me to determine what I need to.  Brenda also raised a separate External Event that started with "SMSERROR:" so I can handle any SMS errors.  If you look at her screen shot, you'll see that she parses the first n characters of the BLOB to determine the purpose of the External Event.

Brenda's code works exactly as needed.  Both your mobile app and regular SMS application receive the messages.  I am only interested in messages from two sources, so I need to add the required logic.  All other messages will be ignored by my app.

Craig posted something similar a few weeks ago with how to call Magic from a web page.  It also used ExternalEvent.

Todd

On 6/14/2017 12:29 AM, Tim Downie wrote:


Hi Brenda/Todd - Im curious as to what this is actually doing - triggering an event in magic when and SMS hits the device?


From: main@magicu-l.groups.io <main@magicu-l.groups.io> on behalf of Brenda Bullorini <bbullorini@...>
Sent: Tuesday, 13 June 2017 3:28 PM
To: main@magicu-l.groups.io
Subject: Re: [magicu-l] XPA 3.2b Android SMS Listener
 
Great news, Todd!

Really glad it worked :)

Brenda


Tim Downie
 

Ive used the external events a long time ago with html.

Does this still invoke magic if the app isnt open on the phone?
From: main@magicu-l.groups.io <main@magicu-l.groups.io> on behalf of Todd Baremore <tbaremor@...>
Sent: Wednesday, 14 June 2017 12:15:10 PM
To: main@magicu-l.groups.io
Subject: Re: [magicu-l] XPA 3.2b Android SMS Listener
 

Tim,


Exactly.   This is the line in Brenda's java code:

CoreApplication.getInstance().invokeExternalEvent("SMSRECEIVED:" + message);

 
In the Main Program add a handler for Event Type: Internal  -  Event: ExternalEvent
The ExternalEvent parameter is a single BLOB. 

You may need to have your mobile app respond to multiple ExternalEvents, each with a different purpose.  This is why Brenda prefaced the parameter with "SMSRECEIVED:" .  In the event handler, this allows me to determine what I need to.  Brenda also raised a separate External Event that started with "SMSERROR:" so I can handle any SMS errors.  If you look at her screen shot, you'll see that she parses the first n characters of the BLOB to determine the purpose of the External Event.

Brenda's code works exactly as needed.  Both your mobile app and regular SMS application receive the messages.  I am only interested in messages from two sources, so I need to add the required logic.  All other messages will be ignored by my app.

Craig posted something similar a few weeks ago with how to call Magic from a web page.  It also used ExternalEvent.

Todd

On 6/14/2017 12:29 AM, Tim Downie wrote:


Hi Brenda/Todd - Im curious as to what this is actually doing - triggering an event in magic when and SMS hits the device?


From: main@magicu-l.groups.io <main@magicu-l.groups.io> on behalf of Brenda Bullorini <bbullorini@...>
Sent: Tuesday, 13 June 2017 3:28 PM
To: main@magicu-l.groups.io
Subject: Re: [magicu-l] XPA 3.2b Android SMS Listener
 
Great news, Todd!

Really glad it worked :)

Brenda


Todd Baremore
 

No. The Magic app must be running to handle the event.  Brenda may know if this can be accomplished.


On 6/14/2017 8:41 AM, Tim Downie wrote:

Ive used the external events a long time ago with html.

Does this still invoke magic if the app isnt open on the phone?
From: main@magicu-l.groups.io <main@magicu-l.groups.io> on behalf of Todd Baremore <tbaremor@...>
Sent: Wednesday, 14 June 2017 12:15:10 PM
To: main@magicu-l.groups.io
Subject: Re: [magicu-l] XPA 3.2b Android SMS Listener
 

Tim,


Exactly.   This is the line in Brenda's java code:

CoreApplication.getInstance().invokeExternalEvent("SMSRECEIVED:" + message);

 
In the Main Program add a handler for Event Type: Internal  -  Event: ExternalEvent
The ExternalEvent parameter is a single BLOB. 

You may need to have your mobile app respond to multiple ExternalEvents, each with a different purpose.  This is why Brenda prefaced the parameter with "SMSRECEIVED:" .  In the event handler, this allows me to determine what I need to.  Brenda also raised a separate External Event that started with "SMSERROR:" so I can handle any SMS errors.  If you look at her screen shot, you'll see that she parses the first n characters of the BLOB to determine the purpose of the External Event.

Brenda's code works exactly as needed.  Both your mobile app and regular SMS application receive the messages.  I am only interested in messages from two sources, so I need to add the required logic.  All other messages will be ignored by my app.

Craig posted something similar a few weeks ago with how to call Magic from a web page.  It also used ExternalEvent.

Todd

On 6/14/2017 12:29 AM, Tim Downie wrote:


Hi Brenda/Todd - Im curious as to what this is actually doing - triggering an event in magic when and SMS hits the device?


From: main@magicu-l.groups.io <main@magicu-l.groups.io> on behalf of Brenda Bullorini <bbullorini@...>
Sent: Tuesday, 13 June 2017 3:28 PM
To: main@magicu-l.groups.io
Subject: Re: [magicu-l] XPA 3.2b Android SMS Listener
 
Great news, Todd!

Really glad it worked :)

Brenda



Brenda Bullorini
 

Hi Todd and Tim,

I've been trying all to day to make the listener works when the app is closed, but hadn't succed.
I mean, the java class is invoked (if you add some logic there it's going to work, since the activity is declared as BroadcastReceiver which is always listening), but then it doesn't get to Magic's Main program.

I've found some solutions but they are not very performant. 
:(

I'll let you know if I manage to make it work in a simple way.

Brenda


Todd Baremore
 

Brenda,

Considering what we're paying you, there's no rush (:-)

Todd


On 6/14/2017 6:11 PM, Brenda Bullorini wrote:

Hi Todd and Tim,

I've been trying all to day to make the listener works when the app is closed, but hadn't succed.
I mean, the java class is invoked (if you add some logic there it's going to work, since the activity is declared as BroadcastReceiver which is always listening), but then it doesn't get to Magic's Main program.

I've found some solutions but they are not very performant. 
:(

I'll let you know if I manage to make it work in a simple way.

Brenda



Joseph Knickerbocker
 

The only way I have found to communicate with the server while the app is closed is to have the java communicate with a web service or something like a PHP script creating an xml file (with the data I need to send to Magic) and have the server looking the xml. It's a bit of a roundabout way, but it works.


Brenda Bullorini
 

That would be the right way to communicate a mobile app with the server! That's what I do with my non-magic mobile apps.
But will not work if you need to do things on the magic client (although I can't think of something you would like to do on the client when app is closed)


Todd Baremore
 

Brenda

Emergency services are dispatched over radio and SMS.   It would very convenient to have my app launch when an SMS is received from one or more specified senders (either phone numbers or email addresses) and have the message passed to the appropriate event handler or program.

Using your SMS Listener solution, when an Emergency Services SMS is received I will be able to parse the message for the address, locate the address in mobile device local database and display construction, hazardous materials, disabled person and other information for the address.   The user will also be able to open a map of the location that contains incident pre-plan information.   I need to add an annoying audio alert.  When a first responder hears the annoying alert, by the time he/she picks up the phone, all the data needed to respond to the call will already be displayed.

The American Red Cross has an app called Tornado (free in the google app store) that will warn you of severe weather in one or more areas.  It does not have to be running for me to receive alerts. I'm guessing it uses the equivalent of a TSR program to listen for alerts.

Everything above is a "nice to have", but not a "must have" for me. Users are told to leave the app running and it works just fine.   If you can figure out the stuff above it would be great  for me and the Magic mobile community, but please don't spend time on this if you have better things to do.  I'm very happy with the solution you have already provided.

Now if Tim is willing to up the ante to a dinner cruise, I'll leave the negotiating to the two of you (:-)

Todd

On 6/15/2017 8:40 AM, Brenda Bullorini wrote:

That would be the right way to communicate a mobile app with the server! That's what I do with my non-magic mobile apps.
But will not work if you need to do things on the magic client (although I can't think of something you would like to do on the client when app is closed)


Brenda Bullorini
 

Todd,

If you need to launch your app (I mean, the visual part and everything) when a sms is received, I can help you!
I managed to do that, it's just some lines of code to check if the app is running and then call the app.
I didn't tell you because I didn't think you wanted to open the app. I thought you jsut needed to run a batch in background or something (which works also, but the splash screen is launched)
Give me some time and I'll send you how to!