android how do I receive sms in broadcast receiver [duplicate] - android

I'd like my app to catch incoming SMS messages. There are a few examples of this around. Looks like we just need to do this:
// AndroidManifest.xml
<receiver android:name=".SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
// SMSReceiver.java
public class SMSReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "SMS received.");
....
}
}
is this correct? I'm sending my phone some sms messages, but the log statement never gets printed. I do have some other SMS applications installed on the phone, which display a popup when the sms is received - are they somehow blocking the intent from getting passed down to my app, they are just consuming it completely?
Thanks

You would also need to specify a uses-permission in your manifest file:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
The following tutorials should help:
React on incoming SMS
SMS messaging in Android

There are a few gotchas on the way. You can find all the needed info on stackoverflow. I have gathered all the info in this answer, for convenience.
Things to be noticed
I assume android kitkat and above.
The intent for incomming sms is "android.provider.Telephony.SMS_RECEIVED"
You can change the priority of the intent filter, but it's not necessary.
You need this permission "android.permission.RECEIVE_SMS" in manifest xml, in order to receive sms messages. In android 6 and above, you additionally need to ask for the permission in runtime.
You do not need to set the MIME type of data in the intent filter. Intent filter should pass only on empty data if no MIME type is set, but fortunately it will still work without MIME.
adb shell am broadcast will not work. Use telnet connection to simulator to test sms receiving.
Long sms messages are divided into small sms chunks. We need to concatenate them.
How to send a sms message to the emulator
The most important thing is to have the possibility to send fake sms messages to the device, so we can test the code.
For this we will use a virtual device and a telnet connection to it.
Create a virtual device in android studio and run the simulator
Look at the title bar in the simulator window. There is the device name and a port number. We need to know this port number in the next steps.
Now connect to the port number shown in the simulator title bar with telnet
$ telnet localhost 5554
If you see this: Android Console: Authentication required, then you need to authenticate the connection with this command:
auth xxxxxx
Replace the xxxxxx above with the token read from ~/.emulator_console_auth_token file.
Now you should be able to run all the commands. To send a sms message, type this command:
sms send 555 "This is a message"
Where you can replace 555 with the sender telephone number and a message of your own.
How to listen to SMS_RECEIVED broadcasts
To get the broadcasts, you need to register a BroadcastReceiver object. You can do this in the manifest.xml OR just call registerReceiver function. I will show you the latter, as it is easier to reason about and yet more flexible.
Connecting the broadcast receiver with the main activity
The data flow is one way. From broadcast receiver to the main activity. So the simplest way to get them to talk is to use a function interface. The activity will implement such a function and the broadcast receiver will have the activity instance passed as a parameter in the constructor.
File SmsHandler.java:
package ...
interface SmsHandler {
void handleSms(String sender, String message);
}
Implementing the broadcast receiver
The broadcast receiver will get the intent in a callback. We will use the function Telephony.Sms.Intents.getMessagesFromIntent(intent) to get the sms messages. Notice the SmsHandler parameter in the constructor. It will be the activity to which we will send the received sms.
File SmsInterceptor.java:
package ...
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.Telephony;
import android.telephony.SmsMessage;
public class SmsInterceptor extends BroadcastReceiver {
private SmsHandler handler;
/* Constructor. Handler is the activity *
* which will show the messages to user. */
public SmsInterceptor(SmsHandler handler) {
this.handler = handler;
}
#Override
public void onReceive(Context context, Intent intent) {
/* Retrieve the sms message chunks from the intent */
SmsMessage[] rawSmsChunks;
try {
rawSmsChunks = Telephony.Sms.Intents.getMessagesFromIntent(intent);
} catch (NullPointerException ignored) { return; }
/* Gather all sms chunks for each sender separately */
Map<String, StringBuilder> sendersMap = new HashMap<>();
for (SmsMessage rawSmsChunk : rawSmsChunks) {
if (rawSmsChunk != null) {
String sender = rawSmsChunk.getDisplayOriginatingAddress();
String smsChunk = rawSmsChunk.getDisplayMessageBody();
StringBuilder smsBuilder;
if ( ! sendersMap.containsKey(sender) ) {
/* For each new sender create a separate StringBuilder */
smsBuilder = new StringBuilder();
sendersMap.put(sender, smsBuilder);
} else {
/* Sender already in map. Retrieve the StringBuilder */
smsBuilder = sendersMap.get(sender);
}
/* Add the sms chunk to the string builder */
smsBuilder.append(smsChunk);
}
}
/* Loop over every sms thread and concatenate the sms chunks to one piece */
for ( Map.Entry<String, StringBuilder> smsThread : sendersMap.entrySet() ) {
String sender = smsThread.getKey();
StringBuilder smsBuilder = smsThread.getValue();
String message = smsBuilder.toString();
handler.handleSms(sender, message);
}
}
}
The main activity
Finally we need to implement SmsHandler interface into the main activity and add registering the broadcast receiver and permission check to the onCreate function.
File MainActivity.java:
package ...
import ...
public class MainActivity extends AppCompatActivity implements SmsHandler {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* Register the broadcast receiver */
registerSmsListener();
/* Make sure, we have the permissions */
requestSmsPermission();
}
/* This function will be called by the broadcast receiver */
#Override
public void handleSms(String sender, String message) {
/* Here you can display the message to the user */
}
private void registerSmsListener() {
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
/* filter.setPriority(999); This is optional. */
SmsInterceptor receiver = new SmsInterceptor(this);
registerReceiver(receiver, filter);
}
private void requestSmsPermission() {
String permission = Manifest.permission.RECEIVE_SMS;
int grant = ContextCompat.checkSelfPermission(this, permission);
if ( grant != PackageManager.PERMISSION_GRANTED) {
String[] permission_list = new String[1];
permission_list[0] = permission;
ActivityCompat.requestPermissions(this, permission_list, 1);
}
}
}
Finally remember to add RECEIVE_SMS permission to your manifest xml
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<application>
...
</application>
</manifest>

One more thing that these answers haven't mentioned - you should require the permission android.permission.BROADCAST_SMS. If you don't do this, any application can spoof messages in your app.
<receiver android:name=".SMSReceiver"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>

Also note that the Hangouts application will currently block my BroadcastReceiver from receiving SMS messages. I had to disable SMS functionality in the Hangouts application (Settings->SMS->Turn on SMS), before my SMS BroadcastReceived started getting fired.
Edit: It appears as though some applications will abortBroadcast() on the intent which will prevent other applications from receiving the intent. The solution is to increase the android:priority attribute in the intent-filter tag:
<receiver android:name="com.company.application.SMSBroadcastReceiver" >
<intent-filter android:priority="500">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
See more details here: Enabling SMS support in Hangouts 2.0 breaks the BroadcastReceiver of SMS_RECEIVED in my app

Did you try with the emulator ?
After deploying your application in the emulator, you can send events like SMS via the DDMS or via the command line by connecting with telnet :
telnet localhost <port_emulator>
send sms <incoming_tel_number> <sms_content>
port_emulator is usually 5554

You should read this acticle about send and receive sms programmatically.
http://mobiforge.com/developing/story/sms-messaging-android

Android Messenger (the SMS client) has a "Chat" feature which transmits messages over WiFi instead of SMS.
If the person you are testing with uses Messenger as well, you'll need to disable this feature on one or both of your devices otherwise there is no SMS message actually being received:
To turn chat features off:
Open Messages Messages Logo Round.
Tap More More and then Settings.
Tap Advanced and then Chat features.
Turn Enable chat features on or off.
https://support.google.com/messages/answer/7189714?hl=en

Related

"com.android.vending.INSTALL_REFERRER" fetching referrer parameters on Broadcast has up to 15 seconds delays on some devices

My server creates a link that redirects and passes parameters to google play store;
The sms I receive by my Server;
https://goo.gl/{UNIQUE_ID}
when I click, I actually click on this this url below;
http://www.mycompany.com/env=dev&token=123&id=456
The link above directs me to google play store to my app included parameters;
https://play.google.com/store/apps/details?id=com.mycompany.app&referrer=123,456
Here is the question;(First time installation)
When I install the app opened with the link above, I want to pass those "token", "id" parameters to my app in first time then I will skip login. These parameters creating by server because they are also unique to user.
I have setup the "com.android.vending.INSTALL_REFERRER" and I am able to receive parameters as expected but not consistent on every devices and could face with big delays.
<receiver
android:name=".GooglePlayReceiver"
android:exported="true"
android:permission="android.permission.INSTALL_PACKAGES">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
My GooglePlayReceiver Broadcastreceiver is;
public class GooglePlayReceiver extends BroadcastReceiver {
Context mContext;
String purchaseId = null;
public GooglePlayReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
try {
mContext = context;
Bundle extras = intent.getExtras();
String verificationCode = null;
String phoneNumber = null;
if (extras != null) {
String code = extras.getString("referrer");
String[] strArr = code != null ? code.split(",") : new String[0];
token = strArr[0];
id = strArr[1];
}
} catch (Exception ex) {
}
}}
This flow has big delays on some devices. For ex, Google Pixel 2 fetches the parameters immediately without delay, Samsung Galaxy S7 has 5-10 seconds delay.
How to solve this?
Because the INSTALL_REFERRER is sent as a broadcast (documentation) it uses the publish subscribe model. There is no guarantee about timing.
Because of this you shouldn't design your app startup flow to rely on receiving the broadcast within a certain length of time. Android is open source, and changes made my different phone manufacturers will cause different promptness in the delivery of broadcasts.
I'd have a different design for your app:
take the user always to the normal setup flow
if the broadcast arrives later, allow the user to skip login

How to prevent SMS going to inbox in Android?

I'm developing a business SMS application. In this app, if an incoming message is from a particular number, say 999999999, it should go to the application's inbox and not to the default native inbox. All other messages should go to the phone's native inbox. How do I do this?
When SMS is received by the Android system, it broadcasts an ordered broadcast Intent with action "android.provider.Telephony.SMS_RECEIVED". All registered receivers, including the system default SMS application, receive this Intent in order of priority that was set in their intent-filter. The order for broadcast receirers with the same priority is unspecified. Any BroadcastReceiver could prevent any other registered broadcast receivers from receiving the broadcast using abortBroadcast().
So, everything you need is broadcast receiver like this:
public class SmsFilter extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
Bundle extras = intent.getExtras();
if (extras != null) {
Object[] pdus = (Object[])extras.get("pdus");
if (pdus.length < 1) return; // Invalid SMS. Not sure that it's possible.
StringBuilder sb = new StringBuilder();
String sender = null;
for (int i = 0; i < pdus.length; i++) {
SmsMessage message = SmsMessage.createFromPdu((byte[]) pdus[i]);
if (sender == null) sender = message.getOriginatingAddress();
String text = message.getMessageBody();
if (text != null) sb.append(text);
}
if (sender != null && sender.equals("999999999")) {
// Process our sms...
abortBroadcast();
}
return;
}
}
// ...
}
}
Looks like the system default SMS processing application uses priority of 0, so you could try 1 for your application to be before it. Add these lines to your AndroidManifest.xml:
<receiver android:name=".SmsFilter">
<intent-filter android:priority="1">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Don't forget about necessary permissions:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
By the way, you can find all registered receivers and their priorities using this code:
Intent smsRecvIntent = new Intent("android.provider.Telephony.SMS_RECEIVED");
List<ResolveInfo> infos = context.getPackageManager().queryBroadcastReceivers(smsRecvIntent, 0);
for (ResolveInfo info : infos) {
System.out.println("Receiver: " + info.activityInfo.name + ", priority=" + info.priority);
}
Update: As FantasticJamieBurn said below, starting from Android 4.4 the only app that can intercept SMS (and block if it wish) is the default SMS app (selected by user). All other apps can only listen for incoming SMS if default SMS app not blocked it.
See also SMS Provider in the Android 4.4 APIs.
With the release of Android 4.4 KitKat (API level 19), the option to block an SMS message and prevent it from being delivered to the default SMS app has been removed. Non-default SMS app's may observe SMS messages as they are received, but any attempt to abort the broadcast will be ignored by Android 4.4+.
If you have an existing app which relies on aborting SMS message broadcasts then you may want to consider the impact this change in behaviour will have when your users upgrade to Android 4.4+.
http://android-developers.blogspot.co.uk/2013/10/getting-your-sms-apps-ready-for-kitkat.html
Yes it can be DOne
public void onReceive(Context context, Intent intent)
{
Bundle bundle=intent.getExtras();
Object[] messages=(Object[])bundle.get("pdus");
SmsMessage[] sms=new SmsMessage[messages.length];
Toast.makeText(context, "Hello", 1).show();
for(int n=0;n<messages.length;n++){
sms[n]=SmsMessage.createFromPdu((byte[]) messages[n]);
}
for(SmsMessage msg:sms){
if(msg.getOriginatingAddress().endsWith(number))
{
SMS.updateMessageBox("\nFrom: "+msg.getOriginatingAddress()+"\n"+
"Message: "+msg.getMessageBody()+"\n");
/*((SMS) context).delete();*/
abortBroadcast();
}
}
}
just use abortbroadcast() after receiving in app
Are you the one sending the messages? If so consider using datasms instead as they will not show up in the inbox.
Check this question for more info on how to use it
Check the sender number is equal to the mobile number of your sms sending phone.
replace the following code line of Mr "praetorian droid"
if (sender != null && sender.equals("999999999")) {
to
if (sender != null && sender.equals("YOUR SMS SENDING MOBILE NUMBER HERE")) {
further more you can give a setting to user to manually add sms sending number if he want to change it.

Not receiving broadcast from k9 email

I am listening for the email received broadcast from k9 and I cannot seem to get it to work.
I have registered a receiver for the following:
com.fsck.k9.intent.action.EMAIL_RECEIVED
I'm wondering if I need to add a permission - I can't seem to receive this broadcast.
I know my receiver is working as I can receive broadcasts for SMS and the phone. Has anyone else used this that can maybe shed some light on the subject?
Here's my filter:
IntentFilter fltr = new IntentFilter();
fltr.addAction("android.provider.Telephony.SMS_RECEIVED");
fltr.addAction("com.fsck.k9.intent.action.EMAIL_RECEIVED");
fltr.addAction("android.intent.action.PHONE_STATE");
registerReceiver(mRcv, fltr);
In my BroadcastReceiver:
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private static final String EMAIL_RECEIVED = "com.fsck.k9.intent.action.EMAIL_RECEIVED";
private static final String CALL_RECEIVED = "android.intent.action.PHONE_STATE";
public void onReceive( Context context, Intent intent ) {
Log.d(TAG, "Inside Broadcast Reciever");
Log.d(TAG, "Action: " + intent.getAction());
if(intent.getAction().equals(SMS_RECEIVED)) {
StartAct("SMS Received", context);
}else if(intent.getAction().equals(EMAIL_RECEIVED)){
StartAct("Email received", context);
}else if(intent.getAction().equals(CALL_RECEIVED)){
if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING))
StartAct("Incoming Phone Call", context);
}
}
I have it working - finally....
You have to add a data scheme to the intent filter. This will allow you to receive the broadcast. BUT it will break the other actions that I had in the filter, so I had to break them into separate receivers - one for SMS and phone and another for the k9 email broadcast.
Here's the one for k9 email:
IntentFilter fltr = new IntentFilter();
fltr.addAction("com.fsck.k9.intent.action.EMAIL_RECEIVED");
fltr.addDataScheme("email"); //This is needed to even receive the broadcast
registerReceiver(mRcv, fltr);
Try looking at the actual K9 source code. The AndroidManifest shows several Permissions that they have. Try compiling your program with it hooked up to eclipse and check LogCat, it'll usually show in it's error section if there is a missing permission. I only see 4 declared permissions that they have created, so READ_MESSAGE would be my guess, but check the logcat and see what it says.
Unfortunately it looks like their documentation is lacking quite a bit, which is a damn shame.

Android: Receiving SMS from specific phone number

Is it possible for my application to receive an SMS from a specific phone number, without letting it trig a system notification, but let all other messages pass to the default SMS application to be treated normally?
If so, how can the system know which process is first on queue to pick which messages to receive?
I didn't try this, but in theory it should work:
In Android SMS broadcast is sent as ordered broadcast, which means that receivers are handled in order and can cancel the broadcast. See SMSDispatcher.java, line 420.
In order to be called first, a receiver must have a higher priority then others.
<intent-filter android:priority="1000" >
. . .
</intent-filter>
To cancel a broadcast call broadcastReceiver.setResultCode(RESULT_CANCELED). That way a SMS broadcast will be cancelled and will not be shown by system SMS app (and SMS notifier).
Update:
Also try using broadcastReceiver.setResultCode(Intents.RESULT_SMS_HANDLED).
Update 2:
user672601 noted in another answer that this indeed works, but he used abortBroadcast() inside broadcast receiver.
I second farhan its not possible for number of reason. Anybody can do anything with such allowance. Check this out for details http://groups.google.com/group/android-developers/browse_thread/thread/78fecbc156f4a1ea
Peter Knego's answer is correct. I was trying to do this exact thing, tried his solution, and it indeed works except for I used:
this.abortBroadcast();
inside the broadcastReceiver.
public class NotifyServiceReceiver extends BroadcastReceiver{
static final String ACTION ="android.provider.Telephony.SMS_RECEIVED";
#Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
if(arg1.getAction().equalsIgnoreCase(ACTION))
{
Bundle extras = arg1.getExtras();
String strMessage = "private message";
if ( extras != null )
{
Object[] smsextras = (Object[]) extras.get( "pdus" );
for ( int i = 0; i < smsextras.length; i++ )
{
SmsMessage smsmsg = SmsMessage.createFromPdu((byte[])smsextras[i]);
String strMsgBody = smsmsg.getMessageBody().toString();
String strMsgSrc = smsmsg.getOriginatingAddress();
//Toast.makeText(GasService.this,strMessage, Toast.LENGTH_SHORT).show();
if(strMsgSrc.equals("+919XXXXXXXXX"))
{
strMessage += "SMS from " + strMsgSrc + " : " + strMsgBody;
Toast.makeText(PrivatesmsService.this,strMessage, Toast.LENGTH_SHORT).show();
abortBroadcast();
}
}
}
}
}
}
you can tell to the system by setting the priority of the activity to 100 or greater then that in manifest file so that when ever you receive sms then your application will access it and by calling abortBroadcast() it will prevent sms reaching to inbox or any other application which has set BroadcastReceiver to receive sms
I dont think its possible.... because android gives us broadcast Listener which only listen the event. so you have to read every message and check the number if its yours, do an operation else just ignore it.... the default messaging application will automatically handle it....

BroadcastReceiver + SMS_RECEIVED

I'd like my app to catch incoming SMS messages. There are a few examples of this around. Looks like we just need to do this:
// AndroidManifest.xml
<receiver android:name=".SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
// SMSReceiver.java
public class SMSReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "SMS received.");
....
}
}
is this correct? I'm sending my phone some sms messages, but the log statement never gets printed. I do have some other SMS applications installed on the phone, which display a popup when the sms is received - are they somehow blocking the intent from getting passed down to my app, they are just consuming it completely?
Thanks
You would also need to specify a uses-permission in your manifest file:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
The following tutorials should help:
React on incoming SMS
SMS messaging in Android
There are a few gotchas on the way. You can find all the needed info on stackoverflow. I have gathered all the info in this answer, for convenience.
Things to be noticed
I assume android kitkat and above.
The intent for incomming sms is "android.provider.Telephony.SMS_RECEIVED"
You can change the priority of the intent filter, but it's not necessary.
You need this permission "android.permission.RECEIVE_SMS" in manifest xml, in order to receive sms messages. In android 6 and above, you additionally need to ask for the permission in runtime.
You do not need to set the MIME type of data in the intent filter. Intent filter should pass only on empty data if no MIME type is set, but fortunately it will still work without MIME.
adb shell am broadcast will not work. Use telnet connection to simulator to test sms receiving.
Long sms messages are divided into small sms chunks. We need to concatenate them.
How to send a sms message to the emulator
The most important thing is to have the possibility to send fake sms messages to the device, so we can test the code.
For this we will use a virtual device and a telnet connection to it.
Create a virtual device in android studio and run the simulator
Look at the title bar in the simulator window. There is the device name and a port number. We need to know this port number in the next steps.
Now connect to the port number shown in the simulator title bar with telnet
$ telnet localhost 5554
If you see this: Android Console: Authentication required, then you need to authenticate the connection with this command:
auth xxxxxx
Replace the xxxxxx above with the token read from ~/.emulator_console_auth_token file.
Now you should be able to run all the commands. To send a sms message, type this command:
sms send 555 "This is a message"
Where you can replace 555 with the sender telephone number and a message of your own.
How to listen to SMS_RECEIVED broadcasts
To get the broadcasts, you need to register a BroadcastReceiver object. You can do this in the manifest.xml OR just call registerReceiver function. I will show you the latter, as it is easier to reason about and yet more flexible.
Connecting the broadcast receiver with the main activity
The data flow is one way. From broadcast receiver to the main activity. So the simplest way to get them to talk is to use a function interface. The activity will implement such a function and the broadcast receiver will have the activity instance passed as a parameter in the constructor.
File SmsHandler.java:
package ...
interface SmsHandler {
void handleSms(String sender, String message);
}
Implementing the broadcast receiver
The broadcast receiver will get the intent in a callback. We will use the function Telephony.Sms.Intents.getMessagesFromIntent(intent) to get the sms messages. Notice the SmsHandler parameter in the constructor. It will be the activity to which we will send the received sms.
File SmsInterceptor.java:
package ...
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.Telephony;
import android.telephony.SmsMessage;
public class SmsInterceptor extends BroadcastReceiver {
private SmsHandler handler;
/* Constructor. Handler is the activity *
* which will show the messages to user. */
public SmsInterceptor(SmsHandler handler) {
this.handler = handler;
}
#Override
public void onReceive(Context context, Intent intent) {
/* Retrieve the sms message chunks from the intent */
SmsMessage[] rawSmsChunks;
try {
rawSmsChunks = Telephony.Sms.Intents.getMessagesFromIntent(intent);
} catch (NullPointerException ignored) { return; }
/* Gather all sms chunks for each sender separately */
Map<String, StringBuilder> sendersMap = new HashMap<>();
for (SmsMessage rawSmsChunk : rawSmsChunks) {
if (rawSmsChunk != null) {
String sender = rawSmsChunk.getDisplayOriginatingAddress();
String smsChunk = rawSmsChunk.getDisplayMessageBody();
StringBuilder smsBuilder;
if ( ! sendersMap.containsKey(sender) ) {
/* For each new sender create a separate StringBuilder */
smsBuilder = new StringBuilder();
sendersMap.put(sender, smsBuilder);
} else {
/* Sender already in map. Retrieve the StringBuilder */
smsBuilder = sendersMap.get(sender);
}
/* Add the sms chunk to the string builder */
smsBuilder.append(smsChunk);
}
}
/* Loop over every sms thread and concatenate the sms chunks to one piece */
for ( Map.Entry<String, StringBuilder> smsThread : sendersMap.entrySet() ) {
String sender = smsThread.getKey();
StringBuilder smsBuilder = smsThread.getValue();
String message = smsBuilder.toString();
handler.handleSms(sender, message);
}
}
}
The main activity
Finally we need to implement SmsHandler interface into the main activity and add registering the broadcast receiver and permission check to the onCreate function.
File MainActivity.java:
package ...
import ...
public class MainActivity extends AppCompatActivity implements SmsHandler {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* Register the broadcast receiver */
registerSmsListener();
/* Make sure, we have the permissions */
requestSmsPermission();
}
/* This function will be called by the broadcast receiver */
#Override
public void handleSms(String sender, String message) {
/* Here you can display the message to the user */
}
private void registerSmsListener() {
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
/* filter.setPriority(999); This is optional. */
SmsInterceptor receiver = new SmsInterceptor(this);
registerReceiver(receiver, filter);
}
private void requestSmsPermission() {
String permission = Manifest.permission.RECEIVE_SMS;
int grant = ContextCompat.checkSelfPermission(this, permission);
if ( grant != PackageManager.PERMISSION_GRANTED) {
String[] permission_list = new String[1];
permission_list[0] = permission;
ActivityCompat.requestPermissions(this, permission_list, 1);
}
}
}
Finally remember to add RECEIVE_SMS permission to your manifest xml
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<application>
...
</application>
</manifest>
One more thing that these answers haven't mentioned - you should require the permission android.permission.BROADCAST_SMS. If you don't do this, any application can spoof messages in your app.
<receiver android:name=".SMSReceiver"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
Also note that the Hangouts application will currently block my BroadcastReceiver from receiving SMS messages. I had to disable SMS functionality in the Hangouts application (Settings->SMS->Turn on SMS), before my SMS BroadcastReceived started getting fired.
Edit: It appears as though some applications will abortBroadcast() on the intent which will prevent other applications from receiving the intent. The solution is to increase the android:priority attribute in the intent-filter tag:
<receiver android:name="com.company.application.SMSBroadcastReceiver" >
<intent-filter android:priority="500">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
See more details here: Enabling SMS support in Hangouts 2.0 breaks the BroadcastReceiver of SMS_RECEIVED in my app
Did you try with the emulator ?
After deploying your application in the emulator, you can send events like SMS via the DDMS or via the command line by connecting with telnet :
telnet localhost <port_emulator>
send sms <incoming_tel_number> <sms_content>
port_emulator is usually 5554
You should read this acticle about send and receive sms programmatically.
http://mobiforge.com/developing/story/sms-messaging-android
Android Messenger (the SMS client) has a "Chat" feature which transmits messages over WiFi instead of SMS.
If the person you are testing with uses Messenger as well, you'll need to disable this feature on one or both of your devices otherwise there is no SMS message actually being received:
To turn chat features off:
Open Messages Messages Logo Round.
Tap More More and then Settings.
Tap Advanced and then Chat features.
Turn Enable chat features on or off.
https://support.google.com/messages/answer/7189714?hl=en

Categories

Resources