Instead of
stopForeground(true)
calling,
stopForeground(false)
should retain the notification as it is (without ongoing state) unless it is dismissed by user/removed programmatically.
This also should prevents notification flashing since I am not recreating the notification.
But it does not work. stopForeground(false) has the same behavior of stopForeground(true).
This is a sample project:
public class AudioTestService extends Service {
private static final String CHANNEL_ID = "TestChannel";
private static final int NOTIFICATION_ID = 14;
Notification mBuilder;
public AudioTestService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
return null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
stopForeground(true);
super.onTaskRemoved(rootIntent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent intentA = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intentA, 0);
Notification mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Titolo")
.setContentText("Descrizione")
.setContentIntent(pendingIntent)
.setOngoing(false)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build();
this.mBuilder = mBuilder;
createNotificationChannel();
startForeground(NOTIFICATION_ID, mBuilder);
return START_STICKY;
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = CHANNEL_ID;
String description = CHANNEL_ID + "Description ";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
#Override
public void onDestroy() {
stopForeground(false);
//NotificationManagerCompat.from(this).notify(NOTIFICATION_ID, mBuilder);
super.onDestroy();
} }
The activity, easily handle the button click event:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startService = findViewById(R.id.startService);
Button stopService = findViewById(R.id.stopService);
Button stopNotification = findViewById(R.id.stopWithNotification);
startService.setOnClickListener(this);
stopService.setOnClickListener(this);
stopNotification.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.startService:
ContextCompat.startForegroundService(this, new Intent(this, AudioTestService.class));
break;
case R.id.stopService:
finish();
break;
case R.id.stopWithNotification:
stopService(new Intent(this, AudioTestService.class));
break;
}
}}
If you look at the Service's onDestroy() method I set
stopForeground(false);
instead of the method onTaskRemoved() that should remove the notification when the app is cleaned from the task list.
What am I doing wrong?
Please do not mark this as duplicated, I am looking for a solution for days...
Instead of calling stopForeground(false); from onDestroy(), send a broadcast from activity (with action) for stop service. Change your onStartCommand code to check action in intent and do startForeground or stopForeground(false);
Related
Masters:
There is problem on my program as following:
Compile platform:android studio 3.2
moible of test: android 8.0
operation: press "home", make progrem run on the background. it is OK on charging state. If not charged, the service would be "dead" after about one minute. How can I make it keep alive longer? Thanks. codes attached:
========the first part:activity class (partial codes)
Intent i=new Intent(this,RegistService.class);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
this.startForegroundService(i);
} else {
this.startService(i);
}
========the 2nd part: service class
public class RegistService extends Service {
Timer timer;
int num=0;
public static final String CHANNEL_ID_STRING = "test001";
#Override
public void onCreate() {
super.onCreate();
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel mChannel = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
mChannel = new NotificationChannel(CHANNEL_ID_STRING, "test001", NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(mChannel);
Notification notification = new Notification.Builder(getApplicationContext(), CHANNEL_ID_STRING).build();
startForeground(28, notification);
}
}
#Override
public void onStart(Intent intent, int startId) {
TimerTask task = new TimerTask(){
public void run(){
num=num+1;
Log.v(num+"count","test");
}
};
timer = new Timer();
timer.schedule(task, 1000,1000);
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
Hi I have got problems with launching IntentService as a foreground service. Unfortunatelly the official tutorial does not tell me much as some of methods does not exists, some are deprecated and moreover it's not said where to place the code, that they provide.
I created my own IntentService and I have overridden onCreate method. It looks following:
#Override
public void onCreate(){
super.onCreate();
Intent notificationIntent = new Intent(this, Settings.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new Notification.Builder(this)
.setContentTitle(getText(R.string.serviceName))
.setContentText(getText(R.string.serviceDescription))
.setSmallIcon(R.mipmap.ic_launcher)
.setOngoing(true)
.setContentIntent(pendingIntent)
.build();
startForeground(101, notification);
I know it's not debugging site, but surely there is something obvious, that I am missing. Settings class is my Activity class, from which startService was called, I have also set all needed things to the notification and called startForeground with nonzero first argument. Still no notification appears, although I am pretty sure, that service is working in the background.
Any help would be appreciated (btw. I have already searched for different topics on SO woth service in foreground, but with no help.)
If you use a Service instead of IntentService, you can put the code you wrote to build the notification & startForeground() in onStartCommand :
public class SettingsService extends Service {
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
public SettingsService getService() {
return SettingsService.this;
}
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, SettingsService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new Notification.Builder(this)
.setContentTitle("myService")
.setContentText("this is an example")
.setSmallIcon(R.mipmap.ic_launcher)
.setOngoing(true)
.setContentIntent(pendingIntent)
.build();
startForeground(101, notification);
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
Additionnaly, in onStartCommand, return START_NOT_STICKY if you dont want the service to be recreated when it is killed otherwise return START_STICKY
My application has a button : "Foreground". By clicking on the foreground button, a notification appears attached to a foreground service (started at the time of click). Clicking on my notification is supposed to stop my service (with a PendingIntent) to be able to be garbage collected, however, this is not the case. Android Studio tells me, that there is a reference to my Service held by a NotificationManager. The weird thing is that it only happens if I click on my notification after I closed the main activity.
My service code:
public class TestService extends IntentService {
public static final String ACTION_GO_FOREGROUND = "GO_FOREGROUND";
public static final String ACTION_DESTROY = "DESTROY";
private NotificationManagerCompat notificationManager;
public TestService() {
super("Name");
}
#Override
public void onCreate() {
super.onCreate();
notificationManager = NotificationManagerCompat.from(this);
}
#Override
public void onDestroy() {
super.onDestroy();
notificationManager.cancelAll();
notificationManager = null;
}
#Override
protected void onHandleIntent(Intent intent) {
}
#Override
public int onStartCommand(Intent intent, int flags, final int startId) {
switch (intent.getAction()) {
case ACTION_GO_FOREGROUND:
fg();
break;
case ACTION_DESTROY:
destruct();
break;
}
return START_STICKY;
}
private void destruct() {
stopForeground(true);
stopSelf();
}
private void fg() {
Intent intent = new Intent(this, TestService.class);
intent.setAction(ACTION_DESTROY);
// Create the notification.
android.support.v7.app.NotificationCompat.Builder notificationBuilder = new android.support.v7.app.NotificationCompat.Builder(this);
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);
notificationBuilder.setTicker("Ticker");
notificationBuilder.setContentTitle("Title");
notificationBuilder.setContentText("Content text");
notificationBuilder.setContentIntent(PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
startForeground(1, notificationBuilder.build());
}
I know the code is messy, but it's just a sample. So why is there a reference to my service, but only if you close the activity and try to destroy the service?
Try removing the code from OnDestroy -
notificationManager.cancelAll();
notificationManager = null;
and place it in destruct() before calling stopSelf()
There seems to be other questions regarding cancelling ongoing notification.
However, i really look into quite a number of them and still have no solution.
SettingFragment
public class SettingFragment extends Fragment {
private Switch mSwitchNotific;
mSwitchNotific.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if(isChecked){
Log.v(LOGTAG, "step notification on");
getContext().startService(new Intent(getContext(), UpdateStepNotificationService.class));
}else{
Log.v(LOGTAG, "step notification off");
NotificationManager notificationManager = (NotificationManager)
getContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(StickyUpdateStepNotification.NOTIFICATION_ID);
}
}
}
}
UpdateStepNotificationService
public class UpdateStepNotificationService extends Service {
static NotificationManager notificationManger;
StepsDBHandler stepsDBHandler;
public UpdateStepNotificationService() {}
#Override
public void onCreate() {
super.onCreate();
stepsDBHandler = new StepsDBHandler(getApplicationContext(), null, null, 0);
notificationManger = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
StickyUpdateStepNotification.NOTIFICATION_ID,
new Intent(getApplicationContext(), MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
final Notification notification = new Notification.Builder(
getApplicationContext())
.setSmallIcon(R.drawable.ic_notice)
.setContentTitle("Walksapp")
.setContentText("Now: " +Integer.toString(stepsDBHandler.getCurrentStepToday()) + " steps")
.setContentIntent(pendingIntent)
.build();
notification.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
new Timer().schedule(new TimerTask() {
#Override
public void run() {
notificationManger.notify(StickyUpdateStepNotification.NOTIFICATION_ID, notification);
}
}, 0, 1000);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onDestroy() {
notificationManger.cancel(StickyUpdateStepNotification.NOTIFICATION_ID);
super.onDestroy();
}
}
UpdateStepNotificationService for repeating issue new notification with latest step count.
The notification is with FLAG_NO_CLEAR and FLAG_ONGOING_EVENT.
The only way turn on and off the notification is by switch button in SettingFragment.
Attempt:
notificationManger.cancel(StickyUpdateStepNotification.NOTIFICATION_ID);
Not working
Hope to see any input
Thanks
You will need to kill the timer otherwise it will continue updating the notification.
I have a simple app that downloads a file from the internet using a service showing the progress in a progress dialog and also in an ongoing notification.
My problem is how to remove the notification when the user stops the download by force closing the app (for example by long pressing the home button and by clearing all the recent apps list).
I tried with this:
#Override
protected void onDestroy() {
Toast.makeText(getApplicationContext(), "ADDIO", Toast.LENGTH_SHORT).show();
NotificationManager nm =(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancelAll();
super.onDestroy();
}
but it doesn't work.
Please help
You could start a service from your activity.
Step 1 create a service that kills
Simple one. It just kills a notification on create and has his special Binder.
public class KillNotificationsService extends Service {
public class KillBinder extends Binder {
public final Service service;
public KillBinder(Service service) {
this.service = service;
}
}
public static int NOTIFICATION_ID = 666;
private NotificationManager mNM;
private final IBinder mBinder = new KillBinder(this);
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
#Override
public void onCreate() {
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNM.cancel(NOTIFICATION_ID);
}
}
Step2: Add it to your manifest:
Add it somewhere inbetween your <application> tags.
<service android:name="KillNotificationsService"></service>
Step3: Always create the Service before firing the notification, and use the static notificationid.
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder binder) {
((KillBinder) binder).service.startService(new Intent(
MainActivity.this, KillNotificationsService.class));
Notification notification = new Notification(
R.drawable.ic_launcher, "Text",
System.currentTimeMillis());
Intent notificationIntent = new Intent(MainActivity.this,
Place.class);
PendingIntent contentIntent = PendingIntent.getActivity(
MainActivity.this, 0, notificationIntent, 0);
notification.setLatestEventInfo(getApplicationContext(),
"Text", "Text", contentIntent);
NotificationManager mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNM.notify(KillNotificationsService.NOTIFICATION_ID,
notification);
}
public void onServiceDisconnected(ComponentName className) {
}
};
bindService(new Intent(MainActivity.this,
KillNotificationsService.class), mConnection,
Context.BIND_AUTO_CREATE);
It might take a little time until service is restarted (1-5 sec), but it will eventually start and kill the notification.