I am working on geo-loaction applciation where I need to calculate user speed, to get user speed I used LocationManager for their current location after every 30second, for this I used following code.
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000*30, 0, myLocationListener); //from NETWORK_PROVIDER
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000*30, 0, myLocationListener); //from GPS_PROVIDER
But my problem is I want location based on fix time interval here is 30second. Right now I get location after every 45second also vary. So if any know how I can set 'maxTime' to location manager then please let me know.
Also if any one know the location listener calling business logic based on time / distance also please let me know.
Thanks in advanced.
Use the new introduced Fused Location Provider API
import android.app.IntentService;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
public class Locations extends IntentService implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {
public Locations() {
super("Locations");
Log.d("Locations", "Location service started... ");
}
private LocationRequest locationRequest;
private LocationClient locationClient;
private Location location;
private static final int INTERVAL = 1800000;
private static final int FASTEST_INTERVAL = 60000;
#Override
protected void onHandleIntent(Intent intent) {
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(INTERVAL);
locationRequest.setFastestInterval(FASTEST_INTERVAL);
locationClient = new LocationClient(this, this, this);
locationClient.connect();
}
#Override
public void onLocationChanged(Location l) {
// do something on Location change.
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
}
#Override
public void onConnected(Bundle arg0) {
Log.w("Locations", "Location client connected...");
// get last location
location = locationClient.getLastLocation();
Log.w("Locations", "Latitude : "+location.getLatitude() + "");
Log.w("Locations", "Longitude : "+location.getLongitude() + "");
}
#Override
public void onDestroy() {
if (locationClient.isConnected()) {
locationClient.removeLocationUpdates(this);
}
locationClient.disconnect();
}
#Override
public void onDisconnected() {
}
}
Source https://developer.android.com/training/location/index.html
Related
I created a service for getting user Location which I am calling from my main thread. Now, this service is getting my location not just from gps, but also from network. Why is it getting user Location on some phones and on some phones it doesnt?
Here is my service class:
import android.app.Service;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import java.util.List;
public class LocationService extends Service implements LocationListener {
protected LocationManager locationManager;
public String providerNow;
private List<String> providers;
public Location location;
public LocationService() {
}
#Override
public void onCreate() {
super.onCreate();
locationManager = (LocationManager) this.getSystemService(LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, this);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 0, this);
providerNow = (GetProvider());
}
public Location getLocation() {
location = locationManager.getLastKnownLocation(providerNow);
return location;
}
public String GetProvider() {
Criteria criteria = new Criteria();
criteria.setAccuracy(2);
providers = locationManager.getProviders(true);
String providerToSend = providers.get(1);
return providerToSend;
}
public IBinder onBind(Intent intent) {
Log.i("TestMap", "onBind");
//TODO for communication return IBinder implementation
return null;
}
public void onLocationChanged(Location location) {
Static.location = location;
if (location != null) {
Log.d("Lat", String.valueOf(location.getLatitude()));
Log.d("Lon", String.valueOf(location.getLongitude()));
Static.latitude = location.getLatitude();
Static.longitude = location.getLongitude();
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
providerNow = (GetProvider());
}
#Override
public void onProviderDisabled(String provider) {
providerNow = (GetProvider());
}
}
Here is the code from main thread where I am calling this service:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
Intent serviceIntent = new Intent(this, LocationService.class);
startService(serviceIntent);
proveraInterneta();
getSizeOfTheScreen();
}
Here are the two suggestions for the issue you are facing:
As per coding, make use of the Google's Fused Location API. FusedLocationProviderApi can be accessed via LocationServices as below,
private FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
FusedLocationProviderApi requires the GoogleApiClient instance to get the Location and it can be obtained as below.
googleApiClient = new GoogleApiClient.Builder(locationActivity)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
Secondly, from device perspective make sure that the GPS is turned on all the devices under test.
Last but not the least, check if this permission is added in the manifest.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Take a look at this tutorial for more reference.
As i understand your code, when you call getLocation method then obtain latest location from currently working provider (or latest enabled provider). When you enable a provider, it's not guaranteed getting location from getLocation method.
if i call getLastKnownLocation("gps") right after making enabled gps provider, it so normal getting null result. Because gps provider must fire onLocationChanged method at least one time, so i have to wait for gps fix. Also this scenario is same for network provider too.
Calling getLastKnownLocation("a provider") method without being sure about the provider is fixed, will give you unreliable(old location) or null result. In this case, if some phones doesn't give null, it means these devices have cached location for current provider or they are lucky because the provider is warmed up already
My app is currently using Maps by Google Play Services
speficying:
mMap.setMyLocationEnabled(true);
I realize each time I am displaying the map in my app:
the location is indicated on the map by a blue dot
a location icon is displaying in the top bar
if I go into Settings/Location of the phone, my app is reported as "High battery use"
However, I can see there are apps that use Maps and still show the location blue dot, but the location icon doesn't appear in top bar and their battery usage is low.
My app currently grants both permissions:
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
My question is:
how can I show the location blue dot with low battery usage?
is it possible to specify the accuracy/battery usage by code?
UPDATE
Actually I realized that the way to do it is to use the GoogleApiClient's FusedLocationApi
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
I have configured the GoogleApiClient inside my Activity, calling:
GoogleApiClient.connect() on the Activity's start
GoogleApiClient.disconnect() on the Activity's stop
on the onConnected callback I set the criteria for the location updates: fastest interval of 1 minute with low power priority:
private static final LocationRequest REQUEST = LocationRequest.create()
.setFastestInterval(60000) // in milliseconds
.setInterval(180000) // in milliseconds
.setPriority(LocationRequest.PRIORITY_LOW_POWER);
#Override
public void onConnected(Bundle bundle) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient,
REQUEST,
this); // LocationListener
}
I have tested that the GoogleApiClient connects correctly at start, but for some reasons whenever I visit the fragment with the embedded MapView, I still get the high battery use for my app on the Settings/Location screen!
It seems the MapView is ignoring these low power criterias!
FINALLY FOUND THE SOLUTION!!!
thanks to Tristan for his answer!
By default, GoogleMap uses its on location provider, which is not the Fused Location Provider. In order to use the Fused Location Provider (which allows you to control the location accuracy and power consumption) you need to explicitely set the map location source with GoogleMap.setLocationSource() (documentation)
I am reporting here a sample activity to do that:
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends FragmentActivity
implements
ConnectionCallbacks,
OnConnectionFailedListener,
LocationSource,
LocationListener,
OnMyLocationButtonClickListener,
OnMapReadyCallback {
private GoogleApiClient mGoogleApiClient;
private TextView mMessageView;
private OnLocationChangedListener mMapLocationListener = null;
// location accuracy settings
private static final LocationRequest REQUEST = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMessageView = (TextView) findViewById(R.id.message_text);
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
protected void onResume() {
super.onResume();
mGoogleApiClient.connect();
}
#Override
public void onPause() {
super.onPause();
mGoogleApiClient.disconnect();
}
#Override
public void onMapReady(GoogleMap map) {
map.setLocationSource(this);
map.setMyLocationEnabled(true);
map.setOnMyLocationButtonClickListener(this);
}
public void showMyLocation(View view) {
if (mGoogleApiClient.isConnected()) {
String msg = "Location = "
+ LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
}
/**
* Implementation of {#link LocationListener}.
*/
#Override
public void onLocationChanged(Location location) {
mMessageView.setText("Location = " + location);
if (mMapLocationListener != null) {
mMapLocationListener.onLocationChanged(location);
}
}
#Override
public void onConnected(Bundle connectionHint) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient,
REQUEST,
this); // LocationListener
}
#Override
public void onConnectionSuspended(int cause) {
// Do nothing
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Do nothing
}
#Override
public boolean onMyLocationButtonClick() {
Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT).show();
// Return false so that we don't consume the event and the default behavior still occurs
// (the camera animates to the user's current position).
return false;
}
#Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mMapLocationListener = onLocationChangedListener;
}
#Override
public void deactivate() {
mMapLocationListener = null;
}
}
You will want to make your activity (or better a separate object for this purpose) implement the LocationSource interface.
It is pretty simple you need to store the listener passed in the activate() method and call it when the location is updated and forget it when deactivate() is called. See this answer for an example, you will probably want to update it to use the FusedLocationProvider.
Once you have this set up you can pass your activity as the LocationSource for the map like so mMap.setLocationSource(this) (documentation).
This will stop the map from using its default LocationSource which uses the high battery use location services.
It's stated here that
FusedLocationProviderApi provides improved location finding and power usage and is used by the "My Location" blue dot.
So "My Location" dot on map is fed by FusedLocationProviderApi. And as you grant permission android.permission.ACCESS_FINE_LOCATION you allow FusedLocationProviderApi for your app to get data from GPS which may cause high battery use.
So add only android.permission.ACCESS_COARSE_LOCATION permission to manifest and Android should not blame you for battery usage.
You can do so by using Network provider classes
You can use below code
AppLocationService.java // Special for getting current location with low battery usage (same like Battery saver mode in nexus 5 ,5.0)
package coreclass;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
public class AppLocationService extends Service implements LocationListener {
protected LocationManager locationManager;
Location location;
private static final long MIN_DISTANCE_FOR_UPDATE = 10;
private static final long MIN_TIME_FOR_UPDATE = 1000 * 60 * 2;
public AppLocationService(Context context) {
locationManager = (LocationManager) context
.getSystemService(LOCATION_SERVICE);
}
public Location getLocation(String provider) {
if (locationManager.isProviderEnabled(provider)) {
locationManager.requestLocationUpdates(provider,
MIN_TIME_FOR_UPDATE, MIN_DISTANCE_FOR_UPDATE, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(provider);
return location;
}
}
return null;
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
}
Usage of above class
MainActivity.java
AppLocationService appLocationService;
appLocationService = new AppLocationService(getActivity());
Location nwLocation = appLocationService.getLocation(LocationManager.NETWORK_PROVIDER);
if (nwLocation != null) {
Lat = nwLocation.getLatitude();
Longi = nwLocation.getLongitude();
}
In this way you can get the current location with GPS mode in high bettery usage mode, after you can set the blue dot or whatever you want
Hope it helps you and all
my android application can detect longitude and latitude. but it take some time. my app has 9 activates and last activity should send location to data base. any one can give a solution for this. i want to detect location soon as possible, what did missed in my code?
package com.example.zlocation;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity implements LocationListener{
protected LocationManager locationManager;
protected LocationListener locationListener;
protected Context context;
protected TextView txtLat;
String lat;
String provider;
protected String latitude,longitude;
protected boolean gps_enabled,network_enabled;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtLat = (TextView) findViewById(R.id.textView1);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
#Override
public void onLocationChanged(Location location) {
txtLat = (TextView) findViewById(R.id.textView1);
txtLat.setText("Latitude:" + location.getLatitude() + ", Longitude:" + location.getLongitude());
}
#Override
public void onProviderDisabled(String provider) {
Log.d("Latitude","disable");
}
#Override
public void onProviderEnabled(String provider) {
Log.d("Latitude","enable");
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.d("Latitude","status");
}
}
You are trying to get the location from gps provider.The problem with gps is however vit is accurate but it takes time in starting the gps and providing a location it can take anything from 2-30 seconds to provide the location if you want location as soon as possible have a look at fused location provider by google and implement it in that you can define the time after you want the location updates or from my personal experience i would suggest you to have a look at littlefluffy location library it is easier to implement.
So, I have an Android application that is asking for the GPS from the LocationManager class.
I have an Activity that wants to use that data, and a custom class that implements LocationListener.
I have written some custom methods to return the GPS values to my other class.
Currently, I am asking for and releasing the location updates from my Activity class, not my implementation of the LocationListener class... I think this is the right way to go about it, but I just wanted to get any feedback on the life cycle, etc. (the class that implements LocationListener is not an Activity, so I don't think I even could call onPause() etc, ?)
This is the Activity:
package com.jessescott.sonicity;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationListener;
public class PlayActivity extends Activity {
// GLOBALS
private static final String TAG = "SoniCity";
LocationManager locationManager;
MyLocationListener locationListener;
TextView latitude, longitude;
TextView ActualLatitude, ActualLongitude;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.play_layout);
// GPS
locationListener = new MyLocationListener(this);
// TextViews
latitude = (TextView) findViewById(R.id.Latitude);
longitude = (TextView) findViewById(R.id.Longitude);
ActualLatitude = (TextView) findViewById(R.id.ActualLat);
ActualLatitude.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.v(TAG, "Asking For New Latitude");
ActualLatitude.setText(locationListener.getCurrentLatitude());
}
});
ActualLongitude = (TextView) findViewById(R.id.ActualLon);
ActualLongitude.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.v(TAG, "Asking For New Latitude");
ActualLongitude.setText(locationListener.getCurrentLongitude());
}
});
}
#Override
protected void onPause() {
super.onPause();
// Stop GPS
locationManager.removeUpdates(locationListener);
locationManager = null;
}
#Override
protected void onResume() {
super.onResume();
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 5, locationListener);
}
#Override
public void onDestroy() {
super.onDestroy();
}
} /* */
... and this is the LocationListener implementation :
package com.jessescott.sonicity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.util.Log;
class MyLocationListener implements LocationListener {
private static final String TAG = "SoniCity";
float currentLatitude = 0;
float currentLongitude = 0;
public MyLocationListener(Context context) {
super();
}
// Define all LocationListener methods
public void onLocationChanged(Location location) {
currentLatitude = (float)location.getLatitude();
currentLongitude = (float)location.getLongitude();
}
public void onProviderDisabled (String provider) {
Log.v(TAG, "Provider is " + provider);
}
public void onProviderEnabled (String provider) {
Log.v(TAG, "Provider is " + provider);
}
public void onStatusChanged (String provider, int status, Bundle extras) {
Log.v(TAG, "Status is " + status);
}
// Custom Methods
public String getCurrentLatitude() {
String lat = Float.toString(currentLatitude);
return lat;
}
public String getCurrentLongitude() {
String lon = Float.toString(currentLongitude);
return lon;
}
} /* */
I guess since I've moved it to a separate class (they used to be the same one), I just want to make sure I'm calling th request/remove in the right place.
I haven't looked at your code in detail, but from what I've seen it looks fine to me. onResume() is the right place to register your listener, and onPause() is the right place to unregister it, so that e.g. battery life is optimised.
A couple of things to consider going forward:For a robust app, make sure you pay attention to the information that you get from onStatusChanged, onProviderEnabled and onProviderDisabled. I've seen various questions on stackoverflow.com to which the answer was to pay attention to status changes etc.Also for a better estimate of location, you might consider using the Location.accuracy value, because the accuracy of GPS location estimates can change. One minute they might be very accurate, but then the visible satellites change and the accuracy can suddenly be much lower. In my apps I use a simple Kalman filter for this, and I posted the code for it in my answer to the question Smooth GPS data.
So i am using the getLastKnownLocation method to get the Location loc of the device but it returns null unless there is a GPS fix. Is there a way to delay execution of getLastKnownLocation until the GPS has a valid location to provide?
package test.example;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
public class testGPS extends Activity
{
private LocationManager lm;
private LocationListener locationListener;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
//---use the LocationManager class to obtain GPS locations---
lm = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
locationListener = new MyLocationListener();
lm.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
0,
0,
locationListener);
Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (loc != null) {
tv.setText("Hello, lat is " + loc.getLatitude() + " lon is " + loc.getLongitude());
setContentView(tv);
} else {
tv.setText("Hello, loc is null :(");
setContentView(tv);
}
}
private class MyLocationListener implements LocationListener
{
#Override
public void onLocationChanged(Location loc) {
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status,
Bundle extras) {
// TODO Auto-generated method stub
}
}
}
You're misunderstanding how location works in Android. getLastKnownLocation() doesn't provide null unless the GPS has a fix, it returns null if there's no previous known location - the location does not have to come from the GPS (it could come via wifi or mobile network) and calling that method does not instruct the location framework to return a new location.
You need to start again, after fully reading and understanding this page:
http://developer.android.com/guide/topics/location/obtaining-user-location.html
It includes everything you need to handle locations in Android, and you need a framework that suits the needs of your application. If you want the location to persist (to reduce the use of the GPS) then you can save the location to preferences, and/or enable network location sending (not as accurate, but usually faster). For some apps you may want to grab a rough location quickly (using last-known, or the network location provider) and then update it when an accurate GPS location arrives. But the approach you use will vary by app.