Android Fused Location API gives inaccurate Location in onLocationChanged - android

I am struggling a little here, I am using Fused API for getting location updates. My intention is to draw a path on Map when user walks.
I have implemented that as follows :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.map_layout, container, false);
// some other initialization
//....
//
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
return view;
}
then I start the stuff by following method
private void startReceivingLocationUpdates() {
if (checkGPSPermission() && mGoogleApiClient.isConnected() && !isReceivingLocationUpdates) {
LocationRequest locationRequest = new LocationRequest();
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(5000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
locationRequest, this);
isReceivingLocationUpdates = true;
}
}
& Here I receive the location update
#Override
public void onLocationChanged(Location location) {
if(getDistanceBetweenTwoLacation(mCoordinates.get(mCoordinates.size() - 1), location) > 3d) {
for(int i= 0; i < mCoordinates.size(); i++) {
Location locationTemp = mCoordinates.get(i);
Log.d(TAG, "i => " + i + " Lat => " + String.valueOf(locationTemp.getLatitude()) + " Lng => " + String.valueOf(locationTemp.getLongitude()));
}
if(mCoordinates.size() > 0)
Log.d(TAG, "lat difference is => " + getDistanceBetweenTwoLacation(mCoordinates.get(mCoordinates.size() - 1), location));
mCoordinates.add(location);
}
}
Now the problem is , onLocationChanged gives location with lat-lng whose difference/distance from past location is about 5-90 meters many times even if device is steady on same place. Am I missing something?
btw, here's the method which returns the distance from two lat-lngs which I used
private double getDistanceBetweenTwoLacation(Location origin, Location destination) {
return origin.distanceTo(destination);
}

Inaccurate (and moving/drifting/jumping) GPS fixes when indoors is pretty common. Without a clear view of the sky, an accurate GPS fix is impossible. In your Location object, there is a getAccuracy() method which returns a float. This value is the accuracy of the position fix in meters, wit 68% (1 standard deviation) confidence and represents the radius of a circle.
While indoors you will probably see an accuracy value of 20, 30, perhaps even 50 meters while the Lat & Long jump around within that distance. Once outdoors, the accuracy value should drop to under 10 meters, often under 5 meters, and your position will jump around much less frequently.
tl;dr : GPS doesn't give accurate results indoors.

Related

Avoid get multiple location when device is still stable in gps android

i using simple Listner Class for get location in onchage location
but the device is stable then gps is getting wrong lat long and get multliple location up to in 1000 meter.
MyLocationListener.java
public class MyLocationListener implements LocationListener{
#Override
public void onLocationChanged(Location location) {
// Toast.makeText(getBaseContext(), "change time", 5).show();
if(location.getAccuracy() < 100.0 && location.getSpeed() >0.95){
Log.v("ddddddd", "fffffffff"+location.getLongitude()+location.getProvider());
// if (location.hasAccuracy() && location.getAccuracy() <= minAccuracyMeters){
accuracy=location.getAccuracy();
longitude=location.getLongitude();
latitude=location.getLatitude();
speed=(int) ((location.getSpeed()*3600)/1000);
}
}
Please Help me i new in android i will workin on GPS last two month.
Filter the locations this way,
public static final int MINIMUM_ACCURACY = 50;
public static boolean isValidAndAccurateLocation(Location location) {
boolean validLocation = location != null
&& Math.abs(location.getLatitude()) <= 90
&& Math.abs(location.getLongitude()) <= 180;
if (validLocation && location.hasAccuracy()
&& location.getAccuracy() <= MINIMUM_ACCURACY) {
return true;
} else {
return false;
}
}
Provide minimum distance when requesting location updates, No need to calculate distance manually. use
mLocationManger.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, time, distance,
this);
Where time is time in milliseconds and distance is minimum distance in meters. See this for full explanation.

Getting location data on an Android device in certain intervals

I am trying to make an Android app which takes the location data in certain intervals e.g:- 5 sec, 1 min,etc. Here is my code :-
public void onLocationChanged(Location loc) {
// TODO Auto-generated method stub
if(loc!=null)
{
//Required Interval
tInterval =(minInterval*60*1000) + (secInterval)*1000 - 1000;
//The app also supports interval mode
RadioButton sel = (RadioButton) findViewById(mode.getCheckedRadioButtonId());
//Code for Manual Functionality
if(sel.getText().equals(MANUAL_RADIO))
{
Time t = new Time();
t.setToNow();
db.addLocationAtTime(loc, t);
Toast.makeText(getApplicationContext(), "Location Added to Database",Toast.LENGTH_SHORT).show();
locate.removeUpdates(this);
b.setText(MANUAL_BUTTON);
d.setEnabled(true);
}
//Code for Interval functionality
else if(sel.getText().equals(INTERVAL_RADIO))
{
//count is object of Countdown class which is a Thread object
if(count == null)
{
//t is a Time object
t.setToNow();
//SQLiteDatabase object for logging Location with Time
db.addLocationAtTime(loc, t);
Toast.makeText(getApplicationContext(), "Location Added to Database",Toast.LENGTH_SHORT).show();
count = new CountDown( tInterval);
count.start();
}
else if(count.getState().toString().equals("TERMINATED"))
{
t.setToNow();
db.addLocationAtTime(loc, t);
Toast.makeText(getApplicationContext(), "Location Added to Database",Toast.LENGTH_SHORT).show();
count = new CountDown(tInterval);
count.start();
}
}
}
}
Here is the code for the Countdown class:-
This class is used to add the interval to the app
public class CountDown extends Thread
{
long time;
public CountDown(long duration)
{
time = duration;
}
public void run()
{
long t1 = System.currentTimeMillis();
long t2 = 0;
do
{
t2 = System.currentTimeMillis();
}while(t2 - t1 < time);
}
}
The problem is that using the above code I am not getting accurate intervals. I am always getting 1 sec extra (due to which I subtracted 1000 in the formula) , but this 1 sec is not happening always. So can anyone please tell me what I am doing wrong ?
Look at LocationManager.requestLocationUpdates, just pass your time interval in parameter..
LocationManager mLocationManager = (LocationManager).getSystemService(mActivity.LOCATION_SERVICE);
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, 0, new GeoUpdateHandler());
i think here you need to use default features , no need to use Timer
NETWORK_PROVIDER
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 3000, 0, networkLocationListener);
GPS_PROVIDER
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 0, gpsLocationListener);
Here ,
minTime(2nd field) => minimum time interval between location updates, in milliseconds
minDistance(3rd field) => minimum distance between location updates, in meters
Documentation
I don't think the minTime param of the requestLocationUpdates(...) methods does anything at all. It does not seem to prevent distance-based updates from coming at shorter intervals, and it definitely does not cause updates to come at the specified interval, as many people seem to think. I've tried it on devices from Android 2.3.6 to 4.0.4.

Toast in loop is not displaying properly

I have the following code in my main activity (Note: GPSTracker in this application works):
double latitude, longitude;
gps = new GPSTracker(MainActivity.this);
if(gps.canGetLocation()){
latitude = gps.getLatitude();
longitude = gps.getLongitude();
Toast.makeText(getApplicationContext(), "Your Location is - \nLat: " + latitude + "\nLong: " + longitude, Toast.LENGTH_LONG).show();
}
else{
gps.showSettingsAlert();
}
I want to create a loop, which would display in some time intervals Toast with my current position. I´ve tried this:
double latitude, longitude;
long currentTime = System.currentTimeMillis();
long myTimestamp = currentTime;
int i = 0;
gps = new GPSTracker(MainActivity.this);
while(i < 5)
{
myTimestamp = System.currentTimeMillis();
if((myTimestamp - currentTime) > 5000)
{
i++;
currentTime = System.currentTimeMillis();
if(gps.canGetLocation()){
latitude = gps.getLatitude();
longitude = gps.getLongitude();
Toast.makeText(getApplicationContext(), "Your Location is - \nLat: " + latitude + "\nLong: " + longitude, Toast.LENGTH_LONG).show();
}else{
gps.showSettingsAlert();
}
}
}
With this code, Toast is shown only one time (the last iteration). Could you help me with this? Thanks in advance.
I want it to be shown every iteration (for example every 5 seconds).
The code above doesn't loop every five seconds, it loops continuously but only increments your counter every five seconds... This is a very inefficient way of creating a time delay because nothing else can happen while the loop runs. (Even if you run this on a separate thread it is still not good tactic.)
Instead use LocationManager's requestLocationUpdates which will use callbacks so your app can do things between updates. A couple quick notes:
Understand that the GPS may not be able to get a fix every five seconds and that this interval is really short so use it sparingly or you'll run the battery down.
Some pre-Jelly Bean devices may not observe the minTime parameter, but you can enforce your time parameter yourself as I describe in Android Location Listener call very often.
All that aside, you use your existing code but I recommend a Handler and Runnable, like this:
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Fetch your location here
// Run the code again in about 5 seconds
handler.postDelayed(this, 5000);
}
}, 5000);
One problem is that this method does a 'busy-wait', which, I suspect, prevents the toast from being displayed. Try doing a sleep() to wait until it's time for the next Toast:
public void sleepForMs(long sleepTimeMs) {
Date now = new Date();
Date wakeAt = new Date(now.getTime() + sleepTimeMs);
while (now.before(wakeAt)) {
try {
long msToSleep = wakeAt.getTime() - now.getTime();
Thread.sleep(msToSleep);
} catch (InterruptedException e) {
}
now = new Date();
}
}

GPS - Getting the distance,time while running and walking

i have a situation where i need to use GPS technique.
i need to find the distance between two points when the person is walking.
When the person starts walking he will click on Start button and when he stops he clicks on stop button
after this it should show him
1.time taken
2.Distance travelled in Kms.
3.from where to where(places name) eg: a to b
Do i need to have google maps for this?
I saw the code here link to get the current location which gives me latitude longitude.
please help how to go with this
**
Edited:
**
This is the code i am using
private EditText editTextShowLocation;
private Button buttonGetLocation;
private ProgressBar progress;
private LocationManager locManager;
private LocationListener locListener = new MyLocationListener();
private boolean gps_enabled = false;
private boolean network_enabled = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
editTextShowLocation = (EditText) findViewById(R.id.editTextShowLocation);
progress = (ProgressBar) findViewById(R.id.progressBar1);
progress.setVisibility(View.GONE);
buttonGetLocation = (Button) findViewById(R.id.buttonGetLocation);
buttonGetLocation.setOnClickListener(this);
locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
}
#Override
public void onClick(View v) {
progress.setVisibility(View.VISIBLE);
// exceptions will be thrown if provider is not permitted.
try {
gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch (Exception ex) {
}
try {
network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception ex) {
}
// don't start listeners if no provider is enabled
if (!gps_enabled && !network_enabled) {
AlertDialog.Builder builder = new Builder(this);
builder.setTitle("Attention!");
builder.setMessage("Sorry, location is not determined. Please enable location providers");
builder.setPositiveButton("OK", this);
builder.setNeutralButton("Cancel", this);
builder.create().show();
progress.setVisibility(View.GONE);
}
if (gps_enabled) {
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locListener);
}
if (network_enabled) {
locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locListener);
}
}
class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location location) {
if (location != null) {
// This needs to stop getting the location data and save the battery power.
locManager.removeUpdates(locListener);
String londitude = "Londitude: " + location.getLongitude();
String latitude = "Latitude: " + location.getLatitude();
String altitiude = "Altitiude: " + location.getAltitude();
String accuracy = "Accuracy: " + location.getAccuracy();
String time = "Time: " + location.getTime();
editTextShowLocation.setText(londitude + "\n" + latitude + "\n" + altitiude + "\n" + accuracy + "\n" + time);
progress.setVisibility(View.GONE);
}
}
#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
}
}
#Override
public void onClick(DialogInterface dialog, int which) {
if(which == DialogInterface.BUTTON_NEUTRAL){
editTextShowLocation.setText("Sorry, location is not determined. To fix this please enable location providers");
}else if (which == DialogInterface.BUTTON_POSITIVE) {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
}
It is showing the Logitude Latitude which i am entering from emulator control.
In this i am manually entering the details of longitude and latitude
by going to window->showview->other->emulator control for testing in the emulator
but what i need is i will have two edittext where i enter the place name(A) and (B)
it should give me the distance
please help
try using Google Distance Matrix Api
https://developers.google.com/maps/documentation/distancematrix/
You can use currentTimeinMillis() to get your start and end time for your journey.
You can then use the formulas explained here to find the distance and lastly you will have to use a reverse geocoding service such as Nominatim to be able to get the address of a place from your GPS coordinates.
That being said, the distance formula will get you the distance between one point and the next, not the actual displacement. If this is not what you need, but rather you want the actual distance travelled you will need to calculate this value at a shorter interval.
You can find out the distance between two locations(in terms of latitude and longitude) by making use of Spherical Trigonometry
Coming to time make use of simple date objects and compare the startTime and endTime.
(OR)
You can get approximate distance using below code
double distance;
Location locationA = new Location("point A");
locationA.setLatitude(latA);
locationA.setLongitude(lngA);
Location locationB = new Location("point B");
locationB.setLatitude(latB);
LocationB.setLongitude(lngB);
distance = locationA.distanceTo(locationB);
For getting the distance between 2points(A to B) there is a function called distanceTo in android.
For e.g.
double distance = startLocation.distanceTo(finishLocation)/1000;
For time taken as npinti said you can use currentTimeinMillis() or you can also use Timer and show it to user when he clicks on start button. Its just like stopwatch.
Edited
Place A - New York
Place B - Paris
In this case you first need to convert the string into Location(i.e you need latitude & longitude). For that you have use the concept of Geocoding.
List<Address> foundGeocode = null;
foundGeocode = new Geocoder(this).getFromLocationName("address here", 1);
foundGeocode.get(0).getLatitude(); //getting latitude
foundGeocode.get(0).getLongitude();//getting longitude
After that you can calculate the distance from the distanceTo method.
Hope this will help....
I suppose the question is one of walking..
Are you walking on the streets, or as the crow flies?
If it's streets, and your connected to the net, use google's api.. It calculates routing based on two points and returns XML.. Should be easy enough to figure out.
If it's crow flies.. well then, just do (a*a) + (b*b) = (c*c) this is by far the easier..
You could have your user tap for major turns.. Or you could keep a runnable running every 10 seconds from when they hit start, and plot the points. Still a*a+b*b=c*c but just a bunch of steps.
Of course you'd have to run it in a service.. And given the choice I'd go with that option. You could adjust the cycle time based on speed traveled. Faster would be smaller pauses.
It requires less on your dataplan.
EDIT
Ah.. I see what you're looking for. Tis not what I thought you were asking for.
Simplify.. convert lat/long to GPS. and then do simple math on the last point stored
void addDistance()
{
newX = ...
newY = ...
deltaX = absolute(m_oldX - newX)
deltaY = absolute(m_oldY = newY)
m_distance += sqrt(deltaX^2 + deltaY^2);
m_oldX = newX;
m_oldY = newY;
}
void startOver()
{
newX = ...
newY = ...
m_distance = 0;
m_oldX = newX;
m_oldY = newY;
}

How to get the latitude and longitude or gps data quickly while we are indoor in an android phone?

I'm trying to get the latitude and longitude information from an android phone through GPS, when i'm outdoor or under the sky directly i'm able to get the values instantly but when i'm indoor or inside a room its taking more than a minute to get the values. Can anyone help me in getting this values fastly when I'm using my app inside a room.
I'm using the following code in getting the values:
LocationManager locManager;
locManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000L,500.0f,
locationListener);
Location location = locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
and
private final LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
EditText myLocationText = (EditText)findViewById(R.id.editText1);
EditText myLocationText1 = (EditText)findViewById(R.id.editText2);
String latString = "";
String LongString = "";
if (location != null) {
double lat = location.getLatitude();
double lng = location.getLongitude();
latString = "" + lat;
LongString ="" + lng;
} else {
latString = "No location found";
LongString = "No location found";
}
myLocationText.setText(""+ latString);
myLocationText1.setText(""+ LongString);
}
Is there any other way in getting the GPS values other than using LocationManager??
You can get the last known location, and it's quite fast:
/**
* Gets the last known location.
*
* #param locationManager the location manager
* #return the last known location
*/
public static Location getLastKnownLocation(LocationManager locationManager)
{
Location bestResult = null;
float bestAccuracy = 10000;
long bestTime = 0;
List<String> matchingProviders = locationManager.getAllProviders();
for (String provider: matchingProviders) {
Log.d("LOCATION", "Provider: " + provider);
Location location = locationManager.getLastKnownLocation(provider);
Log.d("LOCATION", "Location found? "+ (location==null?"NO":"YES"));
if (location != null) {
float accuracy = location.getAccuracy();
long time = location.getTime();
Log.d("LOCATION", "Acc: "+ String.valueOf(accuracy) + " -- Time: " + String.valueOf(time));
if ((time > minTime && accuracy < bestAccuracy)) {
bestResult = location;
bestAccuracy = accuracy;
bestTime = time;
}
else if (time < minTime &&
bestAccuracy == Float.MAX_VALUE && time > bestTime){
bestResult = location;
bestTime = time;
}
}
}
Log.d("LOCATION", "BEST FOUND? "+ (bestResult==null?"NO":"YES"));
return bestResult;
}
You can get the last known location of the device using the following method in LocationManager, this is the location that has been last found system-wide.
This method is the key:
Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
See for more details Obtaining User Location
If you are indoors, you would be better of using LocationManager.NETWORK_PROVIDER as you are unlikely to get a signal inside. You could also use getLastKnownLocation(), but this may be non existent or out of date.
If you want get position in a room, gps provider is slowly. You can try changing:
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000L,500.0f,
locationListener);
Location location = locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
By:
locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,1000L,500.0f,
locationListener);
And you will receive location in 'public void onLocationChanged(Location location)' method.
I used Network provider to fetch the Co-Ordinates and it is always much faster inside the house in living room. But when I try the same in the Basement area, it doesn't fetch the coordinates at all though I waited almost couple of minutes.
Note: I could able to make a call from basement area and I am also able to browse as well..

Categories

Resources