Fused Location Api setSmallestDisplacement ignored/not working - android

I am trying to create a service that will receive location updates every x sec and after y distance. I receive updates after x sec but never after y distance. I have tested it multiple times with different values and it seems that setSmallestDisplacement is not working at all. There have been various posts about that matter but without any solution. I would appreciate it if someone could help me or even point me to a different direction.
My Service
public class GPS_Service extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private int timethresh;
private int distancethresh;
protected Location mCurrentLocation;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
//Set the desired interval for active location updates, in milliseconds.
mLocationRequest.setInterval(60* 1000);
//Explicitly set the fastest interval for location updates, in milliseconds.
mLocationRequest.setFastestInterval(30* 1000);
//Set the minimum displacement between location updates in meters
mLocationRequest.setSmallestDisplacement(1); // float
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onConnected(Bundle bundle) {
if (mCurrentLocation == null) {
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
}
//Requests location updates from the FusedLocationApi.
startLocationUpdates();
}
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
//Toast.makeText(this, ""+mCurrentLocation.getLatitude()+","+mCurrentLocation.getLongitude(), Toast.LENGTH_SHORT).show();
System.out.println(""+mCurrentLocation.getLatitude()+","+mCurrentLocation.getLongitude());
}
#Override
public void onConnectionSuspended(int i) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Toast.makeText(getApplicationContext(),"Location services connection failed with code " + connectionResult.getErrorCode(), Toast.LENGTH_LONG).show();
}
protected void startLocationUpdates() {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
}

According to this SO question especially the answer of cgr.
The Displacement that is set for LocationRequest, has no chance of getting the locations if device is still as Displacement takes precedance over Intevals (interval and fastestInterval). As I could guess - Maybe you have passed different LocationRequest object (with no displacement set) to LocationServices.FusedLocationApi.requestLocationUpdates().
The LocationRequest setSmallestDisplacement (float
smallestDisplacementMeters)
is set the minimum displacement between location update in meters. By default the value of this is 0. It returns the same object, so that the setters can be chained.
NOTE: Location requests from applications with ACCESS_COARSE_LOCATION
and not ACCESS_FINE_LOCATION will be automatically throttled to a
slower interval, and the location object will be obfuscated to only
show a coarse level of accuracy.
Check this page for more information.

Try something like this:
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(100); //100 meters
}

Related

Stop location updates if the device has not moved and if it moves a distance of 300m then get it's location

i am making an android application. I want to stop location updates if the device is still and if it moves a distance of 300 or 400m then get it's location again. I don't want to check continuously for location updates and measure distance between previous location and current location because it consumes battery.
My Location service class code:
public class LocationService extends Service implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
public void buildGoogleApiClient() {
createLocationRequest();
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(500);
}
public void startLocationUpdates() {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.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() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
buildGoogleApiClient();
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
// The service is no longer used and is being destroyed
stopLocationUpdates();
}
#Override
public void onLocationChanged(Location location) {
System.out.println("Latitude: " + location.getLatitude());
System.out.println("Longitude: " + location.getLongitude());
}
#Override
public void onConnected(#Nullable Bundle bundle) {
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
I am using locationRequest.setSmallestDisplacement(500) but it continuously receives location updates only the onLocationChanged method is not called if the distance between previous and current location is less than 500m e.g.
Should i use geofencing for this purpose?
What is the best possible way to achieve this using FusedLocationApi with minimum battery consumption?
There are a few things to note here:
When your device isn't moving, Location Services optimizes for battery and does not necessarily do expensive new location lookups. So, you don't really have to try to optimize for this yourself.
Consider passing a smaller value to LocationRequest#setSmallestDisplacement.
To optimize for battery, consider using batched location updates, where location is computed for you in at the interval described in LocationRequest#setInterval, but delivered to your device based on the value in LocationRequest#setMaxWaitTime. This greatly helps with battery.
Not part of your question, but I should note that I would structure the code for requesting and removing location updates a little differently. I would connect GoogleApiClient in onStart(), and disconnect it in onStop(). I would call requestLocationUpdates() in onResume() of in onConnected(), and call removeLocationUpdates() in onPause() or onStop(), but not as late as onDestroy().

Service getting null as location

So, I have a JobService that is being called on background. However I need it to get the current location and send it to the webservice. The webservice is working great when I send static data. However getting the location is being a problem. The location object is always null. This is what I've been trying.
public class GPSBackgroundJobService extends JobService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private String LOGSERVICE = "GPS";
private InspectorsLogic mInspectorsLogic;
ParsoContext mContext;
private GoogleApiClient mGoogleApiClient;
ParsoLocationListener mLocationListener;
Location mLastLocation;
Double longitude;
Double latitude;
#Override
public void onCreate() {
super.onCreate();
Log.i(LOGSERVICE, "onCreate");
mContext = (ParsoContext) getApplicationContext();
mInspectorsLogic = new InspectorsLogic(mContext);
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
#Override
public boolean onStartJob(JobParameters job) {
Log.i(LOGSERVICE, "onStartJob called");
mGoogleApiClient.connect();
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocation!=null) {
latitude = mLastLocation.getLatitude();
longitude =mLastLocation.getLongitude();
sendGPSTask mSendGPSTask = new sendGPSTask();
mSendGPSTask.execute(Double.toString(latitude), Double.toString(longitude));
}else{
Log.e(LOGSERVICE, "Lat and Long are null");
}
return false;
}
#Override
public boolean onStopJob(JobParameters job) {
mGoogleApiClient.disconnect();
return false;
}
#Override
public void onConnected(Bundle connectionHint) {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
getLastLocation returns null if it doesn't have a location fix yet- which means unless you're using GPS elsewhere, it almost always returns null. To make sure you get a location use getLocationUpdates and wait for the location to fix (this will not be instant, depending on atmospheric conditions, whether you're inside or out, etc this could take a few seconds to a minute or so- or just never happen).
Apparently the code is fine, to make it work this is what I did:
check the permissions of the app (the location one needs to be activated)
change your GPS settings to (mobile data and wifi one)
making this with the current code posted on the question, made it.

Cannot Access Network based location when location access is off

I am using google location api for fetching location. issue I'm facing is when the user turned the GPS off I'm not getting the Lcoation, as per this post says we can access Network based location even-though the GPS is turned off. but I'm not getting locaton when the user turned off the location access.
this is my service to fetch location
public class LocationUpdateService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<Status> {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startLocationUpdates();
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
LogUtils.LOGI(TAG, "Service created");
buildGoogleApiClient();
setupBroadCastListenerForGpsStatusChange();
initLastLocationDetails();
}
/**
* Requests location updates from the FusedLocationApi.
*/
protected void startLocationUpdates() {
if (!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
} else {
mRequestingLocationUpdates = true;
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
}
/**
* Builds a GoogleApiClient. Uses the {#code #addApi} method to request the
* LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
LogUtils.LOGI(TAG, "Building GoogleApiClient");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.addApi(ActivityRecognition.API)
.build();
createLocationRequest();
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setSmallestDisplacement(SMALLEST_DISTANCE_METERS);
}
#Override
public void onConnected(Bundle connectionHint) {
startLocationUpdates();
}
#Override
public void onLocationChanged(Location location) {
//location operations
}
}
So my question is, Is it really possible to access location when the location access is disabled (not last cached location), if yes, what is wrong with my code
if (isNetworkEnabled) {
manager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_BTWN_UPDATES,
DISTANCE_OF_UPDAPTES, this);
if (manager != null) {
location = manager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
You canot start the service natively using just Google Api Location , you should manage to operate the location based on user request by using boolean location manager. Otherwise your attempts dose not look superficial, you can either use get when gps is on or off depending when detected.

Android Location service didn't work in background

I am working on a Location-App which should begin to track some statistic data based on longitude and latitude when the user presses a Button. All this stuff works very well but when it comes to lock the screen or put the app in the background the service does not work anymore !
I have read a lot about background services and Broadcast receivers but I don't know how to implement the Google API Location listener in a Service and where to implement this class in the MainActivity. Can anyone tell me with a short code example how to implement such a service or a link where this is explained ?
Use fuse location service and save updated location every time
public class LocationNotifyService extends Service implements
LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
public static Location mCurrentLocation;
.............................
#Override
public void onCreate() {
//show error dialog if GoolglePlayServices not available
if (isGooglePlayServicesAvailable()) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(BACKGROUND_INTERVAL);
mLocationRequest.setFastestInterval(BACKGROUND_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
//mLocationRequest.setSmallestDisplacement(10.0f); /* min dist for location change, here it is 10 meter */
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
//Check Google play is available or not
private boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
return ConnectionResult.SUCCESS == status;
}
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
}
protected void startLocationUpdates() {
try {
PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
} catch (IllegalStateException e) {}
}
#Override
public void onLocationChanged(Location location) {
//Save your location
}
............................
}
you can get current location onLocationChanged()
For more details check http://javapapers.com/android/android-location-fused-provider/ or follow official guide https://developer.android.com/training/location/index.html
Here is application that does something like you want:
https://github.com/sergstetsuk/CosyDVR/blob/master/src/es/esy/CosyDVR/CosyDVR.java
Main Activity starts on BackgroundVideoRecorder service.
Intent intent = new Intent(/*CosyDVR.this*/getApplicationContext(), BackgroundVideoRecorder.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
look at mConnection onServiceConnected,onServiceDisconnected.
Here is BackgroundVideoRecorder class:
https://github.com/sergstetsuk/CosyDVR/blob/master/src/es/esy/CosyDVR/BackgroundVideoRecorder.java
It implements LocationListener. So has onLocationChanged, onProviderDisabled, onProviderEnabled, onStatusChanged.

change interval of the LocationRequest depending on distance between current and some location

I want to save battery by changing the interval of updates using the Fused Location API. As far from some location, bigger should be the interval.
public class service extends Service implements GooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener {
private LocationRequest locationrequest;
private LocationClient locationclient;
#Override
public void onCreate() {
int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resp == ConnectionResult.SUCCESS) {
locationclient = new LocationClient(this, this, this);
locationclient.connect();
} else {
Toast.makeText(this, "Google Play Service Error " + resp, Toast.LENGTH_LONG).show();
}
}
#Override
public void onDestroy() {
super.onDestroy();
if(locationclient!=null)
locationclient.disconnect();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "onConnected");
if (locationclient != null && locationclient.isConnected()) {
locationrequest = LocationRequest.create();
locationrequest.setInterval(5000);
locationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationclient.requestLocationUpdates(locationrequest, this);
}
}
#Override
public void onDisconnected() {
Log.i(TAG, "onDisconnected");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "onConnectionFailed");
}
#Override
public void onLocationChanged(Location location) {
if(location!=null){
double Lat=-34.922611;
double Lng = 138.596161;
Location Loc = new Location("");
Loc.setLatitude(Lat);
Loc.setLongitude(Lng);
Float dist=location.distanceTo(Loc);
String distance = Float.toString(dist);
if (dist>100){
Log.i("distance",distance);
locationclient.removeLocationUpdates(this);
locationrequest.setInterval(30000);
locationrequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);
locationclient.requestLocationUpdates(locationrequest, this);
}
Log.i(TAG, "Location Request :" + location.getLatitude() + "," + location.getLongitude());
}
}
}
Unfortunately this is not working.. somebody knows why? or is there a better way to do that?
thanks
EDIT 1:
What I am getting as output is a locationrequest that behaves in the same way before the change. If I call locationrequest.getInterval , the new interval will be show but the locationrequest will give me updates with the first interval.
Using the Fused Location API you can do something like:
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
Then when an event is triggered in your app and you want to change the intervals, you would call the same piece of code but just change the INTERVAL and FASTEST_INTERVAL values.
After you change them do no forget to update the Location Updates like so:
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
Use removeLocationUpdates before changing the interval
with addOnCompleteListener to make sure you unregistered the previous request, and re-init the LocationRequest object:
LocationServices.FusedLocationApi.removeLocationUpdates(mLocationCallback).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
});
The problem is most likely that you have another process that requests locations, and that your app just listenes along. The setInterval means only what your app requires, not what it gets. So if another process has a faster interval you will get faster location updates.
Check for example if you have a GoogleMap with the MyLocation layer enabled. The map will request its own locations.
Finally, the LocationClient is deprecated. Check the documentation for FusedLocationApi to implement the correct current practice.

Categories

Resources