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" />
Related
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()
}
}
I have a Broadcast that sends user's LatLng information. In another activity, I have a Broadcast receiver that is supposed to receive this LatLng information and display it on map as heatmap. Heatmaps are working fine but I think the Broadcast is either not being sent or not being received, can't figure out exactly what's the problem. Maybe I am setting these up incorrectly? What I am trying to achieve is to display all users of my app on the map as a heatmap point. Maybe this is an entirely wrong approach for that matter?
Sender:
private void broadcastUserData(String userId, Double longitude, Double latitude) {
Intent intent = new Intent();
intent.putExtra("VRUId", userId);
intent.putExtra("longitude", longitude);
intent.putExtra("latitude", latitude);
intent.setAction("VRUData");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
Receiver:
final Map<String, LatLng> map = new HashMap<>();
private void createBroadcastReceiverVRUData() {
// just for testing
map.put("!2321", new LatLng(7.447893883296565, 9.48882099800934));
map.put("!2321", new LatLng(7.44789382565, 9.4888204));
map.put("!2231", new LatLng(7.447780625, 9.489011));
initializeHeatMap(map);
broadcastReceiverVRUData = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String userId = intent.getStringExtra("VRUId");
LatLng gps = new LatLng(
intent.getDoubleExtra("latitude", 0),
intent.getDoubleExtra("longitude", 0));
if (map.containsKey(userId)) {
map.remove(userId);
map.put(userId, gps);
} else {
map.put(userId, gps);
}
initializeHeatMap(map);
Log.d("THIS IS GPS", gps.toString());
}
};
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("VRUData");
LocalBroadcastManager.getInstance(this).registerReceiver(
broadcastReceiverVRUData, intentFilter);
}
Heatmap:
List<LatLng> list;
private void initializeHeatMap(Map<String, LatLng> map) {
list = new ArrayList<LatLng>(map.values());
Log.d("GPS coordinates", map.values().toString());
HeatmapTileProvider mProvider = new HeatmapTileProvider.Builder().data(list).build();
mMap.addTileOverlay((new TileOverlayOptions()).tileProvider(mProvider));
}
intent.setAction("VRUData") is not the same intentFilter.addAction("VRUDATA") - one is in all caps.
Try First Thing: you can try gmap.clear(); before adding marker on map, might be the issue with old marker can not replace with new marker.
Try Second Thing :
Your receiver look like this in your activity or whatever where you are using.
private BroadcastReceiver receiver;
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// put your stuuf here
Bundle extras = intent.getExtras();
HashMap<String, String> mData;
}
}:
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
I am trying to laod some tasks from DB on BOOT_COMPLETED and set alarm for each of them.
Alarm Manager is configured to receive BOOT_COMPLETED in AndroidMAnifest File.
Sometime I get these task via SMS, so i have a brodcastreceiver for sms receiving and processing, which builds task list and calls AlarmManager.setAlarms().
I am wondering that setAlarams works fine when called from OnReceive() method og SMSReceiver, but does not work properly when called from OnReceive() method of AlarmManager on Boot_Completed. it just sets one Alarm and ignores the rest of the list!
any help on this?
thanks in advance
public class AlarmManager extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
List <Task> taskList= db.loadFromDB();
setAlarms(context, taskList);
}
public static void setAlarms(Context context, List<Task> taskList) {
for each task in taskList{
int pendingIntentRequestCode = task.getid();;
Intent myIntent = new Intent(context, AlarmReceiver.class);
myIntent.putExtra("taskName", task.getName());
myIntent.putExtra("taskHour", task.getHour));
myIntent.putExtra("taskMinute", task.getMinute());
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
pendingIntentRequestCode,
myIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP,alarmTime, pendingIntent );
}
}
}
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String taskName = intent.getStringExtra("taskName");
int taskHour = intent.getIntExtra("taskHour", -1);
int taskMinute = intent.getIntExtra("taskMinute", -1);
Intent alarmIntent = new Intent(AlarmClock.ACTION_SET_ALARM);
alarmIntent.putExtra(AlarmClock.EXTRA_MESSAGE, taskName);
alarmIntent.putExtra(AlarmClock.EXTRA_HOUR, ataskHour);
alarmIntent.putExtra(AlarmClock.EXTRA_MINUTES, taskMinute);
alarmIntent.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(alarmIntent);
}
}
public class SMSReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String messageReceived = "";
if (bundle != null) {
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]);
messageReceived += msgs[i].getMessageBody().toString();
sender = msgs[i].getOriginatingAddress();
messageReceived += "\n";
}
List <Task> taskList = MakeTaskListFromReceivedSMS(messageReceived);
AlarmManager.setAlarms(context, taskList);
}
}
}
According to the documentation:
If there is already an alarm scheduled for the same IntentSender, it
will first be cancelled.
I have an app that listens to incoming messages, and if the originating sender is the one specified by the user, it then reacts accordingly, showing a special alert and aborting the broadcast, preventing it from reaching the inbox. On Verizon, it works perfectly. I've sent over 300 without any issue, as have a few other testers.
On any other carrier though, it's a mess.
On AT&T, the broadcast is never aborted and it shows up in the sms inbox.
On Sprint, the broadcast is aborted, but it never gets beyond that. The AlertActivity intent is never called, nor either of the toast messages I put to check.
On T-Mobile, the broadcast is never aborted and it shows up in the sms inbox.
I have the receiver done in java rather than registered in the Manifest because I register it in a service which is started on app launch and on BOOT_COMPLETED.
Service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public void startService() {
IntentFilter SMSfilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
this.registerReceiver(Receiver.br, SMSfilter);
}
Receiver
static public BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
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[i].getOriginatingAddress().equals(Test.SENDER)) {
abortBroadcast();
String[] body = messages[i].getDisplayMessageBody().split(" ", 7);
if (body[0].equals("test")) {
test = true;
}
cat = body[1];
level = body[2];
urgency = body[3];
certainty = body[4];
carrier = body[5];
message = body[6];
intent = new Intent(context, AlertActivity.class);
Bundle b = new Bundle();
b.putString("title", cat);
b.putString("certainty", certainty);
b.putString("urgency", urgency);
b.putString("level", level);
b.putString("message", message);
b.putBoolean("test", test);
intent.putExtras(b);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
carrierName = manager.getNetworkOperatorName();
if (carrierName.replaceAll(" ", "").equals(carrier)) {
context.startActivity(intent);
} else {
//testing
toast(carrierName.replaceAll(" ", ""), context);
}
}
}
}
}
};
I use these imports in the app,
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
I know that there is a gsm version of these as well, which I don't use. Could this be why the app isn't detecting the incoming messages on the gsm carriers?
UPDATE 1
According to http://developer.android.com/reference/android/telephony/gsm/package-summary.html its not due to not using the gsm specific imports.
ANSWER
Got it.
It has to do with how the incoming message senders number is read.
On the verizon device it would register as xxxxxxx on others, +1xxxxxxx. Added an option to acces Test.SENDER or Test.SENDER_LAME which is +1xxxxxxx
Got it. It has to do with how the incoming message senders number is read. On the verizon device it would register as xxxxxxx on others, +1xxxxxxx. Added an option to acces Test.SENDER or Test.SENDER_LAME which is +1xxxxxxx