Android My BroadcastReceiver Class no receive the action send from Notification - android

In my IntentService class, i create a Notification and assign ID=1213, and the notification will show up once the apps is open.
Intent cancelScan = new Intent();
cancelScan.setAction(CANCEL);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1213, cancelScan, PendingIntent.FLAG_UPDATE_CURRENT);
mNbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel,"Cancel Scanning",pendingIntent);
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(NOTIFICATION_ID, mNbuilder.build());
in my BroadcastReceiver class
if(CANCEL.equals(intent.getAction())){
Log.i(TAG,"Received Broadcasr Receiver");
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
//context.stopService(new Intent(context,ScanService.class));
nm.cancel(NOTIFICATION_ID);
}
}
and, my Manifest.XML
<receiver android:name=".WifiScanReceiver" android:enabled="true">
<intent-filter>
<action android:name="CANCEL"/>
</intent-filter>
</receiver>
I had tried couple times when i click the action button beneath the notification, but the Logcat did not print anything. Which parts i had done wrong? Thank in Advance.

The values of CANCEL and the value declared as action ("CANCEL") in your manifest must be equal, or it won't work. Your's don't, that's why you don't reach your if statement. Your receiver is triggered though, because you send a broadcast with the correct action.
To make sure you use the correct values in your code, you can declare a static final in your WifiScanReceiver:
public class WifiScanReceiver {
public static final String CANCEL = "CANCEL";
...
}
So you can also use it in you code when you send the broadcast:
Intent cancelScan = new Intent();
cancelScan.setAction(WifiScanReceiver.CANCEL);
That way you are always certain that you use the same value. The only one that you have to make sure is also correct, is the one in your manifest.

Related

Android 8.0 Oreo AlarmManager with broadcast receiver and implicit broadcast ban

I have critical reminders that are set via the Alarm Manager (It should function the same way as an alarm clock application).
Previously I had the following in my Android Manifest:
<receiver android:name="com.example.app.AlarmReceiver" >
<intent-filter>
<action android:name="${packageName}.alarm.action.trigger"/>
</intent-filter>
</receiver>
The broadcast receiver:
public class AlarmReceiver extends BroadcastReceiver {
#Override public void onReceive(
final Context context,
final Intent intent) {
// WAKE LOCK
// BUILD NOTIFICATION etc...
}
}
How the alarm is set:
final PendingIntent operation = PendingIntent.getBroadcast(
mContext,
requestCode,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
if (PlatformUtils.hasMarshmallow()) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);
}
}
With Android 8.0 I can no longer use an implicit broadcast as defined in the Manifest. That's fine, the alternative given is to register it manually like so:
final BroadcastReceiver receiver = new AlarmReceiver();
final IntentFilter intentFilter = new IntentFilter(ALARM_RECEIVER_INTENT_TRIGGER);
context.registerReceiver(receiver, intentFilter);
This does not seem logical to me.
The alarm receiver will be tied to the lifetime of the context. This causes an issue when say the application is killed due to memory pressure or when the device is restarted. I need my alarms to fire every time as they are critical for the health of the user.
Even if I listen to "android.intent.action.BOOT_COMPLETED" and register my alarm receiver the app is killed shortly after and no alarm is fired. I also don't see my alarm via
adb shell dumpsys alarm
How do I create a custom broadcast receiver that receives an implicit broadcast to fire an alarm while targeting Android O (8.0)? Can someone enlighten me with a code example or link to documentation. How does Timely or any other alarm clock app function while targeting O?
Revise your code slightly to make the broadcast explicit rather than implicit and you'll be fine (assuming this is an Activity reference or some other Context):
Intent intent = new Intent(ALARM_RECEIVER_INTENT_TRIGGER);
intent.setClass(this, AlarmReceiver.class);
The restriction in Oreo is on implicit broadcast Intent registration, which is to say it you are sending it broadcasts will only action, category, or data specified. You make it an explicit broadcast by specifying the class which is to receive the broadcast.
If you guys are used to check if the alarm has already been registered don't forget to do the same on this verification:
public boolean isAlarmBroadcastRegistered(Context context, String action, Class clazz) {
Intent intent = new Intent(action);
intent.setClass(context, clazz);
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE) != null;
}

stack notification received from parse

I want to stack multiple received notification from parse,when received notification is more than 1 notify and display to user in one notification. I searched so much but i can not find the right solution. is that possible anyway?
What you need is a custome PushReceiver, so according to Parse docs you declare receiver in the manifest
<receiver
<!-- Put here path to a class that will handle pushes -->
android:name="com.domain.ReceiverClass"
android:exported="false">
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE"/>
<action android:name="com.parse.push.intent.DELETE"/>
<action android:name="com.parse.push.intent.OPEN"/>
</intent-filter>
</receiver>
And in this PushReceiver class you implement all needed logic concerning displaying of pushes
public class PushReceiver extends ParsePushBroadcastReceiver {
#Override
protected void onPushReceive(Context context, Intent intent) {
//Don't call super.onPushReceive!
JSONObject pushData = new JSONObject(intent.getStringExtra(KEY_PUSH_DATA));
//Here is how you obtain data
String alert = pushData.optString("alert", "Notification received.");
//Any manipulations with stacking go here
}
}
EDIT. So everything depends on your requirements. You can for example just accumulate notifications in the receiver and schedule AlarmManager to wake up after 5 mins. Pass current number of notificaitons as an extra and then check if new pushes arrived. If so - wait for the next alarm, if not - show everything.
SharedPreferences prefs = context.getSharedPreferences(KEY_NOTIFICATIONS,
Context.MODE_PRIVATE
);
JSONArray stacked = new JSONArray(prefs.getString(KEY_STACKED, ""));
stacked.put(alert);
prefs.edit().putString(KEY_STACKED, stacked.toString()).apply();
Intent i = new Intent(context, ActualProcessor.class);
i.putExtra(EXTRA_COUNT, stacked.length());
PendingIntent receiver = PendingIntent.getBroadcast(context, CODE, i, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5),
receiver
);

AlarmManager Stops after removing app from recents apps

I am new to this part of android, and here I aim to use alarm manager to run a code snippet every 2 minute which will poll a server (using the website's api) and based on the returned JSON generate notification.
After a looking up the web I thought one of the best option in my case will be using intent service and android.
Manifest of Services and Recievers
<service
android:name=".NotifyService"
android:enabled="true"
android:exported="false" >
</service>
<receiver
android:name=".TheReceiver"
android:enabled="true"
android:exported="true" >
</receiver>
<receiver
android:name=".OnOffReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
Part in the flash screen activity where I call the intent service which is responsible for polling for notification:
Intent msgIntent = new Intent(this, NotifyService.class);
startService(msgIntent);
The receiver to start the alarm on device start:
public class OnOffReceiver extends BroadcastReceiver
{
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
public OnOffReceiver(){}
#Override
public void onReceive(Context context, Intent intent)
{
Intent service = new Intent(context, NotifyService.class);
service.setAction(NotifyService.CREATE);
context.startService(service);
}
}
The IntentService Class
public class NotifyService extends IntentService
{
public NotifyService()
{
super("NotifyService");
}
public static final int STATUS_RUNNING = 0;
public static final int STATUS_FINISHED = 1;
public static final int STATUS_ERROR = 2;
#Override
protected void onHandleIntent(Intent intent)
{
if (intent != null)
{
final String action = intent.getAction();
}
StartStuff();
}
public void StartStuff()
{
Intent intent = new Intent(this, TheReceiver.class);
PendingIntent pend_intent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,1200,1200, pend_intent);
//1200ms to make it easier to test
}
}
The receiver class which sets notification, for testing pupose I am not doing any network related work here just making a simple notification to check if the app is running in all situations
public class TheReceiver extends BroadcastReceiver
{
public TheReceiver(){}
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, " Success ", Toast.LENGTH_SHORT).show();
Log.d("Notification", "The Receiver Successful");
showNotification(context);
}
private void showNotification(Context context)
{
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context).setContentTitle("My notification").setContentText("Hello World!");
mBuilder.setDefaults(Notification.DEFAULT_SOUND);
mBuilder.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
}
}
However the notification come only when the app is running or in the recent apps tray.
It does not start notifying when the phone reboots, nor does it notify after the app is removes from the recent apps tray.
The app needs Notify users like other apps (like gmail, whatsapp) do, even if they are swiped out of the recent apps tray.
Timeliness and punctuality are not very big issue as delay up to 5 to 10 minutes are tolerable. (I intend to poll ever 2 minutes though.)
Where am I going wrong? Also, is there a better way to go about the problem?
To keep a receiver active after closing the app is to use
android:process=":remote"
in the manifest file for the receiver that needs to be kept alive.
<receiver
android:name=".TheAlarmReceiver"
android:process=":remote">
</receiver>
in the manifest for the receiver (TheReceiver in this case) that we need to keep active after the app closes.
P.S. : I also changed the way I use IntentsService and AlarmManager for the application, as my previous(above) implementation is not a very good way to go around it.
If an App is killed from recent apps or from "force stop" it won't restart by itself. The user has to start the app again in order to make it run again. There is no way to prevent this. It's just the way android works.
However there is a way to make your app run oon boot. Check out this link.

how to use delete intent to perform some action on clear notification?

I want to reset a variable of my service when user clears my notification: that's all!
Looking around I see that everyone suggest to add a delete intent on my notification, but intent is used to start an activity, a service o whatever while I just need a thing like this:
void onClearPressed(){
aVariable = 0;
}
how to obtain this result?
Notifications are not managed by your app and all things like showing notifications and clearing them are actually happening in another process. You can't make another app directly execute a piece of code just because of security reasons.
The only possibility in your case is to provide a PendingIntent which just wraps around a regular Intent and will be started on behalf of your app when notification is cleared.
You need to use PendingIntent for sending broadcast or starting a service and then doing what you want in the broadcast receiver or in the service. What exactly to use depends on from which application component you are showing notifications.
In case of broadcast receiver you can just create an anonymous inner class for broadcast receiver and register it dynamically before showing notification. It will look something like that:
public class NotificationHelper {
private static final String NOTIFICATION_DELETED_ACTION = "NOTIFICATION_DELETED";
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
aVariable = 0; // Do what you want here
unregisterReceiver(this);
}
};
public void showNotification(Context ctx, String text) {
Intent intent = new Intent(NOTIFICATION_DELETED_ACTION);
PendingIntent pendintIntent = PendingIntent.getBroadcast(ctx, 0, intent, 0);
registerReceiver(receiver, new IntentFilter(NOTIFICATION_DELETED_ACTION));
Notification n = new Notification.Builder(mContext).
setContentText(text).
setDeleteIntent(pendintIntent).
build();
NotificationManager.notify(0, n);
}
}
Andrei is correct.
If you want multiple messages back such as:
you want to know if the message was clicked
you attached an action with an icon that you want to catch
AND you want to know if the message was canceled
you must register each of those response filters:
public void showNotification(Context ctx, String text) ()
{
/… create intents and pending intents same format as Andrie did../
/… you could also set up the style of your message box etc. …/
//need to register each response filter
registerReceiver(receiver, new IntentFilter(CLICK_ACTION));
registerReceiver(receiver, new IntentFilter(USER_RESPONSE_ACTION));
registerReceiver(receiver, new IntentFilter(NOTIFICATION_DELETED_ACTION));
Notification n = new Notification.Builder(mContext)
.setContentText(text)
.setContentIntent(pendingIntent) //Click action
.setDeleteIntent(pendingCancelIntent) //Cancel/Deleted action
.addAction(R.drawable.icon, "Title", pendingActionIntent) //Response action
.build();
NotificationManager.notify(0, n);
}
Then you can catch the different responses with if, else statements (as Andrei did), or with a switch statement.
Note: I make this response primarily because I could not find this anywhere, and I had to figure it out on my own. (perhaps I will remember it better for that :-) Have Fun!

How to execute a method by clicking a notification

I have an application with two buttons. One button that "closes" the application and one that begins the algorithm. When I click "begin" it "hides" the application and displays a notification in the notification bar. I need to be able to execute/call a method when the notification is clicked/pressed. There are a few answers for this sort of question, but they are incredibly vague and one only points to a link to the doc on BroadcastReceiver.
If you are going to leave a url to the BroadcastReceiver doc and say "read this page," please don't reply to this question. If you are going to explain how I could use BroadcastReceiver to execute a method (from within the same class that displayed the notification), please show me some code for how this could be done.
My algorithm: press a button, display notification, click notification, call a method (don't display activity). That's it.
If it's not possible, just let me know. If it is, please show me what you would do to make it possible. Something this simple shouldn't have been overlooked by the developers of the android sdk.
After several iterations of trial and error, I finally found a fairly straightforward and clean way to run an arbitrary method when a notification's action is clicked. In my solution, there is one class (I'll call it NotificationUtils) that creates the notification and also contains an IntentService static inner class that will run when actions on the notification are clicked. Here is my NotificationUtils class, followed by the necessary changes to AndroidManifest.xml:
public class NotificationUtils {
public static final int NOTIFICATION_ID = 1;
public static final String ACTION_1 = "action_1";
public static void displayNotification(Context context) {
Intent action1Intent = new Intent(context, NotificationActionService.class)
.setAction(ACTION_1);
PendingIntent action1PendingIntent = PendingIntent.getService(context, 0,
action1Intent, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Sample Notification")
.setContentText("Notification text goes here")
.addAction(new NotificationCompat.Action(R.drawable.ic_launcher,
"Action 1", action1PendingIntent));
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
public static class NotificationActionService extends IntentService {
public NotificationActionService() {
super(NotificationActionService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
DebugUtils.log("Received notification action: " + action);
if (ACTION_1.equals(action)) {
// TODO: handle action 1.
// If you want to cancel the notification: NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID);
}
}
}
Now just implement your actions in onHandleIntent and add the NotificationActionService to your manifest within the <application> tags:
<service android:name=".NotificationUtils$NotificationActionService" />
Summary:
Create a class that will create the notification.
Inside that class, add a IntentService inner classes (make sure it is static or you will get a cryptic error!) that can run any method based on the action that was clicked.
Declare the IntentService class in your manifest.
On Notification click we can't get any fire event or any click listener. When we add notification in notification bar, we can set a pending intent, which fires an intent (activity/service/broadcast) upon notification click.
I have a workound solution for you, if you really don't want to display your activity then the activity which is going to start with pending intent send a broad cast from there to your parent activity and just finish the pending activity and then once broadcast receiver receives in parent activity call whatever method you want inside the receiver. For your reference..
// This is what you are going to set a pending intent which will start once
// notification is clicked. Hopes you know how to add notification bar.
Intent notificationIntent = new Intent(this, dummy_activity.class);
notificationIntent.setAction("android.intent.action.MAIN");
notificationIntent.addCategory("android.intent.category.LAUNCHER");
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT |
Notification.FLAG_AUTO_CANCEL);
// Now, once this dummy activity starts send a broad cast to your parent activity and finish the pending activity
//(remember you need to register your broadcast action here to receive).
BroadcastReceiver call_method = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action_name = intent.getAction();
if (action_name.equals("call_method")) {
// call your method here and do what ever you want.
}
};
};
registerReceiver(call_method, new IntentFilter("call_method"));
}
}

Categories

Resources