0

following service is created to continuously update user location. User's location has to be tracked even app is in background, device is idle or screen is off or application is removed/killed from recent list.

But somehow this code doesn't work. Location update stopped after some time automatically and on some devices it doesn;t even work I can't understand why, and I have turned everything from blue to purple.

gradle : 2.3.3 Play service and Map verion : 11.0.4 compile sdk version : 25

## but I am running this app on Android 6.0.1 Marshmallow

Please help me out of this. Thanks in advance.

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

private static final long INTERVAL = 10000;
private static final long FASTEST_INTERVAL = 10000;
private static final long FUSED_DISTANCE = 5;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mCurrentLocation;
String mLastUpdateTime;
Location mLastLocation;

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

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

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
    if (mGoogleApiClient == null) {
        buildApiClient();
    }
    if (!isGooglePlayServicesAvailable()) {
        stopSelf();
    }
    createLocationRequest();
    return START_STICKY;
}

public void buildApiClient() {
    if (mGoogleApiClient == null) {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }
}

private boolean isGooglePlayServicesAvailable() {
    int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    if (ConnectionResult.SUCCESS == status) {
      return true;
    } else {
      return false;
    }
}

protected void createLocationRequest() {
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(INTERVAL);
    mLocationRequest.setSmallestDisplacement(FUSED_DISTANCE);
    mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
    mLocationRequest.setSmallestDisplacement(FUSED_DISTANCE);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    startLocationUpdates();
}

protected void startLocationUpdates() {
    if (ActivityCompat.checkSelfPermission(this,         Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
    }

    LocationServices.FusedLocationApi.requestLocationUpdates(
            mGoogleApiClient, mLocationRequest, this);
}

protected void stopLocationUpdates() {
    if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.removeLocationUpdates(
                mGoogleApiClient, this);
    }
}

@Override
public void onConnected(Bundle bundle) {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
    }
    mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    if (mLastLocation != null) {
        updateUI();
    }
    if (mGoogleApiClient.isConnected()) {
        if (mLocationRequest != null) {
            startLocationUpdates();
        } else {
            createLocationRequest();
        }
    }
}
@Override
public void onConnectionSuspended(int i) {

}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    updateUI();
}
@Override
public void onLocationChanged(Location location) {
    mCurrentLocation = location;
    mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
    updateUI();
}

public static float distFrom(double lat1, double lng1, double lat2, double lng2) {
    double earthRadius = 6371000; //meters
    double dLat = Math.toRadians(lat2 - lat1);
    double dLng = Math.toRadians(lng2 - lng1);
    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
            Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                    Math.sin(dLng / 2) * Math.sin(dLng / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    float dist = (float) (earthRadius * c);

    return dist;
}


private void updateUI() {
       if (mCurrentLocation != null) {
//calculate distance between current and last location           

        double dLon = (Double.parseDouble(mLastLocation.getLongitude) - mCurrentLocation.getLongitude());
        double y = Math.sin(dLon) * Math.cos(Double.parseDouble(mLastLocation.getLatitude));
        double x = Math.cos(mCurrentLocation.getLatitude()) * Math.sin(Double.parseDouble(mLastLocation.getLatitude)) - Math.sin(mCurrentLocation.getLatitude()) * Math.cos(Double.parseDouble(mLastLocation.getLatitude)) * Math.cos(dLon);
        double brng = Math.toDegrees((Math.atan2(y, x)));
        brng = (360 - ((brng + 360) % 360));

         double earthRadius = 6371000; //meters
    double dLat = Math.toRadians(mCurrentLocation.getLatitude() - mLastLocation.getLatitude());
    double dLng = Math.toRadians(mCurrentLocation.getLongitude() - mLastLocation.getLongitude());
    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
            Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                    Math.sin(dLng / 2) * Math.sin(dLng / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    float distance = (float) (earthRadius * c);



        if (distance >= CV.LOCATION_DISTANCE) {
                        Tblname.Insert(mCurrentLocation);
        } 
    }

}

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopLocationUpdates();
    }
 }
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
jil123
  • 99
  • 1
  • 12
  • Regular Services can be destroyed by the system to save energy, or free up resources. You probably need to run it as a foreground service. – Lukasz Oct 25 '17 at 10:51
  • @Lukasz I don't want a foreground service I need a background serivce – jil123 Oct 25 '17 at 10:56
  • 1
    Why? What are you using those locations for? I'm afraid Android is putting more and more restrictions onto what you can do in the background [link](https://developer.android.com/about/versions/oreo/background-location-limits.html), so you'r probably fighting a loosing battle. – Lukasz Oct 25 '17 at 11:17
  • I am tracking user's location with their awareness. I just need a way to restart service automatically even if it gets stopped – jil123 Oct 25 '17 at 12:10

1 Answers1

0

You can not achieve this for devices running Android Oreo. But for others you can achieve this by setting

 <service
            android:name=".YourLocationService"
            android:exported="false"
            android:process=":YourLocationService"
            android:stopWithTask="false" />

in your manifest file. The stopWithTask="false" is the key here.

and

@Override
    public void onTaskRemoved(Intent rootIntent) {

        Intent restartService = new Intent(getApplicationContext(), this.getClass());
        PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartService, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.ELAPSED_REALTIME, 5000, pendingIntent);


    }
lakshman.pasala
  • 565
  • 6
  • 16