Android Question FusedLocationProvider -> .getProvider()

mo_alex

Member
Licensed User
Hello, everyone. I have a question about the FusedLocationProvider.

I would like to filter out positions in the LocationChanged event that do not have GPS as location source. The native location-object in Android Studio provides the method getProvider() for this. In B4A this method is missing, as well as other methods like getExtras(). Why are these methods not available in B4A and will these methods be available in the future?

Note: The screenshots from Android Studio are taken from an FLP code example.


Best regards, Alex.
 

Attachments

drgottjr

Well-Known Member
Licensed User
2 answers:

i believe the easiest way to filter out gps is not to permit high accuracy. that is, you turn location on in your settings, but you don't set high accuracy. the result should be you only get wifi, network. try it.

the second answer tells you how to access the native location object returned by FLP's Location_Changed event.
as to why the methods you're interested in are not exposed in the library, you'll have to ask the author. but the methods are public, so you can access them yourself. as far as getProvider() is concerned, you're not going to like what you see. the code snippet below shows how to find out who the provider was for the last location. you can probably extrapolate from there to get your getExtras().

B4X:
    Public Sub Location_Changed (loc As Location)
    lblLocation.Text = $"$1.2{loc.Latitude} / $1.2{loc.Longitude}"$
    
    Dim lobj As JavaObject
    lobj.InitializeNewInstance("android.location.Location", Array( loc ))
    Dim provider As String = lobj.RunMethod("getProvider", Null)
    Log("location provided by your friendly provider: " & provider)
End Sub
replace the Location_Changed sub with the above (or just add the 4 lines i cobbled together).

you need to use the deprecated geolocation api to filter by provider. google wants us to use flp instead. there is (or, perhaps, are) such libraries here, but it needs to be modified. the assumption is that a person is interested in simply geolocating herself, not ignoring locations reported by certain providers.
 

mo_alex

Member
Licensed User
First of all, thanks for the feedback.

The other way round: I don't want to discard the GPS positions, but all non-GPS positions (network and wifi) should be discarded.
But I don't want to give up the high accuracy for this, because otherwise the sensors will not be used.

The normal FusedLocationProviderApi is now deprecated. FusedLocationProviderClient seems to be the most current and recommended API.
But why shouldn't it be possible with the current API (FusedLocationProviderClient) to request the provider of a location?
 

drgottjr

Well-Known Member
Licensed User
it's in the name: fused. fused is the provider (did you run my example?)

sorry, i misread what you wanted to filter out. turn on high accuracy in your device settings and, if you're outside (and not visiting lascaux II), you should get the position as "provided" by your gps.

if all you want is gps, work with a gps api. if, in addition, you need geolocation, you tack on some geolocation code. frankly, it's an abuse to geolocate a position on every change, since the geolocation will be the same. and if you're on a map, you might not even need geolocation, just positioning on the map. in my case, i signal i've found my position (via gps), and then call a geolocator to get an address. i wrote my mapping app years ago when only gps was available. still works just fine. later on, as google exposed its cache of wifi location tricks, i added that. eventually, flp was made available with the purpose of "fusing" all the providers. you want to go backwards by unfusing. i'm not saying that's a bad thing; it just may be the wrong tool for what you're after.

i realize the original flp api is deprecated. b4a wraps to such apis don't appear by magic; an interested party will create a wrap and (often) post it for our use. you are welcome to do the same. you can expose or hide whatever methods and properties you choose to. years later somone will ask why your wrap doesn't expose this method or the other...
 

mo_alex

Member
Licensed User
it's in the name: fused. fused is the provider (did you run my example?)
Okay, I see what you meant. The provider is: fused.


if you're outside (and not visiting lascaux II)
🤠👍


But can't I use getExtras to find out the provider? If it was a GPS position, there would have to be a number of satellites among the extras, wouldn't there?


I have tried to get the extras of the loaction object:
getExtras:
Dim lobj As JavaObject
lobj.InitializeNewInstance("android.location.Location", Array( Location1 ))
Dim extras As JavaObject = lobj.RunMethod("getExtras", Null)
Log("extras: " & extras)

But the log shows me:
extras: (Bundle) Bundle[mParcelledData.dataSize=52]

Is there a way to look into this ParcelledData?
 

drgottjr

Well-Known Member
Licensed User
the documentation implied that you won't get much from it, as its content is dependent on what the provider wants to provide. (i'm guessing nothing).
you've returned the "bundle" as a javaobject. if you look at the documentation for this type of bundle, you should be able to access its properties: eg,
extras.thisproperty, extras.thatproperty. maybe even extras.runmethod("tellMeMore", null) ...
 

drgottjr

Well-Known Member
Licensed User
bundle may be a map. see if you can step through the keys. you might have to dim a map and set extras = to it. using extras alone might work. do you know how to step through the keys of a map?
 

drgottjr

Well-Known Member
Licensed User
it is a map of sorts. and it does have a toString() method. you'll need to fool with it a bit.
 

drgottjr

Well-Known Member
Licensed User
i add this:
B4X:
    Dim bundler As JavaObject
    bundler.InitializeNewInstance("android.os.Bundle", Array( extras ))
    
    Dim bundle As Int = bundler.RunMethod("describeContents",Null)
    Log("extras: " & bundle)
to test a little. my bunderler object is a new bundle, based on extras (from previous runmethod()). toString() just gave me the vague Bundle message you've already seen. to i tried a different method, one that would return something i was expecting. "describeContents" is supposed to return 0 or some particular value. it returned 0, so i'm sure my bundler object is correct. (app would have crashed had the return value not been initialized). so you'll have to fool around with the keys and values. "satellites" might be a good starting point.

it looks like toString() is just that vague message reporting 52 bytes. i've seen similar things before (ie, logging an object gets you a stringified version).
 

drgottjr

Well-Known Member
Licensed User
so, i've tried things a vew different ways. trying to read key/values of the getExtras() Bundle is responding in the way the documentation says it will respond when it has nothing to say (which is what i expected). i'm satified i'm querying the correct object in the correct way. your luck may be different if you stay with it.

as for me, i'm giving up on this one, if you don't mind. if i want gps readings, i use gps, which is what i do. i don't believe your use of the fusedlocationprovider is what google had in mind when they foisted it on us. just sayin'
 

mo_alex

Member
Licensed User
A big thank you for your kindness. I'm gonna keep on trying for a while. Otherwise I will probably use the pure GPS API. Thanks again, you have helped me a lot :)
 

mo_alex

Member
Licensed User
The reason why I wanted to filter out non-GPS positions is the following: In motion the tracking seems to work well with the FLP. The problem arises when the device is not moved. For example, if I select 50 meters as the minimum distance for a new position, I would expect that no new position would be detected if the device is not moved. But this is not the case. Even if the device is not moved and I have selected a minimum distance of 50 meters, new positions are still detected. On the map "stars" are created. I suspect that these positions come from surrounding WLAN routers. These would then be 100-200 meters away and the FLP would report a new position.

If I could determine the provider, then I could filter out these location jumps (due to the surrounding routers) and could probably avoid the "stars" on the map.
 

drgottjr

Well-Known Member
Licensed User
just to "provide" some closure to the original issue, i can see what's in the bundle. although not mentioned in the Location-related getExtras() Bundle, i found that android.os.Bundle has keySet() and get() methods, not unlike b4a's map. if you get the bundle with location.getExtras(), you can get the bundle's keySet() and you can see what the keys are. (they're declared as String). with gps as the location provider, i could see that the "satellites" key is used. as discusssed, since fused is the location provider, you're not going to see that.

i plugged some code into a different location app, one not using flp. i'll see about plugging it into the flp example i sent to you. that 52-byte bundle might just contain some nugget you can use. if the bundle is always the same, then its contents aren't going to help. but maybe fused indicates which provider was used. we couldn't see it the other day because we couldn't read the bundle. since the keys are now visible, maybe there's something there.

note: the keys in keySet() are strings, so no big deal. unfortunately, the values are yet again another bundle whose keys/values we don't know. so it means more digging to reveal the values even if you have the keys. hope this is all clear.
 
Top