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.
Related
I am trying to get continuous location updates by running a background service. While I debug the code onConnected(Bundle b) is called and location update request is called. But onLocationChanged(Location location) is never called. Below is my code:
public class LocationUpdateService extends Service implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleApiClient googleApiClient;
private LocationRequest mLocationRequest;
Location mCurrentLocation;
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
double lat = mCurrentLocation.getLatitude();
double lng = mCurrentLocation.getLongitude();
}
//GoogleApiClient
#Override
public void onConnectionFailed(ConnectionResult bundle) {
}
#Override
public void onConnected(Bundle bundle) {
Log.i("onConnected", "GoogleApiClient");
Toast.makeText(this, "Location service connected", Toast.LENGTH_SHORT).show();
createLocationRequest();
startLocationUpdate();
}
#Override
public void onConnectionSuspended(int i) {
}
//Service
#Override
public void onCreate() {
super.onCreate();
buildGoogleApiClient();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY; // run until explicitly stopped.
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void startLocationUpdate() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, mLocationRequest, this);
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
}
void buildGoogleApiClient() {
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
googleApiClient.connect();
}
void createLocationRequest() {
mLocationRequest = new LocationRequest().create()
.setInterval(5000)
.setFastestInterval(5000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
}
I can't understand where I am making mistake, while I have followed android docs. I am testing on real device and app has location permissions.
service in menifest:
<service
android:name=".locations.LocationUpdateService"
android:enabled="true"
android:exported="false"></service>
Call of service in activity:
startService(new Intent(BaseActivity.this, LocationUpdateService.class));
What is your android phone SDK and how are you asking for the permissions on the manifest file?
If your phone SDK is 23 or higher the way you ask for permissions is different.
It was just a stupid debugging issue. I found my device location Access was off in advance settings.
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().
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
}
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
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.