Android problems with fused location provider - android

I develop an application which needs to be location aware. I tried to use the new google api client but i have some problems.
1.When i ask for location I ask for PRIORITY_HIGH_ACCURACY but i want the user to have the choise to save his battery by using only the mobile networks. When I check Battery saving mode (or disable GPS on old devices) everything works fine. But when I tested the app on a phone with lollipop, even if I close all location providers, the battery is killed. (I also noticed that and by the time the battery is drained, no location update received).
2.I tested to some devices and tried to get location with mobile networks. That worked fine when the device was close to a wifi (but not connected). But in a specific device (sony xperia M2) it is needed to connect to wifi to update location. Is there anything i can do? Is problem of the device or the version of google play services?
My code is here. I fire periodically a pending intent to run the service to be sure that location listener is still listening (i had some problems in the past where location listener disconnected)
public class UpdateLocService extends Service implements GoogleApiClient.ConnectionCallbacks, LocationListener {
public static final String SENDER_ID = "66801";
public static final String devIdToServer = "send dev id to server";
private static LocationListener listener = null;
//private LocationClient locationClient;
private GoogleApiClient mGoogleApiClient;
private static Location lastLocation = null;;
private LocationRequest mLocationRequest;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
#Deprecated
public void onStart(Intent intent, int startId) {
Log.d("UpdateLocService", "dienem service ");
locApi();
}
private void locApi() {
if(mGoogleApiClient != null && (mGoogleApiClient.isConnected() || mGoogleApiClient.isConnecting())){
dLog.d("loc.txt","tryed to connect but already connected or trying now");
dLog.d("flow.txt","tryed to connect but already connected or trying now");
}else{
dLog.d("loc.txt","new connection attempt");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
//.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
}
#Override
public void onConnected(Bundle bundle) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(1000 * 60);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
}
public static Location getLocation(){
return lastLocation;
}
#Override
public void onLocationChanged(Location location) {
dLog.d("loc.txt",location.toString());
lastLocation = location;
}
}

Related

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.

Fused Location Api setSmallestDisplacement ignored/not working

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
}

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.

Making a Service out of Basic Location Sample code

I want to make a service (background operation) in Android to track the location of a device every now and then and store it on SharedPreference or send it to my server when location changes. I came accross this code from Get current location name of user without using gps or internet but by using Network_Provider in android and Android Developers - Getting the Last Known Location.
This is the code:
public class MainActivity extends AppCompatActivity implements
ConnectionCallbacks, OnConnectionFailedListener {
protected static final String TAG = "MainActivity";
/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mGoogleApiClient;
/**
* Represents a geographical location.
*/
protected Location mLastLocation;
protected String mLatitudeLabel;
protected String mLongitudeLabel;
protected TextView mLatitudeText;
protected TextView mLongitudeText;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
mLatitudeLabel = getResources().getString(R.string.latitude_label);
mLongitudeLabel = getResources().getString(R.string.longitude_label);
mLatitudeText = (TextView) findViewById((R.id.latitude_text));
mLongitudeText = (TextView) findViewById((R.id.longitude_text));
buildGoogleApiClient();
}
/**
* Builds a GoogleApiClient. Uses the addApi() method to request the LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
// Provides a simple way of getting a device's location and is well suited for
// applications that do not require a fine-grained location and that do not need location
// updates. Gets the best and most recent location currently available, which may be null
// in rare cases when a location is not available.
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
Log.e("Location", "not null");
makeUseOfNewLocation(mLastLocation);
} else {
Toast.makeText(this, R.string.no_location_detected, Toast.LENGTH_LONG).show();
// should request new one
// location should be enabled
Log.i(TAG,
"No location data previously acquired.. should request!");
Toast.makeText(this,
"Requesting location data ..",
Toast.LENGTH_SHORT).show();
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(5000);
PendingResult<Status> result = LocationServices.FusedLocationApi
.requestLocationUpdates(mGoogleApiClient,
locationRequest,
new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Log.e("Location", "not null");
makeUseOfNewLocation(location);
}
});
// TODO: use result to retrieve more info
Toast.makeText(this, result.toString(),Toast.LENGTH_LONG);
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
private void makeUseOfNewLocation(Location location) {
// do your stuff here
mLatitudeText.setText(String.format("%s: %f", mLatitudeLabel,
location.getLatitude()));
mLongitudeText.setText(String.format("%s: %f", mLongitudeLabel,
location.getLongitude()));
}
}
My question is can this code be a Service by just extending Service on this class. Will this work and be able to track the device's location every now and then on the background
As per Google's documentation, you will need to use a PendingIntent in onConnected to make sure you have a background service running even when the app is off the screen.
https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi
public abstract PendingResult requestLocationUpdates (GoogleApiClient client, LocationRequest request, PendingIntent callbackIntent)
Requests location updates with a callback on the specified PendingIntent.
This method is suited for the background use cases, more specifically for receiving location updates, even when the app has been killed by the system. In order to do so, use a PendingIntent for a started service. For foreground use cases, the LocationListener version of the method is recommended, see requestLocationUpdates(GoogleApiClient, LocationRequest, LocationListener).
My previous method is create an intent which is included in your pendingIntent, then indicates in the intent to pass from your current activity to a Handler class. In the handler class which extends the IntentService, you will be able to get whatever location information in the onHandle method.
You can take a look at one of my previous questions for reference:
FusedLocationProvider using intentservice for background location update: location update does not work when pendingintent has a bundle added

Categories

Resources