I am getting this error shown in the Android Dashboard crash logs:
Context.startForegroundService() did not then call Service.startForeground() (no location available)
I'm aware of the Background Limitations introduced in Oreo and have read through this post.
However, I'm still getting this error thrown for a small percentage of my users who are running Android Wear 8.0. What makes it confusing is it's not all users running 8.0.
According to the documentation, if you call Context.startForgroundService() you must show a notification by calling startForeground() in the service within 5 seconds (I'm assuming MediaBrowserCompat is calling Context.startForgroundService()).
However, I'm not sure if I need to do that if I'm using a MediaBrowserServiceCompat. I do show a foreground notification when the user hits play to start audio playback.
public class MediaActivity {
private MediaBrowserCompat mMediaBrowserCompat;
#Override
public void onCreate() {
super.onCreate(savedInstanceState);
mMediaBrowserCompat = new MediaBrowserCompat(
this,
new ComponentName(this, MediaPlayerService.class),
mMediaBrowserCompatConnectionCallback,
getIntent().getExtras()
);
mMediaBrowserCompat.connect();
}
}
private MediaBrowserCompat.ConnectionCallback mMediaBrowserCompatConnectionCallback = new MediaBrowserCompat.ConnectionCallback() {
#Override
public void onConnected() {
super.onConnected();
final MediaControllerCompat mcc = new MediaControllerCompat(MediaActivity.this, mMediaBrowserCompat.getSessionToken());
mcc.registerCallback(mMediaControllerCompatCallback);
MediaControllerCompat.setMediaController(mActivity, mcc);
}
};
public class MediaPlayerService extends MediaBrowserServiceCompat {
#Override
public void onCreate() {
super.onCreate();
//Should I add a startForeground notification here
}
}
private MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() {
#Override
public void onPlay() {
super.onPlay();
final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelID)
...
startForeground(101, builder.build());
}
#Override
public void onPause() {
super.onPause();
}
};
You have to use the startForegroundService before calling startforeground to attach the foreground notification if you are running audio mediaCompact service , this will not destroy by the system due to background limitation.
Related
I am developing an app where the app will detect Bluetooth signals (Sensoro Smart Beacon device) and open the activity. But I want the app to still be able to detect the signal even when the application on the background or even when killed. I used a foreground service, it detects the signal when I open the application and move between activities but when sending the app to the background and opening other applications, the listener stops although the service still working. I am printing the logs. System.out.println("Sensoro 2" ); keeps printing even when I kill the application or open another application. But the printing logs in BeaconManagerListener are not working. I tried to use background service but it didn't work also.
Can you please advise if there is a way to make the listener works in a service when the app in background or killed?
Here is the service code:
public class MyService extends Service {
public static final String CHANNEL_ID = "ForegroundServiceChannel";
int service_timer=0;
Timer timer = new Timer();
SensoroManager sensoroManager;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
sensoroManager = SensoroManager.getInstance(MyService.this);
String input = intent.getStringExtra("inputExtra");
System.out.println("Sensoro 2" );
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent)
.build();
startForeground(1,notification);
//do heavy work on a background thread
//stopSelf();
if (sensoroManager.isBluetoothEnabled()) {
sensoroManager.setCloudServiceEnable(true);
/**
* Enable SDK service
**/
try {
sensoroManager.startService();
} catch (Exception e) {
e.printStackTrace(); // Fetch abnormal info
}
}
else
{
Toast.makeText(MyService.this,"Bluetooth off",Toast.LENGTH_LONG).show();
}
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//your method
System.out.println("Sensoro 2" );
BeaconManagerListener beaconManagerListener = new BeaconManagerListener() {
#Override
public void onUpdateBeacon(ArrayList<Beacon> beacons) {
// Refresh sensor info
for (Beacon beacon : beacons
) {
System.out.println("Sensoro 3" );
// System.out.println("Sensoro" +beacon.getAccuracy());
}
}
#Override
public void onNewBeacon(Beacon beacon) {
if (beacon.getSerialNumber().equals("0117C59B243C")){
System.out.println("Sensoro 3" );
System.out.println("Sensoro acc" +beacon.getAccuracy());
}
}
#Override
public void onGoneBeacon(Beacon beacon) {
if (beacon.getSerialNumber().equals("0117C59B243C")){
System.out.println("Sensoro acc gone");
System.out.println("Sensoro acc Timer" +service_timer);
}
}
};
sensoroManager.setBeaconManagerListener(beaconManagerListener);
}
}, 0, 2000);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
// timer.cancel();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
Here is where I call it:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService();
}
public void startService() {
Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("inputExtra", "Foreground Service Example in Android");
System.out.println("Sensoro 1 ");
ContextCompat.startForegroundService(this, serviceIntent);
}
public void stopService() {
Intent serviceIntent = new Intent(this, MyService2.class);
stopService(serviceIntent);
}
public void movingg(View view) {
Intent intent=new Intent(this,Usermain.class);
startActivity(intent); }
}
This is not 100% a match with what are you searching but this is near to what are you want.
You can use WorkManager that is working even application in the background. There are two types of WorkManager. 1) OneTimeWorkRequest 2) PeriodicWorkRequest.
So you can you PeriodicWorkRequest which will call every 15 min(minimum interval) and you can add your code in WorkManager to detect Bluetooth signals. So you can able to detect Bluetooth single at every 15 mins of intervals.
I hope this will help you solve your problem.
I don't know if this will help you, but here's my answer:
public void startService() {
Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("inputExtra", "Foreground Service Example in Android");
System.out.println("Sensoro 1 ");
startService(serviceIntent);
}
I looked at the Android rules and regulations page
According to Google documents, from Android 8 onwards, all applications that do not have a Google-approved signature will be removed from the background after a few minutes.
But the solutions:
The first solution is to run the application in debug mode
The second solution is to assign a signature to the application and send it to Google for approval
recommend:
The third solution is to remove the google play service application from the emulator or android phone
you can use BroadcastReceiver.
if your app is killed or in the background ,the broadcast receiver is catch the event of bluetoth
I see there are two issues with your approach here.
First you should your check for specific beacon serial number could be causing issue.
Secondly you are using a Timer that goes off every 2 seconds and every time it does it adds a new BeaconManagerListener which should not be the case you should extract the listener outside maybe make it a class member and then use the same listener every time instead of continuously creating new listener which then replaces the old one.
Also why add listener after 2 seconds I think is should be added before calling sensoroManager.startService()
Lastly if the task is not needed to be repeated every few seconds and can be done with an interval >= 15 mins then consider using Periodic Work Manager instead.
I have an IntentService and inside this instant service, in onCreate, I call the method startforeground(). I see then the notification when the intentService is created. However, when the IntentService is destroyed (going to onDestroy), I can see the notification for few seconds after that the service is destroyed. Why is that?
This is the code of the IntentService:
public class USFIntentService extends IntentService {
private static final String TAG = "USFIntentService";
private static final int USF_NOTIFICATION_ID = 262276;
private static final String USF_NOTIFICATION_CHANNEL_ID = "USF_NOTIFICATION_CHANNEL";
public USFIntentService() {
super("USFIntentService");
}
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG,"in onCreate");
startUsfForegroundService();
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG,"in onDestroy");
}
private void startUsfForegroundService() {
// Define notification channel
CharSequence name = getString(R.string.channel_name);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel =
new NotificationChannel(USF_NOTIFICATION_CHANNEL_ID, name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
// Build notification to be used for the foreground service.
Notification notification =
new Notification.Builder(this, USF_NOTIFICATION_CHANNEL_ID)
.setContentTitle(getText(R.string.notification_title))
.setContentText(getText(R.string.notification_message))
.setSmallIcon(R.drawable.usf_notification_icon)
.build();
// Set the service as a foreground service.
startForeground(USF_NOTIFICATION_ID, notification);
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "onHandleIntent");
if (intent != null) {
doStuff();
}
Log.i(TAG,"End of onHandleIntent");
}
}
I call this service like this:
Intent startServiceIntent = new Intent(intent);
startServiceIntent.setComponent(new ComponentName(context, USFIntentService.class));
context.startForegroundService(startServiceIntent);
Try to call Service#stopForeground after your job is done to remove it
You can call stopForeground(true) when you finish doing the stuff. So that your service gets immediately removed from foreground state and the parameter true ensures that the notification will be removed.
If STOP_FOREGROUND_REMOVE is supplied, the service's associated notification will be cancelled immediately.
If STOP_FOREGROUND_DETACH is supplied, the service's association with the notification will be severed. If the notification had not yet been shown, due to foreground-service notification deferral policy, it is immediately posted when stopForeground(STOP_FOREGROUND_DETACH) is called. In all cases, the notification remains shown even after this service is stopped fully and destroyed.
stopForeground(STOP_FOREGROUND_REMOVE) // remove with notification
stopForeground(STOP_FOREGROUND_DETACH) // remove only intent and not notification
1.I have started a forground service from mainActivity. Also added permission in manifest file android.permission.FOREGROUND_SERVICE but application is crashing.
2.Application is working bellow 9.0 but crashing in android 10.
public class SocketService extends Service {
#Override
public void onCreate() {
super.onCreate();
mCommunicationThread = new Thread(new SocketThread());
mCommunicationThread.start();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channel = createNotificationChannel(getString(R.string.app_name), "Service");
Notification notification = new NotificationCompat.Builder(this, channel)
.setContentTitle("Name")//.build();
.setContentText("Do not close it").build();
startForeground(10012, notification);
}
}
/**
* Thread class which runs in background to accept data which is received
from server via socket
*/
private class SocketThread implements Runnable {
#Override
public void run() {
}
}
/**
Create notification channel
*/
private String createNotificationChannel(String channelId, String channelName) {
NotificationChannel chan = new NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_HIGH);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(chan);
return channelId;
}
}
/**
Start service from MainActivity
*/
Intent intentService = new Intent(MainActivity.this,SocketService.class);
this.startForegroundService(intentService);
You should consider replacing this.startForegroundService(intentService) by ContextCompat.startForegroundService(this, intentService)
Service are manage differently pre-O and post-O with ContextCompat it'll do the check :
public static void startForegroundService(#NonNull Context context, #NonNull Intent intent) {
if (Build.VERSION.SDK_INT >= 26) {
context.startForegroundService(intent);
} else {
// Pre-O behavior.
context.startService(intent);
}
}
PS: You might need to override onHandleIntent in your service to call startForeground
If your application still crashes, update your initial post and give us the log.
I have hundred of crashes reported by my users and I still can't find a fix for it. These crashes are coming from Android 8 (Samsung, Huawei, Google).
I am getting these two crashes:
Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1881)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6938)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
and the other one:
Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2104)
at android.os.Handler.dispatchMessage(Handler.java:108)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7428)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
I assume these crashes are the same, but as you can see the stack trace shows different line of code.
The problem is that I can't reproduce it, everything works fine on my devices and my emulator. However, I (somehow) reproduced by creating a service without calling the startForeground() within the Service class.
I'm unable to "catch" the exception, because it comes from system-level right after 5 seconds when the service was created.
What have I done is that I have created a method which creates a sticky notification and calling the startForeground method (my Service class):
private void startWithNotification() {
Resources res = getResources();
String title = res.getString(R.string.application_name);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createChannels();
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, ANDROID_CHANNEL_ID)
.setContentTitle(title)
.setChannelId(ANDROID_CHANNEL_ID)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setOngoing(true)
.setAutoCancel(false)
.setSmallIcon(R.drawable.ic_siluette)
.setColor(ContextCompat.getColor(this, R.color.colorPrimary))
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.application_icon));
startForeground(NOTIFICATION_APP, builder.build());
}
private void createChannels() {
// create android channel
NotificationChannel androidChannel = new NotificationChannel(ANDROID_CHANNEL_ID, ANDROID_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
// Sets whether notifications posted to this channel should display notification lights
androidChannel.enableLights(true);
// Sets whether notification posted to this channel should vibrate.
androidChannel.enableVibration(true);
// Sets the notification light color for notifications posted to this channel
androidChannel.setLightColor(Color.GREEN);
// Sets whether notifications posted to this channel appear on the lockscreen or not
androidChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.createNotificationChannel(androidChannel);
}
This method is getting called from different Service life-cycle-events:
onCreate()
onStartCommand()
stopService()
onDestroy()
I am calling the method within these events, because people said that the Service might not being created and it's automatically destroyed.
The service gets started when an incoming or an outgoing call is made via BroadcastReceiver:
public class IncomingOutgoingCallReceiver extends BroadcastReceiver {
private void callAppService(Context context, int callType) {
Intent intent = new Intent(context, MyService.class);
Bundle bundle = new Bundle();
bundle.putInt(CALL_TYPE, callType);
intent.putExtras(bundle);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
}
else {
context.startService(intent);
}
}
private void onCallEnd(Context context) {
context.stopService(new Intent(context, MyService.class));
}
}
The Service class:
public class MyService extends Service {
private void handleIntent(Intent intent) {
// Use intent data and do work
if (canStartService(intent)) {
return;
}
}
private boolean canStartService(Intent intent) {
// multiple checks
// if (intent bundle contains ... ) return false;
// if (phone number contains .... ) return false;
return true;
}
#Override
public void onCreate() {
super.onCreate();
startWithNotification();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleIntent(intent);
startWithNotification();
return START_NOT_STICKY;
}
private void startWithNotification() {
// Contains the code from above (didn't put here because of space)
}
#Override
public boolean stopService(Intent name) {
startWithNotification();
return super.stopService(name);
}
// Can be called from different Views which are attached to the WindowManager (user interacting with the UI)
public void stopService() {
startWithNotification();
stopForeground(true);
stopSelf();
}
#Override
public void onDestroy() {
startWithNotification();
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I have an app that has two services.
One is for showing UI for floating (overlay) on other apps using WindowManager. The other is for Location Tracking using GooglePlayAPI. My app always runs these services.
I want these services not to be killed by the OS. So I call Service.startForeground(). However there are two notifications in the notification drawer.
Is there a way to use a single notification for both services?
Yes, it is possible.
If we take a look at Service.startForeground() signature, it accept both notification id & the notification itself (see documentation). Hence, if we want to have an only single notification for more than one foreground services, these services must share the same notification & notification id.
We can use the singleton pattern to get the same notification & notification id. Here is the example implementation:
NotificationCreator.java
public class NotificationCreator {
private static final int NOTIFICATION_ID = 1094;
private static final String CHANNEL_ID = "Foreground Service Channel";
private static Notification notification;
public static Notification getNotification(Context context) {
if(notification == null) {
notification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("Try Foreground Service")
.setContentText("Yuhu..., I'm trying foreground service")
.setSmallIcon(R.mipmap.ic_launcher)
.build();
}
return notification;
}
public static int getNotificationId() {
return NOTIFICATION_ID;
}
}
Thus, we can use this class in our foreground services. For example, we have MyFirstService.java & MySecondService.java:
MyFirstService.java
public class MyFirstService extends Service {
#Override
public void onCreate() {
super.onCreate();
startForeground(NotificationCreator.getNotificationId(),
NotificationCreator.getNotification(this));
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
MySecondService.java
public class MySecondService extends Service {
#Override
public void onCreate() {
super.onCreate();
startForeground(NotificationCreator.getNotificationId(),
NotificationCreator.getNotification(this));
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Just try to run these services. Voila! You have a single notification for multiple foreground services ;)!