I'd like to intercept a Rich Communication message (know as Chat on some networks like Vodafone). I've successfully implemented an SMS receiver using an intent filter and broadcast receiver which works great. However if the SMS is a Rich Communication message the receiver never gets called.
In my manifest:
<receiver
android:name=".IncomingSMS"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="999">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
and my broadcast receiver looks like this:
public class IncomingSMS extends WakefulBroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
// Retrieves a map of extended data from the intent.
final Bundle bundle = intent.getExtras();
if (bundle != null)
{
final Object[] pdusObj = (Object[]) bundle.get("pdus");
SmsMessage currentMessage;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
String format = bundle.getString("format");
currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[0], format);
}
else
{
//noinspection deprecation
currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[0]);
}
String number = currentMessage.getDisplayOriginatingAddress();
Intent serviceintent = new Intent(context, ChargingMonitorService.class);
serviceintent.putExtra(NUMBER, number);
startWakefulService(context, serviceintent);
} // bundle is null
}
}
This all works perfectly except if the text message is a Rich Communication (or chat) message the onReceive() is never called.
There is nothing in the Android docs so I'm assuming its going to be a vendor specific intent but what is it?
After a bit of reverse engineering I've figured out and answer for Samsung devices. I looked at the manifest of the Messages app on a rooted Samsung device to find the intents. I then setup my own receiver and inspected the Bundle extras for any useful data.
In the manifest:
<receiver
android:name=".RCSReceiver"
android:permission="com.samsung.rcs.permission.RCS_APP_PERMISSION"
android:enabled="true"
android:exported="true">
<intent-filter>
<category android:name="com.samsung.rcs.framework.instantmessaging.category.ACTION"/>
<category android:name="com.samsung.rcs.framework.instantmessaging"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_CHAT_INVITATION"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_PARTICIPANT_INSERTED"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_PARTICIPANT_UPDATED"/>
</intent-filter>
</receiver>
with the additional permission:
<uses-permission android:name="com.samsung.rcs.im.READ_PERMISSION"/>
And the receiver code looks like this:
public class RCSReceiver extends BroadcastReceiver
{
private static final String RECEIVE_CHAT_INVITATION = "com.samsung.rcs.framework.instantmessaging.action.RECEIVE_CHAT_INVITATION";
private static final String RECEIVE_PARTICIPANT_UPDATED = "com.samsung.rcs.framework.instantmessaging.action.RECEIVE_PARTICIPANT_UPDATED";
private static final String RECEIVE_PARTICIPANT_INSERTED = "com.samsung.rcs.framework.instantmessaging.action.RECEIVE_PARTICIPANT_INSERTED";
private Logger log = LoggerFactory.getLogger(MainActivity.class);
#Override
public void onReceive(Context context, Intent intent)
{
log.debug("RCS Receiver");
String action = intent.getAction();
Bundle bundle = intent.getExtras();
if(bundle != null)
{
if (RECEIVE_PARTICIPANT_UPDATED.equals(action) || RECEIVE_PARTICIPANT_INSERTED.equals(action))
{
String participant = bundle.getString("participant");
if (participant != null)
{
String number = participant.substring(4); // get the string after "tel:"
log.debug("Chat number is: " + number);
}
}
else if (RECEIVE_CHAT_INVITATION.equals(action))
{
String subject = bundle.getString("subject");
if(subject != null)
{
log.debug("Chat subject: " + subject);
}
}
}
}
}
In the "participant" extra was the telephone number prefixed with "tel:" and the message text was in the subject bundle extra.
This, of course, will only work on Samsung devices and since its not a published API is obviously subject to change without notice so its unknown how long it will work for or if it works on all versions of Android on Samsung. However, it served my purpose of intercepting the number of an incoming chat.
The full list of actions is below however only the two shown above had anything useful in the bundle extras. The extra data for the other intents were in Parcels and would require quite a bit more effort in reverse engineering.
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_TYPING_NOTIFICATION"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_CHAT_CLOSED"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_NEW_MESSAGE"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.DELETE_MESSAGES_RESPONSE"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.DELETE_CHATS_RESPONSE"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_CHAT_INVITATION"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.SEND_MESSAGE_RESPONSE"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_MESSAGE_NOTIFICATION_STATUS"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_SEND_MESSAGE_RESPONSE"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.ADD_PARTICIPANTS_RESPONSE"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_MESSAGE_INSERTED"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_PARTICIPANT_INSERTED"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.RECEIVE_PARTICIPANT_UPDATED"/>
<action android:name="com.samsung.rcs.framework.instantmessaging.action.GET_IS_COMPOSING_ACTIVE_URIS_RESPONSE"/>
Related
I want open App when receive SMS.
I try to handle this problem using Manifest-declared receivers.
Here is my code
<AndroidManifest.xml>
<receiver
android:name=".service.SMSReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
#Override
public void onReceive(Context context, Intent intent) {
packageManager = context.getPackageManager();
if("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction())) {
Bundle bundle = intent.getExtras();
Object[] messages = (Object[]) bundle.get("pdus");
for (Object pdu : messages)
{
SmsMessage message = SmsMessage.createFromPdu((byte[]) pdu);
if(message == null)
{
Log.e(TAG,"message is null");
break;
}
smsSender = message.getDisplayOriginatingAddress();
if(smsSender.compareTo(number)==0)
{
receivedData = new Date(message.getTimestampMillis());
smsBody = message.getDisplayMessageBody();
Log.i(TAG, "onReceive: "+smsBody);
SendToActivity(context,smsSender,smsBody,receivedData);
}
}
}
}
private void SendToActivity(Context context, String sender, String contents, Date receivedDate) {
Log.i(TAG, "SendToActivity: TEST ");
Intent intent = new Intent(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|
Intent.FLAG_ACTIVITY_SINGLE_TOP|
Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("contents",contents);
context.startActivity(intent);
Log.i(TAG, "SendToActivity: RUN >> ");
}
this code works only when app is onPause().
I want to work even app is terminated.
Is possible that terminated app open automatically when SMS received at Android 9?
No, you can't do this. There are certain limitations that Android had put on the Broadcast Receivers.
There are certain broadcasts that Apps can't listen to, and it includes the SMS broadcast too.
You can find more about here
There are some broadcasts which your app can listen to when terminated, you can find the list here
My app needs to be able to receive SMS messages. It all works, but I get this lint warning:
BroadcastReceivers that declare an intent-filter for SMS_DELIVER or
SMS_RECEIVED must ensure that the caller has the BROADCAST_SMS
permission, otherwise it is possible for malicious actors to spoof
intents.
How do I "ensure that the caller has the BROADCAST_SMS permission"?
In my manifest I have:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<application ...>
<receiver
android:name=".SmsReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
My code:
public class SmsReceiver extends BroadcastReceiver {
public SmsReceiver() {}
#Override
public void onReceive(final Context context, final Intent intent) {
final Bundle bundle = intent.getExtras();
if (bundle != null) {
final Object[] pdusObj = (Object[]) bundle.get("pdus");
for (int i = 0; i < pdusObj.length; i++) {
final SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
// use currentMessage
}
}
}
}
Add android:permission="android.permission.BROADCAST_SMS" to the opening <receiver> tag. For example:
<receiver
android:name=".SmsReceiver"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
This android:permission attribute on a <receiver> specifies which permission the sender of the broadcast must hold in order for it to be able to broadcast to your <receiver>. It's a security measure; in this case, so you can be relatively certain that it is the system sending the SMS_RECEIVED broadcast. It's not strictly required, but lint will complain if it's not there, obviously.
I am trying to get phone number and phonebook name from a text message. When I run it from application, and close application, it works, but, when I restart my mobile, it doesn't work. Anybody?
public class IncomingSMSReceiver extends BroadcastReceiver {
private static final String queryString = "#zovi";
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
public void onReceive(Context _context, Intent _intent) {
if (_intent.getAction().equals(SMS_RECEIVED)) {
Intent intent = new Intent(_context, IncomingSMSService.class);
_context.startService(intent);
Bundle bundle = _intent.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++)
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
for (SmsMessage message : messages) {
String msg = message.getMessageBody();
Log.i("Poruka", msg);
String to = message.getOriginatingAddress();
String contactName = TelefonUtils.getContact(_context, to);
Log.i("Od", contactName + "\n" + to);
}
}
}
}
}
My XML:
<receiver android:name=".telefon.receivers.IncomingSMSReceiver"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter android:priority="500">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
In your AndroidManifest.xml try to add <action android:name="android.intent.action.BOOT_COMPLETED" /> action under IncomingSMSReceiver receiver tag.
To start Services or BroadcastReceiver automatically after the Android system restarts or starts you can register a BroadcastReceiver to the Android android.intent.action.BOOT_COMPLETED system event.
Try this code.
<receiver android:name=".telefon.receivers.IncomingSMSReceiver"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter android:priority="500">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
If you have tried android.intent.action.BOOT_COMPLETED then it will not work in your case because you forgot to add BOOT_COMPLETED intent in your
IncomingSMSReceiver and it will work only in case of android.provider.Telephony.SMS_RECEIVED because of if condition you have used in IncomingSMSReceiver. so change if condition from
if (_intent.getAction().equals(SMS_RECEIVED)) {
to
if (_intent.getAction().equals(SMS_RECEIVED) || _intent.getAction().equals(BOOT_COMPLETED)) {
and also define private static final String BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; in IncomingSMSReceiver. Below is full code of IncomingSMSReceiver.
Change your IncomingSMSReceiver code to this:
public class IncomingSMSReceiver extends BroadcastReceiver {
private static final String queryString = "#zovi";
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private static final String BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
public void onReceive(Context _context, Intent _intent) {
if (_intent.getAction().equals(SMS_RECEIVED) || _intent.getAction().equals(BOOT_COMPLETED)) {
Intent intent = new Intent(_context, IncomingSMSService.class);
_context.startService(intent);
Bundle bundle = _intent.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++)
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
for (SmsMessage message : messages) {
String msg = message.getMessageBody();
Log.i("Poruka", msg);
String to = message.getOriginatingAddress();
String contactName = TelefonUtils.getContact(_context, to);
Log.i("Od", contactName + "\n" + to);
}
}
}
}
}
So when your phone restarts it will receive android.intent.action.BOOT_COMPLETED and call your IncomingSMSReceiver receiver then it will start your IncomingSMSService.
I hope it will help you.
Make sure that the receiver starts after phone reboots.
Add <action android:name="android.intent.action.BOOT_COMPLETED" /> in intent-filter
I used this in my project, find this from Android SMS Receive Listener
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import java.util.ArrayList;
/**
* ##author Chathura Wijesinghe <cdanasiri#gmail.com>
*
* <receiver android:name=".SMSReceiver" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
*/
public class SMSReceiver extends BroadcastReceiver {
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private static ArrayList<SMSReceivedListner> smsListner = new ArrayList<SMSReceivedListner>();
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final Bundle extras = intent.getExtras();
if (action.equals(SMSReceiver.SMS_RECEIVED)) {
final boolean smsValid = extras != null;
if (smsValid) {
//Create SMSMessages from PDUs in the Bundle
final Object[] pdus = (Object[])extras.get("pdus");
final SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++)
messages[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
//Assemble
final ArrayList<Long> vibrations = new ArrayList<Long>();
for (SmsMessage message : messages) {
for (SMSReceivedListner smsReceivedListner : smsListner )
smsReceivedListner.message(message);
}
}
}
}
public static void addSMSListner(SMSReceivedListner listner){
smsListner.add(listner);
}
public static void removeSMSListner(SMSReceivedListner listner){
smsListner.remove(listner);
}
public interface SMSReceivedListner{
public void message(SmsMessage message);
}
}
You have to remove the android:permission="android.permission.BROADCAST_SMS" from the receiver declaration. No BOOT_COMPLETED or other permission are required.
explicitly set exported to true in your manifest as an element for the Receiver
android:exported="true"
and make sure both of your application element and receiver element are enabled
android:enabled="true"
Broadcast code seems to be okay and Make sure that you are using any other SMS apps in your device(May this SMS Broadcast might interrupting your apps Broadcast) . If you are not using no other SMS apps then it should work otherwise un-install that SMS app and try once.
and also check you have added the following permissions in your AndroidManifest.xml
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
Hope this will work.
Ideally it should have worked.Is weird that its not working.
Remove android:permission="android.permission.BROADCAST_SMS" from the broadcast receiver.It is not required.
Try increasing the priority android:priority="2147483647" to maximum.It might be some other app is consuming the event or try the below solution.
Add <action android:name="android.intent.action.BOOT_COMPLETED" /> in your intent filter and see if it works.
Something like this:
<receiver android:name=".telefon.receivers.IncomingSMSReceiver"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter android:priority="500">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
and add permission:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
Hi everyone .
i send message to one device and receive this sms in another device's application.I used Broascast receiver to listen sms body or number .I have taken all permission in manifest but my reciver not call.I have used many thing in 2 days related to manifest like android:priority,android:enabled="true", android:exporte but stiil receiver not working.
/* final SmsManager sms = SmsManager.getDefault();*/
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "in receiver", Toast.LENGTH_SHORT).show();
// TODO Auto-generated method stub
Log.e("out", "out");
if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
Bundle bundle = intent.getExtras(); //---get the SMS message passed in---
SmsMessage[] msgs = null;
String msg_from;
Toast.makeText(context, "broad cast reciver", Toast.LENGTH_SHORT).show();
if (bundle != null){
//---retrieve the SMS message received---
try{
Log.e("in", "in");
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for(int i=0; i<msgs.length; i++){
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
msg_from = msgs[i].getOriginatingAddress();
String msgBody = msgs[i].getMessageBody();
}
}catch(Exception e){
// Log.d("Exception caught",e.getMessage());
}
}
}
}
manifest....
<
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_SMS" />
<application android:icon="#drawable/ic_launcher">
<activity android:name=".MainActivity" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".SmsListener" android:enabled="true" android:exported="true" android:permission="android.permission.BROADCAST_SMS">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
Have your SmsListener extend BroadcastReceiver:
public class SmsListener extends BroadcastReceiver {
public SmsListener() {
}
#Override
public void onReceive(Context context, Intent intent) {
//you code here
}
}
And now you can register your receiver in your main activity:
String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
SmsListener smsListener = new SmsListener();
registerReceiver(smsListener, new IntentFilter(SMS_RECEIVED));
Remember to unregister it at the end.
When i uninstalled other application in my device it have also same functionality like my application for example hello application (check out at play store).Then i installed my application it work great.I think another application set priority or other thing in manifest for new incoming sms.So due to this reason our application broadcast receiver not called
Changing the Priority to 1 made it work for me. It defaulted to 1000.
I also had to change the name from .SmsListener to .MainActivity$SmsListener but that would probably depend on where you defined the class (in my case it was within the MainActivity).
<receiver android:name=".MainActivity$SmsListener"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter android:priority="1">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
I have written a SMS receiver for catching income SMS , everything looks fine but it doesn't
works and no SMS income received by the receiver . this is the codes and manifest content.
As I remember I had same app has written in android 2.3 working fine but this code is running in android 4.x which is not functioning properly. what is the problem ? Is it depends on security issues of android 4.x ?
Manifest:
<receiver android:name="SmsReceiver">
<intent-filter android:priority="100">
<action android:name="android.provider.telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
Java Code:
public class SmsReceiver extends BroadcastReceiver {
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Logger.i("INCOMMING SMS...");
if (action == SMS_RECEIVED) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
final SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
if (messages.length > -1) {
String sendr = messages[0].getOriginatingAddress();
Logger.i(sendr);
}
}
}
}
}
I had the same problem and I've fixed it by adding two more actions to the manifest registered receiver so it will look like this:
<receiver android:name=".SmsReceiver">
<intent-filter android:priority="100">
<action android:name="android.intent.action.PHONE_STATE"/>
<action android:name="android.provider.telephony.SMS_RECEIVED"/>
<action android:name="com.your.package.android.action.broadcast"/>
</intent-filter>
</receiver>
also add permission :
<uses-permission android:name="android.permission.RECEIVE_SMS" />
And for comparsion of Strings do not use equals operator, but equals method instead.(Note. equalsIgnoreCase() should be better for you.)
so it will be like:
if(SMS_RECEIVED.equalsIgnoreCase(action))
{
//continue
}
Hope it helps.
I had the same problem as you and after much research on the net, I found the problem. Your application is not started and the Emulator Control doesn't send the option --include-stopped-packages as the adb command can do it. It is a feature introduced with Android 3.x.
So, your receiver never receives the broadcast because your application is not started.
To start it first, open a console from your system and type the following command:
*adb -e shell am broadcast -a android.provider.Telephony.SMS_RECEIVED --include-stopped-packages*
Your BroadcastReceveiver receive an empty SMS.
After this command, your process is displayed in the Devices view, and you can send SMS from your emulator control.