Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stopping a background service from notification

Tags:

android

I have a background service in which I want to show a notification which allows the user to stop it.

In the android SDK docs it says an activity is used to normally launch an Activity. So I am wondering if I need to create an activity to stop the service or can I directly stop the service when user selects the notification,

So how would the intend call back the service to stop it..

Thanks,

like image 528
Ahmed Avatar asked Jun 21 '12 19:06

Ahmed


People also ask

How do I stop foreground services from activity?

To start a foreground service, call startForeground() . To stop it, call stopForeground() .

What is start in background permission?

It's the “let the app run in the background” option. Disabling this feature stops the app from going to sleep, thus not logging out the user. Open the SETTINGS app. You will find the settings app on the home screen or apps tray.

What is foreground service in Android?

Foreground services are an advanced Android concept which allows you to display notifications to your users when running long lived background tasks. The notification acts like any other notification, however it cannot be removed by the user and lives for the duration of the service.


2 Answers

So I am wondering if I need to create an activity to stop the service or can I directly stop the service when user selects the notification,

You cannot directly stop the service from a Notification. You can start the service, using an Intent that has an action string or extra or something that the service sees in onStartCommand() and triggers it to call stopSelf().

like image 50
CommonsWare Avatar answered Sep 22 '22 01:09

CommonsWare


The question is already old, but since there is still no solution with code, I simply share my code as an example for solving the problem:

You cannot directly stop the service from a Notification. You can start the service, using an Intent that has an action string or extra or something that the service sees in onStartCommand() and triggers it to call stopSelf().

That's the right solution so let's jump in code (this code is all in your ExampleService class):

@RequiresApi(Build.VERSION_CODES.O)
private void startForegroundService() {
    // create PendingIntend to open MainActivity (this is when the notification gets clicked) //
    Intent tabIntent = new Intent(this, MainActivity.class);
    tabIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    PendingIntent tabPendingIntent = PendingIntent.getActivity(this, 0, tabIntent, 0);

    // create PendingIntend to open ExampleService (this is when the notification BUTTON gets clicked) //
    Intent closeIntent = new Intent(this, ExampleService.class);
    closeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    closeIntent.putExtra("destroyCode", 666); // this is the important line //
    PendingIntent closePendingIntent = PendingIntent.getService(this, 0, closeIntent, 0);

    createNotificationChannel(); // this is only the default code to create notification channel. I just outsourced? it //

Now the Intent has additional data (the "destroy code" -> 666). Notice that we have created 2 pendingIntents: closePendingIntent (stop Service) and tabPendingIntent (start Activity)

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
    // get extras to know if Intent has destroyCode (666)
    Bundle extras = intent.getExtras();
    if (extras == null) {  
         // extras is null which means there is no destroyCode (666)
         exampleMethod();

    } else {
        // Intent has destroyCode (666) -> Intent comes from notification -> stop the service and close notification

        stopSelf();          
    }
    return START_STICKY;
}

Now we have the code to check if there is a destroyCode or not. The last step is to create a notification with a button:

// set attributes for notification //
            final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "channelID_2");
            Notification notification = builder.setOngoing(true)
                    .setSmallIcon(R.drawable.example)
                    .setContentTitle(getText(R.string.notificationTitle))
                    .setContentText(getText(R.string.notificationText))
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setCategory(NotificationCompat.CATEGORY_MESSAGE)
                    .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                    .setContentIntent(tabPendingIntent) //this is when notification is clicked which only opens ExampleActivity
                    .addAction(R.drawable.example, getString(R.string.notificationButtonText), closePendingIntent) // here is our closePendingIntent with the destroyCode .addAction is "the onClickListener for the notification button"//
                        .build();
                startForeground(2, notification);

In onCreate you start your service

    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
        startForegroundService();
    else
        startForeground(1, new Notification());

    // Toast Message that service has started
    Toast.makeText(this, R.string.serviceStarted, Toast.LENGTH_SHORT).show();

That's it

like image 45
Daniel Avatar answered Sep 22 '22 01:09

Daniel