I'm building an application that should trigger a function when an SMS is received. I've used Broadcast Receivers and NotificationListeners before, but for this specific purpose, I need to register this Broadcast receiver. At this time, I'm unable to register it, and I can't quite tell why.
I've tried multiple answers to similar issues on stack overflow but for some reason, the Log.d that I'm using to troubleshoot right now will not print when I receive an SMS. I think I'm fundamentally misunderstanding the problem, although I'm not sure how.
Here is my SmsListener.java class:
public class SmsListener extends BroadcastReceiver {
private SharedPreferences preferences;
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
Log.d("Test","test");
}
}
}
Here is my Manifest:
<receiver android:name=".SmsListener">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Here is the onCreate() function of my activity that should be calling it:
BroadcastReceiver br = new SmsListener();
IntentFilter filter = new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
registerReceiver(br,filter);
Thank you any help. I'm at a total loss.
This is Your Receiver Class-
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private static final String TAG = "SMSBroadcastReceiver";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null) {
if (intent.getAction().equals(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]);
Log.e("Message Content : ", " == " + messages[i].getMessageBody());
Log.e("Message Content Body : ", " == " + messages[i].getDisplayMessageBody());
Log.e("Message recieved From", " == " + messages[0].getOriginatingAddress());
}
/*if (messages.length > -1) {
Log.e("Message recieved: "," == "+ messages[0].getMessageBody());
Log.e("Message recieved From"," == "+ messages[0].getOriginatingAddress());
}*/
}
}
}
}
In your fragment
val smsReciever = SmsReciever()
val smsIntentFilter = IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)
context?.registerReceiver(smsReciever, smsIntentFilter)
In your manifest
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
In your receiver
class SmsReciever : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val message = Telephony.Sms.Intents.getMessagesFromIntent(intent)
val content = message[0].displayMessageBody
Toast.makeText(context, content,
Toast.LENGTH_SHORT).show()
}
}
Related
My actual code blocks calls perfectly but now I want to identify an incoming SMS number ID and do stuff, like mark as read or whatever ( like Medium and this one ).
I've read a couple articles and threads but it's not even getting the intent, note again that this code works perfectly blocking calls so I'll paste the SMS related information
Manifest.xml
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<service android:name=".CallReceiverService" />
Service with Broadcast receiver
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new Notification.Builder(this, SERVICE_CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText(this.getResources().getString(R.string.stg_ServiceRunning))
.setContentIntent(pendingIntent)
.setCategory(Notification.CATEGORY_CALL)
.build();
startForeground(44332255, notification);
}
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.PHONE_STATE"); // related to call feature, ignore
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
intentFilter.addAction("Telephony.Sms.Intents.SMS_RECEIVED_ACTION");
intentFilter.setPriority(1000);
registerReceiver(callCheckReceiver, intentFilter);
}
private BroadcastReceiver callCheckReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
try {
if (intent.getAction().equals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)) {
Log.d("Call", "SMS received");
String smsSender = "";
if (intent.getAction().equals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)) {
Log.d("Call", "SMS received");
String smsSender = "";
for (SmsMessage smsMessage : Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
smsSender = smsMessage.getDisplayOriginatingAddress();
}
if (!isValidPhoneNumber(smsSender)) {
Log.d("Call", "Invalid SMS detected: From " + smsSender);
}
}
if (!isValidPhoneNumber(smsSender)) {
Log.d("Call", "Invalid SMS detected: From " + smsSender);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
public static boolean isValidPhoneNumber(String phoneNumber) {
return android.util.Patterns.PHONE.matcher(phoneNumber).matches();
}
Basically I'm asking the permission in MainActivity, setting them in Manifest and passing the FilterIntent in the Service that IS properly called in Oreo or lower versions of Android. Target API >=19
I don't want to build an app to manage SMS, I just want to intercept the number ID and do things. Can someone advise?
What you need is SMS Retriever API
If you want to detect the SMS, you can simply use
SmsRetrieverClient client = SmsRetriever.getClient(this /* context */);
Task<Void> task = client.startSmsRetriever();
task.addOnSuccessListener(new OnSuccessListener<Void>()
{
#Override
public void onSuccess(Void aVoid)
{
// Successfully started retriever, expect broadcast intent
// ...
}
});
task.addOnFailureListener(new OnFailureListener()
{
#Override
public void onFailure(#NonNull Exception e)
{
// Failed to start retriever, inspect Exception for more details
// ...
}
});
In AndroidManifest.xml simply add receiver
<receiver
android:name=".custom.SMSBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED" />
</intent-filter>
</receiver>
Within receiver you can do whatever you want with detected message
public class SMSBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction()))
{
Bundle extras = intent.getExtras();
Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
switch (status.getStatusCode())
{
case CommonStatusCodes.SUCCESS:
// Get SMS message contents
String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
// Extract one-time code from the message and complete verification
// by sending the code back to your server for SMS authenticity.
break;
case CommonStatusCodes.TIMEOUT:
// Waiting for SMS timed out (5 minutes)
// Handle the error ...
break;
}
}
}
}
It should be noted that SMSRetrieverClient default timeout is 5 minutes.
For creating detectable SMS please follow SMS Creator for Google
Hi I wonder if anyone could advise. I have an arduino which is sending GPS coordinates via SMS to my phone. I then need to extract the coordinates and display them as a marker on a map. The map is being implemented as a fragment. Here is my code for the broadcastreceiver class:
public class SmsBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent){} }
And within the fragment:
public BroadcastReceiver receiver = new SmsBroadcastReceiver(){
public static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
#Override
public void onReceive(Context context, Intent intent) {
//---get the SMS message passed in---
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
if (bundle != null)
{
String number = "";
String message = "";
//---retrieve the SMS message received---
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]);
number = msgs[i].getOriginatingAddress();
message = msgs[i].getMessageBody();
}
//---display the new SMS message---
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}
};
I have also registered the receiver:
public void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter();
receiver = new SmsBroadcastReceiver();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, filter);
}
#Override
public void onResume() {
super.onResume();
setUpMapIfNeeded();
IntentFilter filter = new IntentFilter();
receiver = new SmsBroadcastReceiver();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, filter);
}
I am not getting the toast message displayed onscreen to indicate that the function has run, what have I not understood? I am very new to java and android programming so my understanding is not complete. Thanks in advance.
You are missing action in IntentFilter which should be android.provider.Telephony.SMS_RECEIVED.
IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
receiver = new SmsBroadcastReceiver();
getActivity().registerReceiver(receiver, filter);
Also watch out for Runtime Permission above api 23.
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
I'm creating a simple Android application where I'm trying to intercept incoming SMS messages. The problem I am having is that the toast messages from the onReceive isn't showing up. Please help!
Thanks,
Isaiah Thompson
public class SMSR extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
//Print Message
Toast.makeText(context,"Received Message Start",Toast.LENGTH_SHORT).show();
// Get the data (SMS data) bound to intent
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str = "";
if (bundle != null) {
// Retrieve the SMS Messages received
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
// For every SMS message received
for (int i = 0; i < msgs.length; i++) {
// Convert Object array
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
// Sender's phone number
str += "SMS from " + msgs[i].getOriginatingAddress() + " : ";
// Fetch the text message
str += msgs[i].getMessageBody().toString();
// Newline <img draggable="false" class="emoji" alt="🙂" src="https://s.w.org/images/core/emoji/72x72/1f642.png">
str += "\n";
}
}
//Print Message
Toast.makeText(context,"Received Message End",Toast.LENGTH_SHORT).show();
Toast.makeText(context,str,Toast.LENGTH_SHORT).show();
}
}
Try this
new Handler(Looper.getMainLooper()).post(new Runnable()
{
#Override
public void run()
{
Toast.makeText(context, R.string.sent, Toast.LENGTH_SHORT).show();
}
});
Check out this answer
https://stackoverflow.com/a/11436473/6051131
also, make sure your priority (in the manifest file) is less than or equal 2147483647
I'm trying to get notification when Android receives a text message, so I wrote a new class for that like this:
public class MyBroadcastReceiver extends BroadcastReceiver {
public MyBroadcastCallback callback;
public MyBroadcastReceiver() {}
public MyBroadcastReceiver(MyBroadcastCallback callback) {
this.callback=callback;
Log.d("myTag", "MyBroadcastReceiver CONSTRUCTOR.... "+this.callback);
this.callback.OnReceiveSMS("phone TEST","message TEST");
}
#Override
public void onReceive(Context context, Intent intent) {
Bundle intentExtras = intent.getExtras();
if (intentExtras != null) {
Object[] sms = (Object[]) intentExtras.get("pdus");
for (int i = 0; i < sms.length; ++i) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) sms[i]);
String phone = smsMessage.getOriginatingAddress();
String message = smsMessage.getMessageBody().toString();
this.callback.OnReceiveSMS(phone,message);
}
}
}
public interface MyBroadcastCallback {
void OnReceiveSMS(String phone,String message);
}
}
Then in my main activity I instantiate the class like this:
public class MainActivity extends AppCompatActivity implements MyBroadcastReceiver.MyBroadcastCallback {
MyBroadcastReceiver broadcastReceiver=null;
#Override
protected void onCreate(Bundle savedInstanceState) {
....
super.onCreate(savedInstanceState);
broadcastReceiver=new MyBroadcastReceiver(this);
....
}
#Override
public void OnReceiveSMS(String phone, String message) {
Log.d("myTag", "NEW SMS MESSAGE PHONE="+phone + " message="+message);
}
}
The Android manifest looks like this:
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
When a text is received, OnReceive is called in the MyBroadCastReceiver class, that works great.
But when I try to call my own callback function inside OnReceive() to notify the main activity of the text message like this:
this.callback.OnReceiveSMS(phone, message);
It crashes with exception that this.callback is null.
I know it's not null in the beginning because in the constructor I pass in the main activity which implements that interface.
To debug I also printed out this.callback in the constructor and even called that function in there to make sure its not null, and all that works, but somehow it BECOMES null when a text comes in and Android OS calls OnReceive.
Does anybody knows why it's null? How to fix?
The onReceive() in my class listens for SMSs and sends an SMS in reply, everything is working fine but once. After sending SMS the app shuts down with the message "Unfortunately, yourApp has stopped". I want it to remain active. I wonder where I'm missing out. Thanks for help!
public class SMSReceiver extends BroadcastReceiver {
private static final String SMS_RECEIVED="android.provider.Telephony.SMS_RECEIVED";
private static final String TAG="SMSReceiver";
#Override
public void onReceive(Context context,Intent intent){
SmsManager smsManager=SmsManager.getDefault();
int i;
Toast.makeText(context,"Intent recieved",Toast.LENGTH_LONG).show();
Log.i(TAG,"Intent recieved: "+intent.getAction());
String messageContent="";
if (intent.getAction() == SMS_RECEIVED) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] pdus = (Object[])bundle.get("pdus");
final SmsMessage[] messages = new SmsMessage[pdus.length];
for (i = 0; i < pdus.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
messageContent=messages[i].getMessageBody().toString();
}
if (messages.length > -1 && messageContent.charAt(8)=='#') {
Log.i(TAG, "Message recieved: " + messages[0].getMessageBody());
Toast.makeText(context, "Message received from victim: "+messageContent, Toast.LENGTH_LONG).show();
smsManager.sendTextMessage("+919032687185",null,"Request#",null,null);
//Toast.makeText(context, "SMS sent.",Toast.LENGTH_LONG).show();
/*for(i=0;i<7;i++){
MediaPlayer mediaPlayer=MediaPlayer.create(context, R.raw.fire_engine_siren_could_be_police_ambulance_etc);
mediaPlayer.start();
}*/
}
/*else if(messages.length > -1 && messageContent.charAt(6) == '#'){
Log.i(TAG, "Location from patrol" + messages[0].getMessageBody());
Toast.makeText(context, "Message received from ambulance: "+messageContent, Toast.LENGTH_LONG).show();
}*/
}
}
}
}
It seems like you're getting a java.lang.StringIndexOutOfBoundsException and my guess is the culprit is messageContent.charAt(8) because the logcat indicates length=8; index=8
Try using indexOf instead if finding this #'s location is necessary. Its a bit more flexible and won't throw exceptions at you.