This question may a repetition but i am not satisfied with others ,that is why asking again .i have created a simple app to show current location and displayed it on map.But its not accurate.I tested my app within a building and is fetching the nearby road as my current location,But other apps like Myteksi,Grab teksi is showing my company name as current location and its accurate.i dont know why its so.Please help.Code for fetching current location is giving below
protected void gotoCurrentLocation() {
Location currentLocation = mLocationClient.getLastLocation();
if (currentLocation == null) {
Log.d("currentLocation-->>>", "null");
Toast.makeText(this, "Current location isn't available",
Toast.LENGTH_SHORT).show();
} else {
LatLng ll = new LatLng(currentLocation.getLatitude(),
currentLocation.getLongitude());
Log.d("lattitude", currentLocation.getLatitude()+"");
Log.d("longitude", currentLocation.getLongitude()+"");
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(ll,
DEFAULTZOOM);
map.animateCamera(update);
/*String address= service.GetAddress(currentLocation.getLatitude(),
currentLocation.getLongitude());
Log.d("address", address);*/
}
}
please comment if any other codes are needed.
As you said you test the app in indoor location. And you know in indoor locations GPS sensor will not work, According to google's docs:
Although GPS is most accurate, it only works outdoors.
So your location might come from Network Provider using wi-fi or cell-id, which is not enough accurate.
Android's Network Location Provider determines user location using cell tower and Wi-Fi signals, providing location information in a way that works indoors and outdoors.
and you must be aware of that:(when using getLastLocation() )
To get the current location, create a location client, connect it to Location Services, and then call its getLastLocation() method. The return value is the best, most recent location, based on the permissions your app requested and the currently-enabled location sensors.
BUT:
The current location is only maintained while a location client is connected to Location Service. Assuming that no other apps are connected to Location Services, if you disconnect the client and then sometime later call getLastLocation(), the result may be out of date.
and also please take a look at this to learn more about Maintaining a current best estimate:
http://developer.android.com/guide/topics/location/strategies.html#BestEstimate
I hope this information helps. ;)
This is because fetching location is a very complicated task to do. And the native implantation of LocationClient might not be the most accurate.
Consider using one or all the 13 sensors(Table 1) in your device to improve that.
TYPE_ACCELEROMETER Hardware Measures the acceleration force in m/s2 that is applied to a device on all three physical axes (x, y, and z), including the force of gravity. Motion detection (shake, tilt, etc.).
TYPE_AMBIENT_TEMPERATURE Hardware Measures the ambient room temperature in degrees Celsius (°C). See note below. Monitoring air temperatures.
TYPE_GRAVITY Software or Hardware Measures the force of gravity in m/s2 that is applied to a device on all three physical axes (x, y, z). Motion detection (shake, tilt, etc.).
TYPE_GYROSCOPE Hardware Measures a device's rate of rotation in rad/s around each of the three physical axes (x, y, and z). Rotation detection (spin, turn, etc.).
TYPE_LIGHT Hardware Measures the ambient light level (illumination) in lx. Controlling screen brightness.
TYPE_LINEAR_ACCELERATION Software or Hardware Measures the acceleration force in m/s2 that is applied to a device on all three physical axes (x, y, and z), excluding the force of gravity. Monitoring acceleration along a single axis.
TYPE_MAGNETIC_FIELD Hardware Measures the ambient geomagnetic field for all three physical axes (x, y, z) in μT. Creating a compass.
TYPE_ORIENTATION Software Measures degrees of rotation that a device makes around all three physical axes (x, y, z). As of API level 3 you can obtain the inclination matrix and rotation matrix for a device by using the gravity sensor and the geomagnetic field sensor in conjunction with the getRotationMatrix() method. Determining device position.
TYPE_PRESSURE Hardware Measures the ambient air pressure in hPa or mbar. Monitoring air pressure changes.
TYPE_PROXIMITY Hardware Measures the proximity of an object in cm relative to the view screen of a device. This sensor is typically used to determine whether a handset is being held up to a person's ear. Phone position during a call.
TYPE_RELATIVE_HUMIDITY Hardware Measures the relative ambient humidity in percent (%). Monitoring dewpoint, absolute, and relative humidity.
TYPE_ROTATION_VECTOR Software or Hardware Measures the orientation of a device by providing the three elements of the device's rotation vector. Motion detection and rotation detection.
TYPE_TEMPERATURE Hardware Measures the temperature of the device in degrees Celsius (°C). This sensor implementation varies across devices and this sensor was replaced with the
TYPE_AMBIENT_TEMPERATURE sensor in API Level 14 Monitoring temperatures
You might be getting stale location data, as you're using LocationClient.getLastKnownLocation(), which returns the last cached location, not the current one. You could try requesting your own location updates using a LocationListener. To do this, you need to create your own LocationListener and override the default onLocationChanged(Location) behavior. For example:
final LocationListener ll = new LocationListener(){
int i=0;
#Override
public void onLocationChanged(Location loc) {
if(i < 5 && loc.getAccuracy() > 8){
i ++;
return;
}
double lat = loc.getLatitude();
double lon = loc.getLongitude();
double acc = loc.getAccuracy();
}
};
You then need to register the listener using an instance of LocationManager:
final LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, ll);
This example will register the listener for whenever the GPS location changes. The actual listener code above waits for at least 5 location changes to help ensure that the final location is accurate (the longer time waited, the more time it will have had to lock-on to satellites), then gets the latitude, longitude, and accuracy from the Location object. There are many other ways that you can setup your listener, but that's the way that I did it in one of my apps. If you Google something like "android location updates", you should find some other good tutorials for it. Good luck!
Related
How are Driving Events tracked?
I need these information in android. Is there any SDK or lib for this?
1) You can use activity recognition api to detect motion this will
give you start and end point
2) speed you can get by speed
=location.getSpeed(); or you can store lat , lng with time stamp so you can calculate distance between two lat lng divide by elapsed
time that will give you speed.
3) based on acceleration you can calculate harsh acceleration or
harsh breaking using linear acceleration value compared with last
acceleration value can be calculated by
SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
for calculating harsh acceleration and breaking you will have to calculate G-force value from acceleration.
Note : You have to make this calculations in service ( foreground service if you want location to be tracked in background
Is it possible to get the information on the location mode which the user has selected among the three modes under the location settings options i.e
1.Hight Accuracy
2.Battery Saving
3.GPS Only
I want to programmatically check if user has selected High Accuracy mode if not then enable it automatically. Is it possible ? Please advice.
It is possible to get the device's current location mode since API level 19 (Kitkat):
public int getLocationMode(Context context) {
return Settings.Secure.getInt(activityUnderTest.getContentResolver(), Settings.Secure.LOCATION_MODE);
}
These are the possible return values (see here):
0 = LOCATION_MODE_OFF
1 = LOCATION_MODE_SENSORS_ONLY
2 = LOCATION_MODE_BATTERY_SAVING
3 = LOCATION_MODE_HIGH_ACCURACY
So you want something like
if(getLocationMode(context) == 3) {
// do stuff
}
Unfortunately you can't set the location mode programmatically but you can send the user directly to the settings screen where he can do that:
startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
You can provide criteria in the LocationMamager.requestLocationUpdates. As criteria you can provide one of the following values to select the accuracy needed.
Constants
int ACCURACY_COARSE A constant indicating an approximate accuracy requirement
int ACCURACY_FINE A constant indicating a finer location accuracy requirement
int ACCURACY_HIGH a constant indicating a high accuracy requirement - may be used for horizontal, altitude, speed or bearing accuracy.
int ACCURACY_LOW A constant indicating a low location accuracy requirement - may be used for horizontal, altitude, speed or bearing accuracy.
int ACCURACY_MEDIUM A constant indicating a medium accuracy requirement - currently used only for horizontal accuracy.
See
http://developer.android.com/reference/android/location/LocationManager.html#requestLocationUpdates(long, float, android.location.Criteria, android.app.PendingIntent)
Since API level 28, you should use LocationManager.isProviderEnabled() to find out if a specific provider is enabled or not.
Changing the setting programmatically from your app is unfortunately not possible.
I'm testing an Android app that records the location (lat/long/alt). I'm running the app on a Samsung GTS5830 phone running Android 2.2.1
I read here and there that GPS altitude is often incorrect due to the earth not being perfectly spherical. At my location, for example, the geoid's height is 52 meters.
My understanding is that this height would be substracted from a "pure" GPS altitude. This would make sense for my location as:
- altitude from GPS phone: 535 m
- geoid altitude: 52 m
- altitude from phone's GPS minus geoid height: 482m
- correct atlitude: 478 m
482 is close enough to the real thing for me to track elevation when hiking
Is the above formula of the GPS height minus the geoid's height correct?
Am I correct to assume that android is not factoring in the geoid's height when returning the GPS altitude?
If the above is true, does it hold for all versions of Android?
Here is the code I use to obtain the GPS coordinates:
public class HelloAndroid extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d("main", "onCreate");
setupGps();
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
LocationListener locationListener;
LocationManager lm;
void setupGps() {
Log.d("gps", "Setting up GPS...");
locationListener = new MyLocationListener();
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 20000, 5,
locationListener);
Log.d("gps",
"GPS supports altitude: "
+ lm.getProvider(LocationManager.GPS_PROVIDER)
.supportsAltitude());
Log.d("gps", "Finished setting up GPS.");
}
static class MyLocationListener implements LocationListener {
public void onLocationChanged(Location location) {
Log.d("gps", "long: " + location.getLongitude() + ", lat: "
+ location.getLatitude() + ", alt: "
+ location.getAltitude());
}
}
}
The answers to all three of your questions are yes.
The altitude you get from GPS is the height above the WGS84 ellipsoid in metres, which is an approximation of the earth's surface. I know that because I've been developing Android software to use it.
A correction has to be applied to convert the figure to height above mean sea level, or altitude as it is usually known. Note that this may differ from the altitude reported by an altimeter set to the current pressure at mean sea level because an altimeter actually measures air pressure, but air pressure is not just a function of height; it is also a function of air density and temperature, so an altimeter shows an approximation. This effect is not seen with GPS.
The Earth Gravitational Model 2008 (EGM2008) maps the difference in mean sea level with the ellipsoid as a function of longitude and latitude. Details are here:
http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008/egm08_wgs84.html
A less accurate model that uses less data called EGM96 is also available. Google both of these to understand these better.
It's not quite that simple -- the Android API has either changed or has bugs. I have two Android devices -- a 'generic' phone (Android 2.3.6) and a Nexus 7 (Android 4.x).
On the phone, getAltitude() gives an answer consistent with my actual altitude AMSL (i.e., corrected for geoid). On the Nexus 7, the altitude returned is uncorrected. The documentation for the API does not specify which is returned -- so in some sense both are 'correct'.
Both devices seem to have decent GPS modules -- the $GPGGA NMEA message shows both the correct altitute and the geoid correction. So it looks as though one has to parse the messages oneself to get the correct altitude, and the getAltitude() method is untrustworthy.
Errors in the altitude may well not be down to the GPS and geoid altitude separation.
The altitude value returned by any GPS receiver is always the least accurate value. I have often seen my office building report that it is moving in altitude between -200 and +750 metres. One fundamental reason is that it is impossible to get an even spread of satellites in the altitude direction; they are always going to be above you, and if there is any obscuration of the sky at low elevations, they will be located in a cone above you. In the X and Y directions there will always, assuming a good sky view, be satellites spread left and right; in front and behind the receiver. This spread enhances the accuracy of the position solution.
I'd like to track my Location every minute. For that I use a locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 60000, 0, pll);
Here is the log when my phone is idle.
Date Latitude Longitude Accuracy
07:45:35 51.362402459999996 - 6.2174867399999995 (75.0)
07:46:35 51.362402459999996 - 6.2174867399999995 (75.0)
07:47:35 51.362402459999996 - 6.2174867399999995 (75.0)
...
07:50:35 51.362402459999996 - 6.2174867399999995 (75.0) # I'm further than 75m away from my home at that time
I've indeed a new location every minute but it is exactly the same. Just the time is updated. The position is not updated (maybe normal when I don't move enough) but I find it strange that the coordinates are exactly the same. Also as I don't have wireless activated, it should locate me accordingly to the CellId (with an accuracy of ~1000m), here I still have an accuracy of 75.0. It seems, it is the last location recorded using wireless networks.
Any idea how can I record the real last location (even with low accuracy) ?
public void onLocationChanged(Location location) {
System.out.println(new Date(location.getTime())+" "
+location.getLatitude()+" - "+location.getLongitude()+" ("+location.getAccuracy()+")");
callback.addEntry(location);
}
Hey use GPS_PROVIDER instead of NETWORK_PROVIDER as per below code
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, pll);
NETWORK_PROVIDER will give you only fix tower location and gps will give you exact changing location
You have got nearest GSM tower coordinates.
It seems there is no way to force to compute the position using the LocationManager with the celltower only when there is no wireless connexion.
Maybe another way would be to use the method mentioned in the thread Poor Man GPS : manually compute the position knowing the CellId.
Pseudo code :
onLocationChanged(new_location)
if isConnected()
record(new_location)
else
cell_location = poorManGPS()
record(cell_location)
end
The problem is of course that I cannot query the cell-id database with no internet connection. I see several solutions :
Store the current (and previous) cell id when I have internet and hope I'll stay in this one when I won't have internet
Use the cell id database on the phone (but I think root privileges needed)
Store the cell id for further localization
my android application shows the direction of a particular place in the world and therefore in needs to get the compass degree.
This is the code I've been using to calculate the degrees:
public void getDirection() {
mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
List<Sensor> mySensors = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
if(mySensors.size() > 0){
mySensorManager.registerListener(mySensorEventListener, mySensors.get(0), SensorManager.SENSOR_DELAY_UI);
}
else{
TextView alert = (TextView)findViewById(R.id.instruct);
alert.setText(getString(R.string.direction_not_found));
myCompassView.setVisibility(myCompassView.INVISIBLE);
}
}
private SensorEventListener mySensorEventListener = new SensorEventListener(){
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
compassBearing = (float)event.values[0];
float bearing;
bearing = compassBearing - templeBearing;
if (bearing < 0)
bearing = 360 + bearing;
myCompassView.updateDirection(bearing);
}
};
This method usually works but sometimes it just gets the wrong north, what do I have to do to get a more accurate location?
I have a couple suggestions for you:
1) Your device may not be calibrated. In order to do it, move it around in a form of 8 (see this). If you don't if your device is calibrated or not make some tests by pointing the device at some known cardinal point direction and compare the values. Typically, if a device is not calibrated, you will see great variations in the azimuth value for small rotations. That is what I would be worried about.
Now, don't forget that the sensor gives you the bearing to Magnetic North, and not True North! This difference is known as declination of the magnetic field and its value changes from place to place and from time to time due to changes in Earth's magnetic field. This app can compute some of the values for you with relative accuracy. I wouldn't be too much worried about this as the declination is typically small, but you might be looking for good precision (where I live the declination is 3º, currently).
2) Stay away from metal objects or stuff that generate a strong magnetic field. For example, don't do tests if you have your phone near the computer or any physical keyboards! This is pure poison for testing compass-geolocation. Some apps can measure the intensity of the magnetic field (if the device supports it). When you get closer to metal stuff you will experience higher values and strong changes in directions. For fun, there are also some "metal detectors": this app recognises changes in the magnetic field and vibrates when you are close "metal object" or stuff that magnetically interfere with the device.
3) Remember to update the bearing when you tilt your device to landscape mode. (article is a must read!) This is because azimuth value is based on the rotation of the perpendicular axis to the plane of the phone. When you rotate the device to landscape, this value is changed by +/-90º! This is not resolved by disabling the application landscape mode! You will have to determine it programmatically by analysing rotations around the other two axis (pitch and roll). This is not trivial, but there are some examples somewhere in the net.
edit: If you are interested in some code, check out Mixare, it is an open source augmented reality framework under the GPL3 for Android. Take a look at their code regarding orientation, compass geolocation and bearing.
PS: I don't have any sort of connection with the creators of the mentioned applications.