B4A Library FusedLocationProvider

FusedLocationProvider is Android's latest attempt to improve the location services available to your applications.

Official documentation can be found here: https://developer.android.com/google/play-services/location.html.

This library depends on the Google Play Services library, android-support-v4 library and the GPS library.
The GPS library is required in order to use it's Location object.

FusedLocationProvider
Events:

  • ConnectionFailed (ConnectionResult1 As Int)
  • ConnectionSuccess
  • ConnectionSuspended (SuspendedCause1 As Int)
  • LocationChanged (Location1 As Location)
  • LocationSettingsChecked (LocationSettingsResult1 As LocationSettingsResult)
Fields:
  • ConnectionResult As ConnectionResult
    Contains the various ConnectionResult constants.
  • SuspendedCause As SuspendedCause
    Contains the various SuspendedCause constants.
Methods:
  • CheckLocationSettings (LocationSettingsRequest1 As LocationSettingsRequest)
    Checks if the relevant system settings are enabled on the device to carry out the desired location requests.
    Raises the event:
    LocationSettingsChecked(LocationSettingsResult1 As LocationSettingsResult)
  • Connect
    Attempt to connect to the Location Services.
    Will raise either event:
    ConnectionFailed(ConnectionResult1 As Int)
    ConnectionSuccess
  • Disconnect
    Disconnect from the Location Services.
  • GetLastKnownLocation As Location
    Returns the best most recent location currently available.
    Can only be called if the FusedLocationProvider is connected.
    The returned Location object will not be initialized if no last known location is available.
  • Initialize (EventName As String)
    Initialize the FusedLocationProvider object.
  • IsConnected As Boolean
    Returns whether the FusedLocationProvider is connected to the Location Services.
  • IsConnecting As Boolean
    Returns whether the FusedLocationProvider is trying to connect to the Location Services.
  • IsInitialized As Boolean
  • RemoveLocationUpdates
    Remove all requests for location updates.
  • RequestLocationUpdates (LocationRequest1 As LocationRequest)
    Request for location updates.
    The LocationRequest object defines the criteria for which location updates are requested.

This is the main library object.
You call the FusedLocationProvider Initialize method and then it's Connect method.
It will then raise the ConnectionFailed event or the ConnectionSuccess event.
Assuming the ConnectionSuccess event is raised you can now call:
  • GetLastKnownLocation As Location
  • RequestLocationUpdates (LocationRequest1 As LocationRequest)

So you could connect, get the last known location and then disconnect.
There is no requirement to request location updates.
This is a quick and simple way to get the device location.

Or you could connect then initialize and configure a LocationRequest object and then request location updates.
The LocationRequest object has various methods you can call to configure the request for location updates:

LocationRequest
Fields:

  • Priority As Priority
    Contains the various priority constants.
Methods:
  • GetExpirationTime As Long
    Get the request expiration time, in milliseconds since boot.
  • GetFastestInterval As Long
    Get the fastest interval of this request, in milliseconds.
  • GetInterval As Long
    Get the desired interval of this request, in milliseconds.
  • GetNumUpdates As Int
    Get the number of updates requested.
  • GetPriority As Int
    Get the quality of the request.
  • GetSmallestDisplacement As Float
    Get the minimum displacement between location updates in meters.
    By default this is 0.
  • Initialize
    Initialize the LocationRequest with default parameters.
    Default parameters are for a block accuracy, slowly updated location.
  • IsInitialized As Boolean
  • SetExpirationDuration (Millis As Long) As LocationRequest
    Set the duration of this request, in milliseconds.
  • SetExpirationTime (Millis As Long) As LocationRequest
    Set the request expiration time, in millisecond since boot.
  • SetFastestInterval (Millis As Long) As LocationRequest
    Explicitly set the fastest interval for location updates, in milliseconds.
  • SetInterval (Millis As Long) As LocationRequest
    Set the desired interval for active location updates, in milliseconds.
  • SetNumUpdates (NumUpdates As Int) As LocationRequest
    Set the number of location updates.
  • SetPriority (Priority As Int) As LocationRequest
    Set the priority of the request.
  • SetSmallestDisplacement (SmallestDisplacementMeters As Float) As LocationRequest
    Set the minimum displacement between location updates in meters.
    By default this is 0.

It is important to note that part of the criteria that defines your request for a location is the location permission that you (manually) set in the manifest file.
This library does not automatically add any permission to your manifest and this library will fail to work if you do not manually add a required permission to your manifest file.

You can add one of two permissions to your manifest:
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION

See: https://developer.android.com/training/location/retrieve-current.html
Apps that use location services must request location permissions.
Android offers two location permissions: ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION.
The permission you choose determines the accuracy of the location returned by the API.
If you specify ACCESS_COARSE_LOCATION, the API returns a location with an accuracy approximately equivalent to a city block.

Also note that as this library uses the Google Play Services library, you must also add this entry to your manifest:

B4X:
AddApplicationText(<meta-data
    android:name="com.google.android.gms.version"
    android:value="@integer/google_play_services_version" />)

Two versions of the library are attached.
  • If you're using a version of Google Play Services older than version 27 then you need to use FusedLocationProvider version 1.10.
  • If you're using Google Play Services version 27 or newer then you need to use FusedLocationProvider version 1.30 or newer

Martin.

Edit by Erel:
Add these two lines if using with B4A v6+:
B4X:
#AdditionalJar: com.android.support:support-v4
#AdditionalJar: com.google.android.gms:play-services-location
New example where FLP is managed from the starter service: https://www.b4x.com/android/forum/threads/fusedlocationprovider.50614/post-717726
 

Attachments

  • FusedLocationProvider_library_files_v1.10.zip
    19.3 KB · Views: 2,242
  • FusedLocationProvider_library_files_v1.31.zip
    20 KB · Views: 3,321
Last edited by a moderator:

imbault

Well-Known Member
Licensed User
Longtime User
@warwound,
It's your example project : 20150329.zip

For the libs:

upload_2015-11-7_11-35-14.png
 

imbault

Well-Known Member
Licensed User
Longtime User
FusedLoactionProvider 1.20 along with Google Play Service V28 is working fine for me.

Yesterday evening I updated my Google Play Service to V28. So far its working fine for me.

Regards
Anser
Hi @Anser , can you please, send me a tiny project, in order to try FusedLocationProvider, if it doesn't work, I will reinstall all Android SDK

Thanks

Patrick
 
Last edited:

Anser

Well-Known Member
Licensed User
Longtime User
Extracted the code from my original huge Activity Code. Haven't tested after extracting it from my Activity, but this is what basically I use in my Activity. I just copy pasted here. I hope that it will work for you.
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
  

    Private FusedLocationProvider1 As FusedLocationProvider
    Private LastLocation As Location  
  
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.

    Private LblLastLocation As Label  
End Sub


Sub Activity_Create(FirstTime As Boolean)

    If FirstTime Then
        FusedLocationProvider1.Initialize("FusedLocationProvider1")
    End If  
  
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("StartEndTravel")

    If LastLocation.IsInitialized Then
        UpdateUI
    End If  
End Sub

Sub Activity_Resume
    '    attempt to connect to the location services
    '    after calling Connect we are waiting for either ConnectionFailed or ConnectionSuccess events
    FusedLocationProvider1.Connect
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    FusedLocationProvider1.Disconnect
End Sub

Sub FusedLocationProvider1_ConnectionFailed(ConnectionResult1 As Int)
    Log("FusedLocationProvider1_ConnectionFailed")
  
    '    the FusedLocationProvider ConnectionResult object contains the various CoonectionResult constants
  
    Select ConnectionResult1
        Case FusedLocationProvider1.ConnectionResult.NETWORK_ERROR
            '    a network error has occurred, this is likely to be a recoverable error
            '    so try to connect again
            FusedLocationProvider1.Connect
        Case Else
            '    TODO handle other errors
    End Select
End Sub

Sub FusedLocationProvider1_ConnectionSuccess
    Log("FusedLocationProvider1_ConnectionSuccess")
    Dim LocationRequest1 As LocationRequest
    LocationRequest1.Initialize
    LocationRequest1.SetInterval(1000)    '    1000 milliseconds
    LocationRequest1.SetPriority(LocationRequest1.Priority.PRIORITY_HIGH_ACCURACY)
    LocationRequest1.SetSmallestDisplacement(1)    '    1 meter
  
    Dim LocationSettingsRequestBuilder1 As LocationSettingsRequestBuilder
    LocationSettingsRequestBuilder1.Initialize
    LocationSettingsRequestBuilder1.AddLocationRequest(LocationRequest1)
    FusedLocationProvider1.CheckLocationSettings(LocationSettingsRequestBuilder1.Build)
  
    FusedLocationProvider1.RequestLocationUpdates(LocationRequest1)
End Sub

Sub FusedLocationProvider1_ConnectionSuspended(SuspendedCause1 As Int)
    Log("FusedLocationProvider1_ConnectionSuspended")
  
    '    the FusedLocationProvider SuspendedCause object contains the various SuspendedCause constants
  
    Select SuspendedCause1
        Case FusedLocationProvider1.SuspendedCause.CAUSE_NETWORK_LOST
            '    TODO take action
        Case FusedLocationProvider1.SuspendedCause.CAUSE_SERVICE_DISCONNECTED
            '    TODO take action
    End Select
End Sub

Sub FusedLocationProvider1_LocationChanged(Location1 As Location)
    Log("FusedLocationProvider1_LocationChanged")
    LastLocation=Location1
    UpdateUI
End Sub

Sub FusedLocationProvider1_LocationSettingsChecked(LocationSettingsResult1 As LocationSettingsResult)
    Log("FusedLocationProvider1_LocationSettingsChecked")
    Dim LocationSettingsStatus1 As LocationSettingsStatus=LocationSettingsResult1.GetLocationSettingsStatus
    Select LocationSettingsStatus1.GetStatusCode
        Case LocationSettingsStatus1.StatusCodes.RESOLUTION_REQUIRED
            Log("RESOLUTION_REQUIRED")
            '    device settings do not meet the location request requirements
            '    a resolution dialog is available to enable the user to change the settings
            Msgbox("It looks like that you have disabled GPS. On the next screen, it will ask you to enable GPS. Please choose 'Yes', Do not use the option 'Never'","GPS is disabled")
            LocationSettingsStatus1.StartResolutionDialog("LocationSettingsResult1")
        Case LocationSettingsStatus1.StatusCodes.SETTINGS_CHANGE_UNAVAILABLE
            Log("SETTINGS_CHANGE_UNAVAILABLE")
            '    device settings do not meet the location request requirements
            '    a resolution dialog is not available to enable the user to change the settings
            Msgbox("Unable to listen for location updates, device does not meet the requirements.", "Problem")
            Activity.Finish
        Case LocationSettingsStatus1.StatusCodes.SUCCESS
            Log("SUCCESS")
            '    device settings meet the location request requirements
            '    no further action required
    End Select
End Sub

Sub LocationSettingsResult1_ResolutionDialogDismissed(LocationSettingsUpdated As Boolean)
    Log("LocationSettingsResult1_ResolutionDialogDismissed")
    If Not(LocationSettingsUpdated) Then
        '    the user failed to update the device settings to meet the location request requirements
            Msgbox("Unable to listen for location updates, you failed to enable the required device settings.", "Problem")
        Activity.Finish
    End If
End Sub

Sub UpdateUI
    'Label LblLastLocation is used to display the lat an long
    LblLastLocation.Text="Date : "&DateTime.Date(LastLocation.Time)& "  Time : "&DateTime.Time(LastLocation.Time)

End Sub

Regards
Anser
 

imbault

Well-Known Member
Licensed User
Longtime User
@Anser, thank you very much, but anyway I put that piece of code in any new, or old project, I always get that bloody error:
** Activity (main) Create, isFirst = true **
main_activity_create (java line: 388)
java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/util/ArrayMap;
at com.google.android.gms.common.api.GoogleApiClient$Builder.<init>(Unknown Source)
at uk.co.martinpearman.b4a.fusedlocationprovider.FusedLocationProvider.<init>(FusedLocationProvider.java:36)
at uk.co.martinpearman.b4a.fusedlocationprovider.FusedLocationProviderWrapper.Initialize(FusedLocationProviderWrapper.java:172)
at com.pim.sgs.main._activity_create(main.java:388)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
at com.pim.sgs.main.afterFirstLayout(main.java:102)
at com.pim.sgs.main.access$000(main.java:17)
at com.pim.sgs.main$WaitForLayout.run(main.java:80)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.util.ArrayMap" on path: DexPathList[[zip file "/mnt/asec/com.pim.sgs-6/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
... 18 more
Suppressed: java.lang.ClassNotFoundException: android.support.v4.util.ArrayMap
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 19 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available

Just become crazy...
 

warwound

Expert
Licensed User
Longtime User
@imbault

Something must have changed within the Google Play Services library and it now depends on the android-support-v4 library.
To be more precise the GoogleApiClient.Builder class seems to depend on it.

The existing demo projects fail to run on my Moto G (lollipop) giving the same error as you posted:

java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/util/ArrayMap;

Here's a solution:

B4X:
#Region  Project Attributes 
	#ApplicationLabel: FusedLocationProvider example
	#VersionCode: 1
	#VersionName: 
	'SupportedOrientations possible values: unspecified, landscape or portrait.
	#SupportedOrientations: unspecified
	#CanInstallToExternalStorage: False
	#AdditionalRes: C:\Users\martin\AppData\Local\Android\sdk\extras\google\google_play_services\libproject\google-play-services_lib\res, com.google.android.gms
	#AdditionalJar: android-support-v4.jar
#End Region

See where i have added the line #AdditionalJar: android-support-v4.jar?
That seems to be all that is required.

You must have the android-support-v4.jar file in your b4a additional libraries folder - and it'd be a good idea to ensure that it's the latest version of the v4 support library.
You can do that by running the android SDK manager, ensuring that everything is up to date and then copying android-support-v4.jar from the SDK folder to your b4a additional libraries folder.
The v4 support library .jar is located at <Android SDK Path Here>\extras\android\support\v4

Try that and post with your results.
 

Anser

Well-Known Member
Licensed User
Longtime User
@imbault

Something must have changed within the Google Play Services library and it now depends on the android-support-v4 library.
To be more precise the GoogleApiClient.Builder class seems to depend on it.

The existing demo projects fail to run on my Moto G (lollipop) giving the same error as you posted:

How come it is running fine on my Samsung Note 4 (Lollypop) ?. Is it because that android-support-v4 library is already included in my project, because I use GoogleMaps, AppCompat etc in my app which is already depended on android-support-v4 library ?

Anyway, it is working fine without having the following line
B4X:
#AdditionalJar: android-support-v4.jar

To avoid problem when my app is run on various other devices, do you recommend me to add the following line in my project ?
B4X:
#AdditionalJar: android-support-v4.jar
Or will it be a duplication ?

As I already told above, that, my project uses AppCompat, GooglePlayServices, GoogleMaps etc which are already depended on android-support-v4 library, is it OK if I don't add the above line ?

Regards
Anser
 

warwound

Expert
Licensed User
Longtime User
How come it is running fine on my Samsung Note 4 (Lollypop) ?. Is it because that android-support-v4 library is already included in my project, because I use GoogleMaps, AppCompat etc in my app which is already depended on android-support-v4 library ?

Yes, if another library has included the v4 support library then you'll not need to manually include it for FusedLocationProvider.

Manually adding the AdditionalJar attribute will not cause any problem, there won't be any unnecessary duplicate library code added to your compiled project.
 

warwound

Expert
Licensed User
Longtime User
FusedLocationProvider updated to version 1.30

At some point in time Google have updated the GoogleApiClient class and this class is used by FusedLocationProvider.
This class update means that FusedLocationProvider now depends on the android v4 support library.

Version 1.30 of FusedLocationProvider simply adds the android v4 support library as a dependency, no other changes have been made.

So in order to use FusedLocationProvider you need to either:
  • Add the AdditionalJar project attribute as described in post 65.
  • Update to version 1.30 of FusedLocationProvider.

Additionally, your b4a additional libraries folder must contain the android-support-v4.jar library file.

Version 1.30 of FusedLocationProvider is attached to the first post in this thread.
 

Croïd

Active Member
Licensed User
Longtime User
Hello,
My Location " MyLocationEnabled "works with android M + FusedLocation 1.30 , but not on android 4.4 et Lollipop !

am I alone? Dot not appear

For now I'll use :


B4X:
 If Location1.Latitude = 0 Or Location1.Longitude = 0 Then
    Dim result As Int
    result = Msgbox2("try another mode ?","Error GPS ! ","OK","","NO",Null)
    If result = DialogResponse.POSITIVE Then
    Gps1.Initialize("Gps")
    Gps1.Start(0,0)
    FusedLocationProvider1.Disconnect
    ProgressDialogShow2(ResourceStrings.Get("Apps_Wait"),True)
    If result = DialogResponse.NEGATIVE Then
    FusedLocationProvider1.Connect
    Gps1.Stop
    End If
 
Last edited:

Croïd

Active Member
Licensed User
Longtime User
Hello,
My Location " MyLocationEnabled "works with android M + FusedLocation 1.30 , but not on android 4.4 et Lollipop !

Surely a problem with another library because work very well with different test
 

Croïd

Active Member
Licensed User
Longtime User
If possible clear cache in internal storage/clear cache.
Because if GPS Turn OFF, the position is activated and i must clear cache for reset
 

warwound

Expert
Licensed User
Longtime User
I see no way to clear the previous location cache - there's no methods that do this.

GetLastKnownLocation returns the last know location.
The returned location will not be initialized if no (cached) last location exists.

But there's no way to clear that cached last location (that i know of).
 

Croïd

Active Member
Licensed User
Longtime User
Thanks Warwound, I'll try to find a trick
 
Last edited:

ValDog

Active Member
Licensed User
Longtime User
Warwound, I ran into real problems when I recently updated my Android SDK files. I don't know how to reference my discussion in the form other than directing you to my "Crash upon installation to Nexus 7" question in the B4A Questions. Please check it out and let me know what you think...
 
Top