fusedLocationClient.getLastLocation always returns NULL - android

i implemented the method used in Lib android this, see:
fusedLocationProviderClient.getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if(location != null) {
localidade = location;
Toast.makeText(getApplicationContext(), "Local correto", Toast.LENGTH_LONG).show();
}
Toast.makeText(getApplicationContext(), "Localidade vazia", Toast.LENGTH_LONG).show();
}
});
However, within OnSuccess the result is ALWAYS null, I am testing on my mobile (9.0 android) with LOCAL(gps) mode on and still returns null, my manisfest has the necessary permissions: <uses-permission android: name = "android.permission .ACCESS_FINE_LOCATION "/>
In my view nothing is wrong, so why ALWAYS null?

Last known location is registered known location by the user. If you read on the location page it states that last known location can be null in certain situations; in those scenarios it is advised you request location updates. Following is taken from the page:
The location object can be nullin the following situations:
Location is disabled in the device settings. The result may nulleven
be that the last location was retrieved earlier, because disabling the
location also clears the cache. The device never recorded its own
location, which happens when the device is new or when it has been
restored to factory settings. The Google Play Services platform on the
device has been restarted and no active Fused Location Provider API
clients have requested location after services have been restarted. To
avoid this situation, create a new customer and request location
updates.

Related

How to make sure that getLastLocation().isSuccessful()

Im trying to getLastLocation(), but sometimes it is null. When that happens, I go to google maps just for a second, and return to my app and in 99% that will do. There is also one app that just returns city that you're in and it works even if my app can't getLastLocation(). I've noticed that when I use that other app, or google maps, or weather app, for a short time location icon will appear in status bar, but when I use my app that icon never appears, so I'm guessing that may be the problem?
What I need to do to assure that I get my location to be != null?
One more thing, sometimes I get my location (lat and long), but reverse geocoding goes to catch because List is empty? How to make sure it always is not empty?
The code that I use is just a copy/past from android developers.
If you are using Android Emulator it is expected that the location doesn't get updated unless you open the Maps App.
To ensure you get non-null location you need to request for location updates
You can do something like this
#SuppressLint("MissingPermission")
private fun getLastKnownLocation() {
// get last known location from fusedLocationProviderClient returned as a task
fusedLocationProviderClient.lastLocation
.addOnSuccessListener { lastLoc ->
if (lastLoc != null) {
// initialize lastKnownLocation from fusedLocationProviderClient
lastKnownLocation = lastLoc
} else {
// prompt user to turn on location
showLocationSettingDialog()
// when user turns on location trigger updates to get a location
fusedLocationProviderClient.requestLocationUpdates(
locationRequest, locationCallback, Looper.getMainLooper()
)
}
// in case of error Toast the error in a short Toast message
}
.addOnFailureListener {
Toast.makeText(requireActivity(), "${it.message}", Toast.LENGTH_SHORT).show()
}
}
This is just a stub, you will need to handle permissions, create FusedLocationProviderClient, LocationRequest and LocationCallbackObject.
You may also need to prompt the user to Turn on Location Settings.
Please show us your GeoCoding code to elaborate further.

Android get high resolution location info on button press

I have read the Android Docs, FusedLocationProvider vs LocationManager; perused the dizzying array of questions and answers around this topic here in stackoverflow; and developed many tests with poor results so far. Why is this so darned confusing and hard to grasp?
I have an app that needs to get a hi-res Location object (lat/long/alt/accuracy/etc) when the user performs an action in the app; let's say they press a button. What is the best way to do this?
I have used the fusedLocationProviderClient.getLastLocation().addOnSuccessListener() and get wildly mixed results.
I have used locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER). If I start the GPS Status app on my Galaxy S9 then this produces quite wonderful results. But if that is not running, then the results are worthless.
What am I missing here? Everyone likes to point to this Doc site or that Example site that is mostly worthless and doesn't really answer this specific question. I have wasted hours pouring over those sites that simply don't answer this question. Please, just sum up the general algorithm that should be used here and the calls to make. That is all I need.
I want to be able to walk around in my yard (10 meters here and there) and press the button and have the app show the lat/long/accuracy/altitude/distance-from-last-location and have it be correct every time within a certain level of accuracy. What do I have to do? I need hi-res accuracy, but the ability to notify the user of accuracy less than say 100ft, and still obtain the best accuracy possible even if it has an error of 400ft.
You are missing how GPS receivers work.
When there is no app using precise location, all smartphones turn off the GPS receiver to conserve battery power.
Even if you selected location services to be on (in settings), you will notice in the notification bar the icon for GPS use is only present when an app is active, like Google Maps or GPS test app.
Once the receiver is turned on (because some app needs it), it takes some time before a "fix" - accurate location measurement is available.
How long it will take to get a fix depends on several things, including environmental conditions, your phone type, time and distance since last accurate fix, etc.
It may take anywhere from several seconds to sever minutes.
So, what you should do, is subscribe to location as soon as your app is opened, and request to receive it as frequently as possible.
Then, enable the button only once you have good accuracy, and when the button is pressed, show the latest result.
You should probably also display some spinner or message to the user while waiting for accurate fix so the user knows your app is not stuck.
Edit: by "subscribe" I mean register the necessary callback so your app will receive the location from the system when it is ready.
How to do this, depends on which API you choose.
There is no error in the google docs.
If you choose to use fused location, you will need to do the following:
Create a location request object and set priority to PRIORITY_HIGH_ACCURACY, also setInterval and setFastestInterval to 1000 (1 second) to get the best accuracy.
Get a FusedLocationProviderClient object from LocationServices
Use the client to register a callback to your app
There are code examples here:
https://developer.android.com/training/location/request-updates
In the callback function in your app you can check the accuracy, and if it is good enough for you enable the button and save the location so you can display it to the user when they click the button.
Ok - this seems to work. This general flow seems to be the answer.
Assumptions: you are requesting android.permission.ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION in manifest.
Just sample code in the onCreate() function of MainActivity for testing purposes.
check to see if we have ACCESS_FINE_LOCATION permission; if not, request.
get FusedLocationProviderClient
get a start location from getLastLocation(); for purposes of comparison and start of track
define locationCallback() to be called by fusedLocationProvider; all we are interested in is getting the last one in the stack and save to class Field.
define LocationRequest with interval of 5 secs and PRIORITY_HIGH_ACCURACY
check to see if the user device is allowing this; not sure what to do with this other than to notify user if not allowed.
now requestLocationUpdates using the LocationCallback defined above.
when user performs action needing current lat/long (e.g. press button), retrieve class field populated with Location object on last LocationCallback().
I am very open to feedback on this pattern. Hope it helps others (as there is a plethora of questions about this). And would love to hear about any problems with this design or issues that I may encounter.
if (Build.VERSION.SDK_INT >= 23) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_ASK_PERMISSIONS);
} else {
// getFusedLocationProviderClient
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
// getStartLocation
fusedLocationProviderClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
StartLocation.set(location);
}
}
}).addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
// Define LocationCallback
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
LastLocation = locationResult.getLastLocation();
}
}
};
// Now lets request location updates - that is how this must happen
// https://developer.android.com/training/location/change-location-settings
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(1000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Attempt to see if requested settings are compatible with user device.
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(locationRequest);
// Check to see if location settings are satisfied by user's device settings?
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> locationTask = client.checkLocationSettings(builder.build())
.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
}
}).addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
}
Toast.makeText(MainActivity.this, "Location Settings Are Not " +
"Correct On This Device", Toast.LENGTH_LONG).show();
}
});
// Request location updates
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
}
}

Mocking location on Android 8.0 (Oreo)

I have an application (call it A) that runs a service that mocks the location obtained from a bluetooth GPS in order to use it in another application (call it B):
A (with service that gets bluetooth GPS location)
Mock location in android system
B (get location from Android System)
Everything works on Android 7.0, but in Android 8.0 (Oreo) the application B does not read the location obtained from the bluetooth, that is, I think, beacuse of a problem in mocking the location, because the log always prints this line:
E PassiveLocationListener_FLP: isFromMockProvider, return
The code I'm using to mock the location is:
private void changeToMockLocation() {
Log.i(TAG, "changeToMockLocation()");
Location newLocation = new Location(PROVIDER_NAME);
newLocation.setLatitude(mNMEAData.getLatitude());
newLocation.setLongitude(mNMEAData.getLongitude());
newLocation.setAccuracy(mNMEAData.getAccuracy());
newLocation.setTime(System.currentTimeMillis());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
newLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
}
// Set mock location.
if (ActivityCompat.checkSelfPermission(
mContext, android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
try {
mLocationManager.setTestProviderLocation(PROVIDER_NAME, newLocation);
} catch (Exception e) {
Log.e(TAG, "Error while setting test provider location: " + e);
}
}
}
The thing is, I don't see the exception printed, so I think the process is right but is like Android doesn't allow me to do so for some reason I can't figure out.
In the manifest I declared the ALLOW_MOCK_LOCATION permission, and the app is allowed to mock location in Developer Settings.
What am I doing wrong?
Thanks in advance and have a nice day.
There seems to be a bug in the (Samsung?) Developer Settings screen in Oreo. I also had my app set up as mock provider and with the permission in the manifest. For me the problem was solved by removing the app as mock location provider and adding it back again:
Developer options -> Mock location app -> No apps
Developer options -> Mock location app -> Your app
I still see these messages in the logcat though:
E/PassiveLocationListener_FLP: isFromMockProvider, return
I/LocationManagerService: remove xxxxxxx
I/LocationManagerService: removeUpdates, receiver.requestedID = xxxxxxx, receiver.mIdentity.mPid = 2908, receiver.mIdentity.mUid = 1000
D/SLocation: removeGpsStatusListener
D/ListenerMonitor_FLP: removeListener, not existed listener android, xxxxxxx in mListenerIdMap
E/RequestManager_FLP: [LocationManagerService] Location remove xxxxxxx from system

LocationManager and LocationClient together to get user location

I simply need to get the user location. Preferably the exactly location, but if it's not possible, a rough location would be fine.
According to the docs:
LocationClient.getLastLocation()
Returns the best most recent location currently available.
and
LocationManager.getLastKnownLocation(String)
Returns a Location indicating the data from the last known location fix obtained from the given provider.
If my understanding is right, the former will give me a very good result (or null sometimes) while the latter will give me a result which would rarely be null.
This is my code (simplified)
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationClient = new LocationClient(this, this, this);
#Override
public void onConnected(Bundle dataBundle) {
setUserLocation();
}
private void setUserLocation() {
myLocation = locationClient.getLastLocation();
if (myLocation == null) {
myLocation = locationManager.getLastKnownLocation(locationManager.getBestProvider(new Criteria(), false));
if (myLocation == null) {
//I give up, just set the map somewhere and warn the user.
myLocation = new Location("");
myLocation.setLatitude(-22.624152);
myLocation.setLongitude(-44.385624);
Toast.makeText(this, R.string.location_not_found, Toast.LENGTH_LONG).show();
}
} else {
isMyLocationOK = true;
}
}
It seems to be working but my questions are:
Is my understanding of getLastLocation and getLastKnownLocation correct?
Is this a good approach?
Can I get in trouble using both in the same activity?
Thanks
LocationClient.getLastLocation() only returns null if a location fix is impossible to determine. getLastLocation() is no worse than getLastKnownLocation(), and is usually much better. I don't think it's worth "falling back" to getLastKnownLocation() as you do.
You can't get into trouble using both, but it's overkill.
Of course, you have to remember that LocationClient is part of Google Play Services, so it's only available on devices whose platform includes Google Play Store. Some devices may be using a non-standard version of Android, and you won't have access to LocationClient.
The documentation for Google Play Services discusses this in more detail.

Android app crashes when retrieving Last Known Location with Location Manager for GPS

To be clear: This is an activity in my Android application that is meant to pull the coordinates for the users location using the GPS_PROVIDER. The Activity contains a button which, when pressed, should initiate a method that obtains the coordinate data. The problem is that the application crashes when there is no previously known location information (ie if the phone was recently reset). If I open up the Maps application (for example) and pinpoint my location, then re-open my own application and run this method, it works as intended. My question is why is this crashing and/or how can I prevent this crash from occurring? Help is appreciated, thanks.
This method is run when the button is pressed - and an intent response is generated back to the calling activity when the coordinates are properly found:
protected void getCurrentLocation() {
Location location = null;
try {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (IllegalArgumentException iae) { }
if (location != null) {
longV = location.getLongitude();
latV = location.getLatitude();
response(longV, latV);
} else {
getCurrentLocation();
}
I'm guessing that you are receiving a StackOverflowException, because if location is null you call the exact same function creating an indefinite loop...
If there is no last know location, you need to request a new location. (getLastKnownLocation() will not change on its own no matter how many times you call it.)

Categories

Resources