I have tried every suggestion I could find on the Internet to use Foreground Service to keep my app running beyond sleep and deep sleep modes but nothing has been successful so far.
I am working on a taxi booking application. I designed it to start emitting driver's location to server whenever the driver turns himself Online and stop emitting when Offline.
The following is the Foreground Service code that is started whenever driver turns himself Online and stopped when he presses online button which changes Common.CustomSocketOn to 0.
It work fine during screen wake and also works when the screen is off before the app gets killed.
However, even with WAKE_LOCK acquired, it still can't stay more than few minutes in sleep mode before getting killed by Android 7.
This failure to keep running in sleep mode breaks down many other features of the app because when the app gets killed silently, it does not get the chance to turn the driver Offline nor sign him out. As a result, the driver gets booking requests when his app is not running and therefore, cannot attend to it, and that keeps the booking from going to the next available driver. In fact, this causes so many other anomalies.
Please, can somebody tell me any other thing I need to do to keep Android from killing the Foreground Service.
public class OnlineForeGroundService extends Service {
private static final String TAG_FOREGROUND_SERVICE = "FOREGROUND_SERVICE";
public static final String ACTION_START_FOREGROUND_SERVICE = "ACTION_START_FOREGROUND_SERVICE";
public static final String ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE";
private static LocationListener locationListener;
private static LocationManager locationManager;
private PowerManager.WakeLock wakeLock;
public OnlineForeGroundService() {
}
@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 onCreate() {
super.onCreate();
Log.d(TAG_FOREGROUND_SERVICE, "My foreground service.");
final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
try {
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "KEEP_AWAKE");
}
catch (Exception e){
e.printStackTrace();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null)
{
String action = intent.getAction();
if(action != null) {
switch (action) {
case ACTION_START_FOREGROUND_SERVICE:
startForegroundService();
Toast.makeText(getApplicationContext(), getText(R.string.going_online), Toast.LENGTH_SHORT).show();
wakeLock.acquire();
break;
case ACTION_STOP_FOREGROUND_SERVICE:
stopForegroundService();
//Toast.makeText(getApplicationContext(), getText(R.string.going_offline), Toast.LENGTH_SHORT).show();
break;
}
}
}
return super.onStartCommand(intent, flags, startId);
//return START_STICKY;
}
/* Used to build and start foreground service. */
@SuppressLint("MissingPermission")
private void startForegroundService()
{
if(OnlineForeGroundService.locationManager == null) {
OnlineForeGroundService.locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
if(OnlineForeGroundService.locationListener == null) {
OnlineForeGroundService.locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if (Common.CustomSocketOn == 1) {
SharedPreferences userPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (Common.OldLatitude != 0 && Common.OldLongitude != 0) {
float distance[] = new float[1];
Location.distanceBetween(Common.OldLatitude, Common.OldLongitude, location.getLatitude(), location.getLongitude(), distance);
//Distance - 100
if (distance.length > 0 && distance[0] > 30) {
try {
JSONArray locAry = new JSONArray();
locAry.put(location.getLatitude());
locAry.put(location.getLongitude());
JSONObject emitobj = new JSONObject();
emitobj.put("coords", locAry);
emitobj.put("driver_name", userPref.getString("user_name", ""));
emitobj.put("driver_id", userPref.getString("id", ""));
emitobj.put("driver_status", "1"); //change by sir
emitobj.put("car_type", userPref.getString("car_type", ""));
emitobj.put("isdevice", "1");
emitobj.put("booking_status", userPref.getString("booking_status", ""));
emitobj.put("isLocationChange", 1);
if (location.getLatitude() != 0.0 && location.getLongitude() != 0.0 && Common.socket != null && Common.socket.connected()) {
Common.socket.emit("Create Driver Data", emitobj);
} else if (location.getLatitude() != 0.0 && location.getLongitude() != 0.0 && Common.socket == null) {
Common.socket = null;
SocketSingleObject.instance = null;
Common.socket = SocketSingleObject.get(getApplicationContext()).getSocket();
Common.socket.connect();
Common.socket.emit("Create Driver Data", emitobj);
} else if (location.getLatitude() != 0.0 && location.getLongitude() != 0.0 && Common.socket != null && !Common.socket.connected()) {
Common.socket.connect();
Common.socket.emit("Create Driver Data", emitobj);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Common.OldLatitude = location.getLatitude();
Common.OldLongitude = location.getLongitude();
}
}
if (Common.OldLatitude == 0 && Common.OldLongitude == 0) {
Common.OldLatitude = location.getLatitude();
Common.OldLongitude = location.getLongitude();
}
}
else{
stopForegroundService();
}
}
@Override
public void onProviderDisabled(String provider) {
Log.d("Latitude", "disable");
}
@Override
public void onProviderEnabled(String provider) {
Log.d("Latitude", "enable");
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
}
if(Common.isPermission){
if(Common.CustomSocketOn == 1){
try {
OnlineForeGroundService.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, Common.DriverDistanceTime, Common.DriverDistance, OnlineForeGroundService.locationListener);
OnlineForeGroundService.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, Common.DriverDistanceTime, Common.DriverDistance, OnlineForeGroundService.locationListener);
}
catch (Exception e){
e.printStackTrace();
}
}
}
Log.d(TAG_FOREGROUND_SERVICE, "Starting foreground service.");
String onlineSticker = getText(R.string.app_name)+" - Online";
Intent notificationIntent = new Intent(this, HomeActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification;
/*if(android.os.Build.VERSION.SDK_INT >= 26) {
notification = new Notification.Builder(HomeActivity.class, NotificationManager.IMPORTANCE_HIGH)
.setContentTitle(getText(R.string.app_name))
.setContentText(getText(R.string.you_are_online))
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setTicker(onlineSticker)
.build();
//startForeground(ONGOING_NOTIFICATION_ID, notification);
// Start foreground service.
}
else{*/
notification = new Notification.Builder(this)
.setContentTitle(getText(R.string.app_name))
.setContentText(getText(R.string.you_are_online))
.setPriority(Notification.PRIORITY_HIGH)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setTicker(onlineSticker)
.build();
//}
startForeground(397, notification);
}
private void stopForegroundService()
{
Toast.makeText(getApplicationContext(), getText(R.string.going_offline), Toast.LENGTH_SHORT).show();
if(Common.isPermission){
if(Common.CustomSocketOn == 0){
try {
OnlineForeGroundService.locationManager.removeUpdates(OnlineForeGroundService.locationListener);
//OnlineForeGroundService.locationListener = null;
}
catch (Exception e){
e.printStackTrace();
}
}
}
Log.d(TAG_FOREGROUND_SERVICE, "Stop foreground service.");
if (null != wakeLock && wakeLock.isHeld()) {
wakeLock.release();
}
// Stop foreground service and remove the notification.
stopForeground(true);
// Stop the foreground service.
stopSelf();
}
}
Here is the androidManifest entry for the service and WAKE_LOCK permission:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<service
android:name=".driver.service.OnlineForeGroundService"
android:process=".process"
android:enabled="true"
android:exported="true" ></service>