35

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.

Chris
  • 1,416
  • 18
  • 29
AnDev
  • 351
  • 1
  • 3
  • 4
  • I only got the notification manager to notify and display the notification in the notification bar. When I click the notification, it opens the activity. I wanted to modify this behavior by calling/executing a method instead of opening the activity. I'm trying to work with Arfin's solution. I just don't see how I'm supposed to make this happen. I created a "DummyActivity" and I'm not sure if the second part of his solution is supposed to be in the "DummyActivity." I'm just confused. I like when things fit together smoothly. – AnDev Jun 30 '12 at 16:01
  • yea AnDev once your dummy activity starts send a broadcast from their and just finish it, so now you will receive the broadcast message in parent class, as i already explained you can call whatever method you want from there. No need to do any thing further inside dummy activity except sending broadcast and finishing it. – Daud Arfin Jul 02 '12 at 04:18
  • 1
    I feel the pain in this question :P The last 2 hours I've searched has turned up dozens and dozens of copy paste karma-mining answers that explain nothing on this topic. Looks like there isn't a clear consensus on this. – sprajagopal Jun 16 '21 at 19:04

2 Answers2

44

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.
Tony Wickham
  • 4,706
  • 3
  • 29
  • 35
  • What if the Action field is already in use? Like "ACTION_VIEW" – X.Y. Oct 28 '16 at 23:53
  • You could add an extra to the Intent, e.g. action1Intent.putExtra("action1extra", 1), and then in onHandleIntent use if (intent.getIntExtra("action1extra", -1) == 1) { ... } – Tony Wickham Oct 29 '16 at 19:04
  • Spent the better part of my day so far looking for a way to do this. Glad I found your answer, works like a charm. – kalenpw Mar 17 '17 at 22:07
13

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"));
    }
}
Daud Arfin
  • 2,499
  • 1
  • 18
  • 37
  • If I want to check either application is in foreground or not on notification click event, and according to your code @Daud Arfin , if we launch an activity, it will always return that app is in foreground. Is there any alternate way to check either application is in foreground or not on notification click event – Kimmi Dhingra Jul 22 '14 at 06:11
  • @Er Kimmi Dhingra - you can depend on android life cycles .. maintain flags inside onPause/onStop and onResume/onStart. – Daud Arfin Jul 22 '14 at 07:17
  • What do the notificationIntent.setAction and .addCategory achieve in this example? – admrply Apr 06 '16 at 17:08