B4A Library FusedLocationProvider

warwound

Expert
Licensed User
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

Last edited by a moderator:

warwound

Expert
Licensed User
This is an example that shows syntax and basic usage of the FusedLocationProvider.

The activity connects to the locations services and requests location updates with an interval of 1000 milliseconds and a 'SmallestDisplacement' of 1 meter.
As location updates are received a Label shows the latest location's time, latitude and longitude.

B4X:
Sub Process_Globals
	Private FusedLocationProvider1 As FusedLocationProvider
	Private LastLocation As Location
End Sub

Sub Globals
	Private LastLocationLabel As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)
	'	**	IMPORTANT see manifest for required entries	**
	If FirstTime Then
		FusedLocationProvider1.Initialize("FusedLocationProvider1")
	End If
	
	Activity.LoadLayout("Main")

	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
	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 UpdateUI
	LastLocationLabel.Text=DateTime.Time(LastLocation.Time)&" ("&LastLocation.Latitude&", "&LastLocation.Longitude&")"
End Sub
Martin.
 

Attachments

Last edited:

warwound

Expert
Licensed User
The Location object passed to the LocationChanged sub has an Accuracy property you can use to determine the accuracy.
 
Last edited:

Shay

Well-Known Member
Licensed User
it looks similar to the locationAPI library
what is the difference between them?
 

warwound

Expert
Licensed User
it looks similar to the locationAPI library
what is the difference between them?
See my post here:
http://www.b4x.com/android/forum/th...e-low-power-location.29700/page-6#post-316394

The API used by the LocationAPI no longer exists.
The LocationAPI will probably still work if you use an old version of the Google Play Services library(though i have not tested this).
But if you use the current version of the Google Play Services library then the LocationAPI library will fail.
You'll see an exception such as:
java.lang.NoClassDefFoundError: uk.co.martinpearman.b4a.android.gms.location.subclasses.LocationClient
So the FusedLocationProvider is much the same as the LocationAPI but works with the current Google Play Services.
 

gudino jose luis

Active Member
Licensed User
hi
I have this little problem
I have the version 21 of Google Play Services and shows me this message:

java.lang.NoClassDefFoundError: uk.co.martinpearman.b4a.android.gms.location.subclasses.LocationClient

but only when I debug
when I run without debugging it is perfect

note:I'm using FusedLocationProvider
 

warwound

Expert
Licensed User
java.lang.NoClassDefFoundError: uk.co.martinpearman.b4a.android.gms.location.subclasses.LocationClient
That exception can only occur if you use the old LocationAPI - that class is only part of the old LocationAPI, it's not part of the FusedLocationProvider.

Have you got both libraries checked in the b4a IDE?
 

gudino jose luis

Active Member
Licensed User
Thank you for your answers and time.

I have just checked a library FusedLocationProvider.

when I debug (legacy) this message is displayed:
java.lang.NoClassDefFoundError: uk.co.martinpearman.b4a.fusedlocationprovider.FusedLocationProvider

when debug (rapid) the program exits without displaying message.

best regards
 

warwound

Expert
Licensed User
There's a very similar problem when using GoogleMapsExtras in debug mode - some classes are not found.
The error occurs because some classes in the Google Play Services library are not found - and classes that depend on these Play Service classes can't be created.

There's no workaround i know of - that makes debugging an activity that depends on a library that depends on Google Play Services tricky.
 

gudino jose luis

Active Member
Licensed User
In fact I was also using Google Maps Extras in debug mode means problems

Install a new version with SDK 21, but gave me many problems when compiling,

Reinstall the previous SDK to version 19 and google play services reinstall the version 15

I can not FusedLocationProvider in debug mode.
I can Google Maps Extras in debug mode.

thanks for your help
 
Last edited:

Shay

Well-Known Member
Licensed User
I had same issue:
java.lang.NoClassDefFoundError: uk.co.martinpearman.b4a.android.gms.location.subclasses.LocationClient

I fixed it by removing old code of LocationApi library and put the new one, base on the example above (the attached project example)
 

gudino jose luis

Active Member
Licensed User
hi

yet I could not solve the problem even get the message
"java.lang.NoClassDefFoundError: uk.co.martinpearman.b4a.fusedlocationprovider.FusedLocationProvider"
I have installed the version SDK 21

any suggestions?
thanks in advance.
 

warwound

Expert
Licensed User
FusedLocationProvider updated to version 1.10

This updates adds support for the Location Settings Dialog that is part of the latest Google Play Services update.
For more info have a read here: http://android-developers.blogspot.co.uk/2015/03/google-play-services-70-places-everyone.html.

You must run the Android SDK Manager and ensure that you have the latest version of Google Play Services installed, and you must also ensure that your copy of the Google Play Services library (google-play-services.jar) in your b4a additional libraries folder is a copy of the latest version.

The FusedLocationProvider has a new method:

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)


You create a LocationSettingsRequest and pass it to this new method.
LocationSettingsRequest is created using the LocationSettingsRequestBuilder object:

LocationSettingsRequestBuilder
Methods:
  • AddLocationRequest (LocationRequest1 As LocationRequest) As LocationSettingsRequestBuilder
    Adds one LocationRequest that the client is interested in.
    This method can be called multiple times if required to add additional location requests.
  • Build As LocationSettingsRequest
    Creates a LocationSettingsRequest.
  • Initialize
  • IsInitialized As Boolean
  • SetNeedBle (NeedBle As Boolean) As LocationSettingsRequestBuilder
    Sets whether the client wants BLE to be enabled.

The LocationSettingsChecked event is raised and passed a LocationSettingsResult object:

LocationSettingsResult
Methods:
  • GetLocationSettingsStates As LocationSettingsStates
    Returns the location settings states.
  • GetLocationSettingsStatus As LocationSettingsStatus
    Returns the location settings result status.
  • IsInitialized As Boolean

The LocationSettingsStates object details exactly which location services are available and enabled on the device:

LocationSettingsStates
Methods:
  • IsBlePresent As Boolean
    Whether BLE is present on the device.
  • IsBleusable As Boolean
    Whether BLE is enabled and is usable by the app.
  • IsGpsPresent As Boolean
    Whether GPS provider is present on the device.
  • IsGpsUsable As Boolean
    Whether GPS provider is enabled and is usable by the app.
  • IsInitialized As Boolean
  • IsLocationPresent As Boolean
    Whether location is present on the device.
    This method returns true when either GPS or network location provider is present.
  • IsLocationUsable As Boolean
    Whether location is enabled and is usable by the app.
    This method returns true when either GPS or network location provider is usable.
  • IsNetworkLocationPresent As Boolean
    Whether network location provider is present on the device.
  • IsNetworkLocationUsable As Boolean
    Whether network location provider is enabled and usable by the app.

And the LocationSettingsStatus object details whether the device's current settings meet the requirements for your LocationRequest object(s):

LocationSettingsStatus
Events:
  • ResolutionDialogDismissed (LocationSettingsUpdated As Boolean)
Fields:
  • StatusCodes As StatusCodes
    Contains the various StatusCode constants.
Methods:
  • GetStatusCode As Int
    Returns the status code that describes whether the location settings meet the location request requirements.
  • IsInitialized As Boolean
  • StartResolutionDialog (EventName As String)
    Starts the resolution dialog.
    The user can then enable the location settings required to meet the location request requirements.
    This method must be called from an Activity.
    Raises the event:
    ResolutionDialogDismissed(LocationSettingsUpdated As Boolean)

The StatusCode is the value to look at:

StatusCodes
Fields:
  • RESOLUTION_REQUIRED As Int
    Location settings do not meet the location request requirements.
    Location settings can be changed to meet the location request requirements.
    A resolution dialog is available.
  • SETTINGS_CHANGE_UNAVAILABLE As Int
    Location settings do not meet the location request requirements.
    Location settings can't be changed to meet the location request requirements.
    No resolution dialog is available.
  • SUCCESS As Int
    Location settings meet the location request requirements.

The LocationSettingsStatus object contains the all important StartResolutionDialog method that shows the user a dialog which enables them to adjust the device location settings.

The StartResolutionDialog method must be called from an Activity - it cannot be called from a Service.

I've attached 2 b4a example projects to this post.
One example shows how to show the Location Settings Dialog when the FusedLocationProvider is being used within an Activity, the other example shows how to show the dialog when the FusedLocationProvider is being used in a Service.

FusedLocationProvider version 1.10 library files are attached to the first post in this thread.

Martin.
 

Attachments

Cebuvi

Active Member
Licensed User
Hi Martin,

I am using your FusedLocationProvider library for a widget to obtain the coordinates. I would like them to update every hour, I configure the LocationRequest object and all is ok. The problem I found is that when the divice is switched on, the widget obtains lat=0,0 and long=0,0 as the coordinates and it does not update them until after 1 hour.

How can I do for it to first update the coordinates until it find the correct values and then, after that, automatically update then hourly?.

Thanks.

Cesar
 
Top