this is my first time posting here. I'm new to Java & using the Android SDK, and thought I'd start off by trying to write a simple app to filter text messages for "scammy" keywords, for an Innovation module in school.
The app began off by showing a small toast whenever a keyword ("FREEBIE" etc.) is flagged, but I've been trying to make a more noticeable indicator, such as through alert dialogs.
Not sure what I've been doing wrong, but the alert isn't displaying when a message containing the keyword is sent through, but toasts work fine though. I thought it might be an issue with the context, so I've tried context/this/getActivityContext etc., but I receive a "Builder cannot be applied to com.example.myapp.ReceiveSms" error.
package com.example.myapp;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
public class ReceiveSms extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
Bundle bundle = intent.getExtras();
SmsMessage[] msgs;
if (bundle != null) {
try {
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]);
String msgFrom = msgs[i].getOriginatingAddress();
String msgBody = msgs[i].getMessageBody();
if (msgBody.matches(".*\\bFREEBIE\\b.*")) {
AlertDialog.Builder builder = new AlertDialog.Builder(context.getApplicationContext());
builder.setTitle("Scam Message");
builder.setMessage("Scam Message");
builder.setCancelable(true);
builder.setNeutralButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
Basicly you can not show dialog in broadcast receiver . See this link for more details , https://stackoverflow.com/a/8766864/1079842
The problem is with the context passed to the dialog as they can only be displayed within an activity.
new AlertDialog.Builder(context.getApplicationContext());
You need to specify the activity that the AlertDialog will appear over not the application context. It would look something like this:
new AlertDialog.Builder(YourActivityClass.this);
Since the dialog is being created from a receiver (not it's designated use case), one solution, but not recommended is to create an activity for this specific dialog.
show an alert dialog in broadcast receiver after a system reboot
Showing AlertDialog in a BroadcastReceiver is not allowed, this should only happen in a context of an Activity.
Instead of showing an AlertDialog, I'd recommend using showing notifications instead.
public class ReceiveSms extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent arg1) {
// Add your desired logic here whether to show or not the notification
showNotification(context);
}
private void showNotification(Context context) {
PendingIntent pIntent = PendingIntent.getActivity(
context, 0,
new Intent(context, MyActivity.class), 0);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.some.icon_here)
.setContentTitle("Your Notification Title")
.setContentText("Your Message");
builder.setContentIntent(pIntent);
builder.setAutoCancel(true);
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, builder.build()); // 1 denotes your notification id
}
}
This should help you further understand the alternatives on what you are trying to do.
Further reading
https://developer.android.com/training/notify-user/build-notification
ReceiveSms extends BroadcastReceiver
This is your BroadcastReceiver. BroadcastReceiver are defined for the purpose of getting system broadcasts on the different resources.
Example :
Internet is started by user
Sms is received
Call is coming
Sms has arrived
What is the BroadcastReceivers work
Just to let developers get the access to the triggers.
Why your Dialog alert not working, even if coded correctly ?
I will not correct the mistake in your dialog alert, As your programming approach is wrong. It is not working because, when the sms receives your app might be in foreground or background or nowhere.. And Even if present in background you needs to draw over other apps, permission.
When Dialog alert are used ?
Used in only when user is actively in the app and app is open in front of him. and not in Broadcastreceivers nor in the background. Broadcastreceivers works in background and you need to show System alert or a notification or simply a toast.
Remove your alertdialog and use below :
Toast.makeText(this, " SMS ARRIVED ", Toast.LENGTH_LONG).show();
Or
A System Alet
or
A Notification
Another problem in your approach :
You are not allowed to use READ_SMS or SEND_SMS or any SMS related operations as your app will be rejected if you tried to upload it on play store.
You need to use https://developers.google.com/identity/sms-retriever/user-consent/request
SMS-RETRIEVAR api for that purpose
Related
I'm trying to open the MainActivity when the user clicks a button in my notification, while the app is only running in the background with a service. When the button is clicked, these lines are triggered in the Service class:
Intent openApp = new Intent(this, MainActivity.class);
openApp.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openApp);
I've checked it, and the lines are triggered, so there's no problem in reacting to the button's click, the Activity won't open though.
Any suggestions? Why isn't this working for me and how can I make it work?
Edit
I was asked for some more code, so in my onStartCommand() inside my Service, if it starts with a stop-action within its intent, I call the killService() method, which kills the Service, starts the MainActivity and do some other stuff:
if (action != null && action.equals(ACTION_STOP_SERVICE)) {
killService();
}
To set the Notifications button, I use this code:
Intent stopActionIntent = new Intent(this, TimerService.class);
stopActionIntent.setAction(ACTION_STOP_SERVICE);
PendingIntent stopActionPendingIntent = PendingIntent.getService(this, 1, stopActionIntent, PendingIntent.FLAG_IMMUTABLE);
timerNotificationBuilder.addAction(R.drawable.stop, "Stop", stopActionPendingIntent);
And as I said, the button already reacts to the user clicking on it, so that's not the problem.
You can try to receive the click in a BroadcastReceiver and then open activity from there.
Try this to add a action button o your notification:
timerNotificationBuilder.addAction(createNotificationActionButton("STOP");
Where the createNotificationActionButton method is this:
public NotificationCompat.Action createNotificationActionButton(String text){
Intent intent = new Intent(this, StopwatchNotificationActionReceiver.class);
#SuppressLint("InlinedApi") PendingIntent pendingIntent = PendingIntent.getBroadcast(this, new Random().nextInt(100), intent, PendingIntent.FLAG_IMMUTABLE);
return new NotificationCompat.Action(0, text, pendingIntent);
}
Create a class named StopwatchNotificationActionReceiver and make it extent a BroadcastReceiver`. This is the code for that class:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class StopwatchNotificationActionReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
PrefUtil.setIsRunningInBackground(context, false);
PrefUtil.setTimerSecondsPassed(context, 0);
PrefUtil.setWasTimerRunning(context, false);
context.stopService(MainActivity.serviceIntent);
Intent activityIntent = new Intent(context, MainActivity.class);
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActvity(activityIntent);
}
}
Also you need to register that receiver in your manifest like this:
<receiver android:name="StopwatchNotificationActionReceiver"/>
Where the MainActivity.serviceIntent is a public static variable which looks like this:
public static Intent serviceIntent;
And this intent is only used to start the service like this:
//In onCreate
serviceIntent = new Intent(this, TimerService.class);
//In onPause
PrefUtil.setTimerSecondsPassed(this,seconds);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent);
}
Or you can try the simple method:
if (action != null && action.equals(ACTION_STOP_SERVICE)) {
Context context = this;
Intent activityIntent = new Intent(context, MainActivity.class);
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActvity(activityIntent);
killService();
}
Edit
Another solution is here. Again. You need to refer to my repo as I have made changes to the files in order to complete your task. In the service class, refer to this method. There, I start the activity if the action is reset(r). Or else, it opens the broadcast receiver. Then, in the activity, I receive that extra in the onResume() method. If the reset button is not clicked, it opens the Receiver class.
And as always, you can view the result of the app from here.
I hope that code will do your work.
I found it! See this answer.
This answer suggests enabling ScreeanOverlay settings because as of Android 10 and later you can no longer open an activity from the background just by calling the lines I've used.
To make it work, you'd have to add this permission through your Manifest.xml:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
And then the user would have to enable the Display over other apps setting.
I searched for an option to get the user to this setting more easily and found this answer.
This answer gives a code that redirects the user to the Display over other apps setting
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 0);
}
and then I guide the user with the notification's content (text) on how to enable the setting.
Once the setting is enabled, The lines I've used before work.\
So, problem solved?
Not Completely Solved
this whole configuration described above works, but only if the app is not killed.
If the app was killed and I try the method listed above, the app joins the recent apps list, but won't open and show up.
A solution that solves this issue as well will be accepted as an answer instead of this one.
I am newbie in android programming; sorry if my question is easy :)
I'm trying to write code that monitors the battery level on the phone and if it is, lower some level for example (%15), create a message that asks user to plug the charger. I know that I need to use BroadcastReceiverclass and I want to use it in my MainActivity class. Here is the code I have:
public class MainActivity extends Activity{
BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, Intent intent) {
String intentAction = intent.getAction();
Log.d("receiver", intentAction);
int level = intent.getIntExtra("level", 0);
if (level < 15){
Log.d("receiver", "battery level low");
}
if (Intent.ACTION_BATTERY_OKAY.equalsIgnoreCase(intentAction)) {
Log.d("receiver", "battery level okay");
}
}
};
......
but it seems that the onReceivemethod is never called since I never see the Log.d("receiver", intentAction) message on Android Studio debug window.
I also have registered br in onResume and unregistered it in onPause:
public void onResume() {
super.onResume();
filter.addAction("receiver");
registerReceiver(br, filter);
}
public void onPause() {
super.onPause();
unregisterReceiver(br);
}
But still I am not getting any message.
Can anybody please help me? Should I also add something to AndroidManifest.xml?
If you dont want to use BroadcastReceiver simply dont use it. Battery intent is sticky intent so you can check it without need of BroadcastReceiver and i also dont think its good idea to put receiver in activity. You can check battery stuff in your activity like this and you dont need to edit your manifest
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, filter);
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float batteryPct = level / (float)scale;
if(batteryPct < 15){
//do your stuff
}
Your code in onResume() is wrong. You will have to update it as follows.
filter.addAction(Intent.ACTION_BATTERY_LOW);
filter.addAction(Intent.ACTION_BATTERY_OKAY);
registerReceiver(br, filter);
to include the ACTION_BATTERY_LOW and ACTION_BATTERY_OKAY filters as mentioned in the docs.
I am going to implement a feature , where my application has to receive events of a camera from ( Event push server).
This server will push the events and my application has to receive and show in the notification bar.
e.g like the Facebook app or WhatsApp app, where in we receive the new message on the notification bar, even though the app is not in active state.
So to implement it:
What all pre requisetes i need. e.g information about the Event server?
Information on what protocol used in the server?
what is required on the Android side to implement this feature.
Please tell me how to proceed to implement on Android application side.
The programs like facebook using service to take events in background. Use JSON files for data interchange. Im using BroadcastReceiver to keep in touch with my activity. BroadcastReceiver its a very nice tool to communicate your service with activity.
Intent in = new Intent("SOMEACTION");
sendBroadcast(in);
Sending intent to you activity after handling response.
#Override
public void onResume() {
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));
}
// handler for received Intents for the "my-event" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
#Override
protected void onPause() {
// Unregister since the activity is not visible
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
I am using DownloadManager to download multiple files (12 to be exact). I have setup a BroadcastReciever and when ACTION_DOWNLOAD_COMPLETE display an AlertDialog like this:
manager.enqueue(f1);
manager.enqueue(f2);
manager.enqueue(f3);
......
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
//Display an alertdialog
}
}
};
registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
However once the downloads complete, the dialog goes into a loop and keeps reappearing until a forcefully exit the app. Does anyone know why this is happening?
I have found that this is happening because it displays the alertdialog for each completed download. How can I make it show just once when all of the downloads are done?
My app is running a service that collects feeds. When it find these feeds it create notations (unsuccessfully). I use a method call like this:
doNotification(date,"New Article",title,link,content,description,false);
for articles and this:
doNotification(date,"New Video",title,link,"","",true);
for videos. The method is this:
public void doNotification(Date date,String title,String subtext,String url,String body,String dateString,boolean video){
long time = date.getTime();
if(time > feedGetter.lastFeed){
//New feed, do notification
NotificationManager mNotificationManager = (NotificationManager) feedGetter.service.getSystemService(Context.NOTIFICATION_SERVICE);
int icon = R.drawable.notification_icon;
Notification notification = new Notification(icon, title + ": " + subtext, time);
Intent notificationIntent = new Intent(feedGetter.service, NotificationActivity.class);
notificationIntent.putExtra("url",url);
notificationIntent.putExtra("video",video);
if(!video){
notificationIntent.putExtra("body",body);
notificationIntent.putExtra("date",dateString);
notificationIntent.putExtra("title",subtext);
}
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(feedGetter.service, 0, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
notification.setLatestEventInfo(feedGetter.service.getApplicationContext(), title, subtext, contentIntent);
mNotificationManager.cancel(video? 1 : 0);
mNotificationManager.notify(video? 1 : 0, notification);
//Update new time if necessary.
if(time > feedGetter.newTime){
feedGetter.newTime = time; //New time will be the time for this feed as it is the latest so far
}
}
}
As you see I add some data to the intent so I can handle the notifications correctly. The notifications are assigned to an ID for videos or an ID for articles and should replace the previous notifications. Here is the NotificationActivity that handles the notifications:
public class NotificationActivity extends Activity{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Debug.out("Notification Activity");
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if(getIntent().getBooleanExtra("video", true)){
//Handle video notification
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getIntent().getStringExtra("url")));
startActivity(browserIntent);
mNotificationManager.cancel(1);
}else{
//Start application UI and move to article
Intent intent = new Intent(this,TheLibertyPortalActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("url", getIntent().getStringExtra("url"));
intent.putExtra("body", getIntent().getStringExtra("body"));
intent.putExtra("date", getIntent().getStringExtra("date"));
intent.putExtra("title", getIntent().getStringExtra("title"));
startActivity(intent);
mNotificationManager.cancel(0);
}
finish();
}
}
So it's supposed to activate a URL for the videos and restart the application for articles with some data for handling the articles so the article is displayed to the user.
Seems simple enough but it doesn't work. The notifications display and they replace each other on the notification menu, showing the latest notifications for videos and articles but when I click on them they go wrong. I try to click on the article notification and it thinks it is a video and loads one of the videos. I go back onto the notification menu and the video notification has disappeared even when I clicked on the article notification. I try clicking on the article notification and nothing happens. It literally closes the menu and doesn't nothing and the notification remains in the menu doing nothing.
Thank you for any help with this. I am targeting the Google APIs level 14 API, with a min SDK version of level 8, trying with a 2.2.1 Android tablet.
The problem is with the Pending intent. Even though the docs say the requestCode is not used, it is. You must pass a unique integer for each PendingIntent. That worked!