I've created a service so that I can have a persistent notification. I want this notification to have an option that will send an intent to another of my activities.
The option will inherently be stopped every process that the app has spawned. So the notification also needs to close once the action is pressed.
I'm trying to accomplish this using a pending broadcast intent, but for some reason the broadcast receiver isn't catching the intent. I register the receiver dynamically in the service's onCreate() method and unregister it in the service's onDestroy() method.
public class myService extends IntentService {
private boolean shown = false;
private ButtonReceiver buttonReceiver;
//Side note: this is legacy code. Necessary?
public myService() {
super("myService");
}
@Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter("com.myapp.KILL_NOTIFICATION");
this.buttonReceiver = new ButtonReceiver();
this.registerReceiver(this.buttonReceiver, filter);
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(this.buttonReceiver);
}
@Override
protected void onHandleIntent(Intent intent) {
if(intent.getAction() == "com.myapp.START_SERVICE") {
//generate a unique id for the notification
int id = Integer.parseInt(new SimpleDateFormat("ddHHmmss", Locale.US).format(new Date()));
//create a pending intent to send off when the kill action is pressed
Intent buttonIntent = new Intent("com.myapp.KILL_NOTIFICATION");
buttonIntent.putExtra("notificationId", id);
PendingIntent btPendingIntent = PendingIntent.getBroadcast(this, 0, buttonIntent, 0);
Notification.Builder builder = new Notification.Builder(getApplicationContext());
builder.setAutoCancel(false);
builder.setContentTitle("my app");
//builder.setContentText("Press this notification to kill.");
builder.setOngoing(true);
builder.setSmallIcon(R.drawable.ic_launcher);
//builder.setContentIntent(pendingIntent);
builder.addAction(R.drawable.ic_clear_black_24dp, "Kill my app", btPendingIntent);
builder.setWhen(0);
builder.setPriority(Notification.PRIORITY_MAX);
Notification notification = builder.build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//TODO need to find first unused notif id
notificationManager.notify(id, notification);
}
}
public class ButtonReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getIntExtra("notificationId", 0);
Intent killIntent = new Intent("com.myapp.KILL_EVERYTHING");
killIntent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(killIntent);
//cancel notification
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(notificationId);
}
}
}
An IntentService
stops itself after the onHandleIntent()
method finishes, so your dynamically registered Receiver is no longer around to get the broadcast when it happens.
You don't need a Service
to maintain an ongoing Notification
. In your case, you can simply issue the Notification
directly, instead of starting the Service
to do it. Then register your Receiver class statically in the manifest, and use an explicit Intent
to broadcast to it from the Notification
.
Move ButtonReceiver
to it's own class file, and register it in the manifest like so:
<receiver android:name=".ButtonReceiver" />
You'll need to call startActivity()
on the context
parameter passed into onReceive()
, like you are getSystemService()
. You'll also need to add the following flag to the Intent
.
killIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Then just change buttonIntent
for the Notification
's PendingIntent
to:
Intent buttonIntent = new Intent(this, ButtonReceiver.class);
If that's the only broadcast ButtonReceiver
will handle, you won't really need the KILL_NOTIFICATION
action anymore.