i'm currently developing an App in Android (Kotlin) to get the location (latitude and longitude) on demand (Only when pressing a float action button) and display them in some TextViews, i dont need constant updates of the location (requestLocationUpdates). In other function i'm checking permissions so all of that is apparently fine. I created the apk file, installed it on my phone (Motorola One Vision - Android 11) and i went to walk to test some locations and getting coordinates but i got something strange. When i pressed the Geolocation button i got the coordinates after a few seconds. After that if i were to walk like 5 or 10 meters (Like 8 to 15 seconds walking) and try to get the location again, 3 possible things happened:
I got a new location after a few seconds (3 to 5) with new coordinates so that was fine. When this happened i saw the little icon of google ubication in the status bar.
I was getting the same location (coordinates) that i got previosly before walking those 5 to 10 meters. The icon of google location didn't appear in the status bar and i got the message of "Location obtained" almost instantly (I see in a Toast the message "Location obtained"). To get a new coordinate i had to wait like 5 seconds and press the button multiple times.
I got new coordinates almost instantly (The toast with "Location obtained") without seeing the little google ubication icon in the status bar.
I don't understand the behaviour of "getCurrentLocation" and i'm worried about the second case (Getting same coordinates than before). Why is that?, and what can i do to adress tha behaviour of getCurrentLocation?. I would like every time i press the button i get new coordinates even if i have to wait some seconds. And the third case is a weird one. How can i get a new coordinate so fast in some cases and in other (first case) i have to wait.
This is my code only of the function that activates the getCurrentLocation function.
#SuppressLint("MissingPermission")
fun getLocation(){
if (isGPSActivated){
fusedLocationProviderClient.getCurrentLocation(
LocationRequest.PRIORITY_HIGH_ACCURACY,
object : CancellationToken() {
override fun onCanceledRequested(p0: OnTokenCanceledListener) = CancellationTokenSource().token
override fun isCancellationRequested() = false
})
.addOnSuccessListener { location: Location? ->
if (location == null) {
Toast.makeText(
this,
"Can't get location, try again",
Toast.LENGTH_SHORT
).show()
}
else {
updateLocationInViewModel(location)
Toast.makeText(
this,
"Location obtained",
Toast.LENGTH_SHORT
).show()
}
}
.addOnFailureListener {
Toast.makeText(
this,
"Can't get location, try again",
Toast.LENGTH_SHORT
).show()
}
}
}
fun updateLocationInViewModel(currentLocation: Location){
individuoViewModel._localization.value = currentLocation
}
I have an observer for individuoViewModel._localization so that when it detects a new value the TextViews refresh.
The getCurrentLocation() function is using the Fused Location Provider API in Android to get the device's current location. The priority is set to high accuracy, which means that the device will use GPS, Wi-Fi, and mobile networks to determine the location. The behavior you're observing is likely due to the way the Fused Location Provider API works.
When you first request the location, the device will use GPS to determine the location, which can take a few seconds. If you request the location again within a few minutes of the first request, the device will likely use the cached location instead of requesting a new location from the GPS, which is why you're seeing the location obtained almost instantly. This can happen if the device is unable to determine a new location using GPS.
When you move a few meters and request the location again, the device may use the GPS to determine the new location, which can take a few seconds. However, if the device is still unable to determine a new location using GPS, it may return the cached location again.
It's normal that you don't see the little icon of google location in the status bar, this icon appears when the device is actively using GPS to determine the location, but it doesn't appear when the device is using cached location or other sources like wifi or mobile network.
In conclusion, the Fused Location Provider API uses a combination of GPS, Wi-Fi, and mobile networks to determine the device's location, and it may return a cached location if the device is unable to determine a new location using GPS. The time it takes to get a location and the accuracy of the location can vary depending on the device's environment and the availability of location sources.
Related
I would like to ask a clarification about the meaning of the "Searching gps" notification. I have a simple app that tries to retrieve user position via FusedLocationProviderClient with this code:
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(activity as Activity)
fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
mMap.isMyLocationEnabled = true
// other trivial stuff here
}.addOnFailureListener {
// showing an error here
}
Even when last location is retrieved android keeps showing the "Searching gps" notification (Ricerca gps in the screenshot below). As far as you know, this means that app is still searching for gps updates (and so draining battery) or is a simple message to notify the user that the app is using the gps? Thanks for the clarification, my device is a Xiaomi Redmi 5 Plus (MiUI)
I'm not 100% sure I understand the question, but I'll take a stab here. I think one of two things is going on:
The notification is being explicitly shown by the MyFoody app and it's that app's responsibility to hide the notification once it no longer needs to be shown. You'd need to take care of clearing that notification in the listener's success and failure functions you've defined. Are your listeners being called? Do they clear the notification?
OR
It may be that Xiaomi has modified Android to show that notification on behalf of your app while it's retrieving location(s). If that's the case, then you'd need to figure out why this Xiaomi-modified Android version still thinks your app is trying to get a location. It could also just be a bug on Xiaomi's part, but I'd consider that as a last resort.
I would have thought that requesting the "lastKnownLocation" would return a saved coordinate (GeoPoint) that points to the last known location of the device (from when it last had access to the GPS functionalities).
According to some tests (made on OSMDroid's GpsMyLocationProvider), it seems like requesting that location returns a NullPointer.
GpsMyLocationProvider provider = new GpsMyLocationProvider(MainActivity.mainActivity);
provider.addLocationSource(LocationManager.NETWORK_PROVIDER);
locationOverlay = new MyLocationNewOverlay(provider, map);
I've been trying to set up default GeoPoint for centering the map when it is first launched, and then recentering the map where the GPS now has confirmed a position.
The problem is that provider.getLastKnownLocation() returns a NullPointer exception unless it is given time to actually get the current location from the GPS.
What am I getting wrong here? Shouldn't the "last known location" be a GeoPoint that is saved in memory on the phone and always have something there, unless the phone never ever had access to GPS localization ?
Please see https://developer.android.com/training/location/retrieve-current
You must set the permissions correctly too. Note that at the bottom they describe why the location may be null so see these for troubleshooting.
If you're using an emulator see How to emulate GPS location in the Android Emulator?
So, I'm trying to build a weather app for practice and I've been running into the problem of trying to get the location. I've read people suggest to use getLastLocation through the fused location API, problem with that is if they don't already have a location registered on the device it comes up null. I've noticed using the emulator times that this come up is rare, but I'd still like my app to handle it properly. One instance where you might run into this is if they just turned GPS off and back on, or if the phone was just turned on. One thing I did was if getLastLocation does come back null, is to request an update, but then you still have to wait for the device to register an updated location, which with a weather app all of the data is based off of and you're still kind of running into the same problem. I've noticed with other apps this isn't a problem, like sometimes I actually have to load up Google Maps to get it to register a location. How does Google Maps force it to update the location? Here's the example from my getLocation method:
public void getLocation() throws SecurityException {
boolean gps_enabled;
LocationManager lm = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (gps_enabled) {
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location != null) {
startGetForecast(location);
} else {
LocationRequest request = LocationRequest.create();
request.setNumUpdates(1);
request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, request, this);
}
}
else {
AlertDialogFragment alertDialogFragment = new AlertDialogFragment();
alertDialogFragment.setErrorTexts("Location Unavailable", "Could not retrieve location information.", "Exit");
alertDialogFragment.show(getSupportFragmentManager(), "Location Unavailable");
}
}
Note: This answer could sound like not answering to the question directly but after chatting (comments in question) with OP as his code was ok in general but the condition around the problem, this answer has satisfied OP.
Fortunately, the standard library Is not the only way Google can get
code into your hands. In addition to the standard library, Google
provider Play services. This is a set of common services that are
installed alongside the Google Play store application. To fix this
location mess, Google shipped a new locations services in Play
Services called the Fused Location Provider.
Since these libraries
live in another application, you must actually have that application
installed. This means that only devices with the Play Store app
installed and up to date will be able to use your application.
So the conclusion is:
You need to test the app on your device as mentioned above.
Since you are using Fused Location Provider Api, that means the Api will automatically determine last location from one of the following sources:
GPS radio
Coarse points from cell towers
WiFi connections
So you could easily remove the GPS if condition from your code
Be a ware of that if you must use GPS signal, you need to be out side the building, lab, home or office.
If you want to dig more find more in the mentioned resources and there is a lot of online resources.
Resources: The first part of the answer, the source of it is from:
Android Programming: The Big Nerd Ranch Guide 2nd edition chapter 31 page 552 under Google Play Services
In my app I am using Android Location Manager API and I have a requirement of identifying whether the location coordinates are from normal Location Manager or if they are from Fake(Mock) Location provider. I used location.isFromMockProvider(). Once I turn on the fake location providing app, isFromMockProvider() method returns me true. And after that it does not matter if I turn, fake location providing app, on or off isFromMockProvider() method always returns true.
I found that once FakeGPS app, once triggered, overrides the location manager coordinates and once I stop the FakeGPS app, the Location Manager does not start collecting correct coordinates.
Is there something I am missing.
Disappointed with no response but I am glad that I got it working :)
Posting the resolution as it might help someone else.
Once the FakeGPS app starts mocking location, it stops my app's Location manager.
Now even if I stop the FakeGPS app mocking service, the location manager of my app won't trigger back.
I have to detect the event and restart the location manager of my app, after removing any test provider and clearing test locations.
just resetting and removing test location should help
String t = LocationManager.GPS_PROVIDER;
locationManager.clearTestProviderEnabled(t);
locationManager.clearTestProviderLocation(t);
locationManager.clearTestProviderStatus(t);
locationManager.removeTestProvider(t);
I am developing android application which gives notification when user enter in specific location
User can specify the location by using latitude longitude(ie Google Map)
I know how to get latitude & longitude but my problem is that when user enter in specific location then it will not exactly match with previously specified latitude & longitude.
As shown in image suppose user specify the location called "My Place" when user enter in area (about 20 meter) then application should send notification to user.
I want know how I can compare the latitude & longitude which user specified(My place) and current latitude & longitude which application fetch by GPS.
The comparison made in such way that it will true if user near by of My place in area of 20 meter.
(This 20 meters is approximate.)
Can I set accuracy of in android e.g. 20 meters.
Thank you.
The best approach to this problem is using the GeoFences feature. Please refer to https://developer.android.com/training/location/geofencing.html for more details.
Outline:
- The application registers with the underlying OS - saying - here is MY list of geofences (specific location + radius from the location) that I want you to monitor.
- If my user comes within this geo fence - wake me up and tell me so.
- At that point of time - you can go ahead and perform any step (either call a server and ask what information you need to display to the user) or just send a push notification (in app notification) to do the necessary work.
Hope this helps.
Look at the LocationManager.addProximityAlert function. It does pretty much exactly what you want. Warning, it does use a good amount of battery.
You can make gps pooling calculating with spatial distance functions
There is point sdk (android & ios) from Bluedotinnovation which has more accuracy and less battery drain also similar free sdk from Radar
Radar geofencing is more powerful than native iOS or Android geofencing, with cross-platform support for unlimited geofences, polygon geofences, stop detection, and accuracy down to 30 meters.
Also they have ReactNative support.