0

I am working on a location tracking application. I need to fetch the user location on every 500-meter displacement or in every 30 minutes. I created a foreground service and returned START_STICKY on onStartCommand method. Tracking is working perfectly until the app is cleared from recent apps. If I cleared my app from recent apps section the foreground service also removing from the background. how can I make it sticky there forever?

Note: I am doing this location tracking with the knowledge of user .

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Temp.msg(TAG, "onStartCommand");

    startMyOwnForeground();
    return START_STICKY;
} 


private void startMyOwnForeground() {
    String NOTIFICATION_CHANNEL_ID = Temp.getNotificationChannelId();
    String channelName = Temp.getNotificationChannelName();
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        NotificationChannel chan = null;
        chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);

        chan.setLightColor(Color.BLUE);
        chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        assert manager != null;
        manager.createNotificationChannel(chan);
    }
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
    Notification notification = notificationBuilder.setOngoing(true)
            .setSmallIcon(R.drawable.ic_push_notifications)
            .setContentTitle("Checked In")
            .setPriority(NotificationManager.IMPORTANCE_HIGH)
            .setCategory(Notification.CATEGORY_SERVICE)
            .build();
    startForeground(1, notification);
}

Note: I tried START_STICKY and START_NOT_STICKY on onStartCommand method but it both removed from the background when the app removed from recent apps

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
JITHIN GOPAL
  • 131
  • 1
  • 14
  • did you find your solution?? – BlackBlind May 06 '19 at 11:41
  • @BlackBlind I found why the app is removing from the background. That was not my code's problem. It happened because the phone I used was Redmi. In Redmi phones, It requires additional permission (AutoStart permission) from Redmi phone settings. – JITHIN GOPAL Aug 17 '19 at 15:05

2 Answers2

0

PLease try to this way:

Start Service

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
     ContextCompat.startForegroundService(MainActivity.this, new Intent(MainActivity.this, ServiceLocation.class));
 } else {
     startService(new Intent(MainActivity.this, ServiceLocation.class));
 }

Service Class

public class ServiceLocation extends Service implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener {

    private static final String NOTIFICATION_CHANNEL_ID = "my_notification_location";
    private static final long TIME_INTERVAL_GET_LOCATION = 1000 * 5; // 1 Minute
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 7; // meters

    private Handler handlerSendLocation;
    private Context mContext;

    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;

    private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 5000;

    Location locationData;

    @Override
    public void onCreate() {
        super.onCreate();

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

        // Create the LocationRequest object
        mLocationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(TIME_INTERVAL_GET_LOCATION)    // 3 seconds, in milliseconds
                .setFastestInterval(TIME_INTERVAL_GET_LOCATION); // 1 second, in milliseconds

        mContext = this;


        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
                .setOngoing(false)
                .setSmallIcon(R.drawable.ic_notification)
                .setColor(getResources().getColor(R.color.fontColorDarkGray))
                .setPriority(Notification.PRIORITY_MIN);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
                    NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW);
            notificationChannel.setDescription(NOTIFICATION_CHANNEL_ID);
            notificationChannel.setSound(null, null);
            notificationManager.createNotificationChannel(notificationChannel);
            startForeground(1, builder.build());
        }
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.w("Service Update Location", "BGS > Started");

        if (handlerSendLocation == null) {
            handlerSendLocation = new Handler();
            handlerSendLocation.post(runnableSendLocation);
            Log.w("Service Send Location", "BGS > handlerSendLocation Initialized");
        } else {
            Log.w("Service Send Location", "BGS > handlerSendLocation Already Initialized");
        }

        return START_STICKY;
    }

    private Runnable runnableSendLocation = new Runnable() {

        @Override
        public void run() {
            Log.w("Service Send Location", "BGS >> Location Updated");

            // You can get Location
            //locationData and Send Location X Minutes
            if (locationData != null) {

                Log.w("==>UpdateLocation<==", "" + String.format("%.6f", locationData.getLatitude()) + "," +
                        String.format("%.6f", locationData.getLongitude()));


            }
            if (handlerSendLocation != null && runnableSendLocation != null)
                handlerSendLocation.postDelayed(runnableSendLocation, TIME_INTERVAL_GET_LOCATION);
        }
    };


    @Override
    public void onConnected(@Nullable Bundle bundle) {
        if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            return;
        }


        FusedLocationProviderClient mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        mFusedLocationClient.requestLocationUpdates(mLocationRequest, new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                locationData = locationResult.getLastLocation();
            }
        }, null);
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        if (connectionResult.hasResolution() && mContext instanceof Activity) {
            try {
                Activity activity = (Activity) mContext;
                connectionResult.startResolutionForResult(activity, CONNECTION_FAILURE_RESOLUTION_REQUEST);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Log.i("", "Location services connection failed with code " + connectionResult.getErrorCode());
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.w("==>UpdateLocation<==", "" + String.format("%.6f", location.getLatitude()) + "," + String.format("%.6f", location.getLongitude()));
        locationData = location;

    }

    @Override
    public void onDestroy() {

        if (handlerSendLocation != null)
            handlerSendLocation.removeCallbacks(runnableSendLocation);


        Log.w("Service Update Info", "BGS > Stopped");

        stopSelf();
        super.onDestroy();
    }


}

AndroidManifest.XML

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<service
            android:name=".ServiceLocation"
            android:enabled="true"
            android:exported="true" />
0

I found why the app is removing from the background. That was not my code's problem. It happened because the phone I used was Redmi. In Redmi phones, It requires additional permission (AutoStart permission) from Redmi phone settings. You can get more info about this from Foreground service getting killed from Oreo

JITHIN GOPAL
  • 131
  • 1
  • 14