BlueGPS Android SDK - version 2¶
1. Introduction¶
This document holds a general guide for the integration of the BlueGPS SDK library into an Android application. The BlueGPS SDK implements the communication with the BlueGPS server allowing Android Applications to make use of the system.
[!IMPORTANT]
All the data contained in this document are currently under development and may be subject to change.
2. Integration guide¶
2.1. Requirements¶
Minimum requirements are:
- Minimum SDK: 21
- Usage of Android X
2.2. Adding the Library to an existing Android application¶
Before you add BlueGPS depencencies, update your repositories in the settings.gradle file to include this repository
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
Or if you're using an older project setup, add this repository in your project level build.gradle file:
allprojects {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
Then add the dependency for BlueGPS-SDK in the build.gradle file for your app or module:
dependencies {
implementation 'com.github.synapseslab:android-bluegps-sdk-public:<version>'
}
The version corresponds to release version, for example:
3. Usage guide¶
3.1 Getting Started¶
Your first step is initializing the BlueGPSLib, which is the main entry point for all operations in the library. BlueGPSLib is a singleton: you'll create it once and re-use it across your application.
A best practice is to initialize BlueGPSLib in the Application class:
class App : Application() {
override fun onCreate() {
super.onCreate()
BlueGPSLib.instance.initSDK(
sdkEnvironment = Environment.sdkEnvironment,
context = applicationContext,
enabledNetworkLogs = true
)
}
}
[!NOTE] The BlueGSP-SDK use an
Environmentwhere integrator have to put SDK data for register the SDK and for create a communication with the BlueGPS Server. The management of the environment is demanded to the app.
object Environment {
private val SDK_ENDPOINT = "{{provided-bluegps-endpoint}}"
val keyCloakParameters = KeyCloakParameters(
authorization_endpoint = "https://[BASE-URL]/realms/[REALMS]/protocol/openid-connect/auth",
token_endpoint = "https://[BASE-URL]/realms/[REALMS]/protocol/openid-connect/token",
redirect_uri = "{{HOST}}://{{SCHEME}}",
clientId = "{{provided-client-secret}}", // for user authentication
userinfo_endpoint = "https://[BASE-URL]/realms/[REALMS]/protocol/openid-connect/userinfo",
end_session_endpoint = "https://[BASE-URL]/realms/[REALMS]/protocol/openid-connect/logout",
guestClientSecret = "{{provided-guest-client-secret}}", // for guest authentication
guestClientId = "{{provided-guest-client-id}}" // for guest authentication
)
val sdkEnvironment = SdkEnvironment(
sdkEndpoint = SDK_ENDPOINT,
keyCloakParameters = keyCloakParameters,
)
}
3.2 App Authentication¶
The BlueGPS_SDK offers a client for managing authentication and authorization within your application. It leverages Keycloak to handle user authentication.
BlueGPS provides 2 kinds of authentication:
- User Authentication:
If you want only the User authentication you must set the clientId.
This means that for each device this is the user on Keycloak that can manage grants for this particular user.
- Guest Authentication:
If you want only the Guest authentication, you must set the guestClientSecret and guestClientId.
This means that we don't have a user that has to login but we use client credentials and there is not an individual user for each app install. Instead BlueGPS treats the user account as a "guest" In this case multiple devices can use the same client credentials to be authenticated and BlueGPS will register the user as a device, and not as a formal Keycloak user.
[!NOTE] This paramaters are provided by Synapses after the purchase of the BlueGPS license.
Finally in your AndroidManifest.xml add this and change host and scheme with your configuration.
<activity
android:name="com.synapseslab.bluegps_sdk.authentication.presentation.AuthenticationActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="{HOST}"
android:scheme="{SCHEME}" />
</intent-filter>
</activity>
Now your app is ready for use keycloak. See KeycloakActivity.kt example for an example of login, logout or refresh token.
3.3 Authentication status¶
Once the SDK is correctly setup, you can ask for authentication status, by using the following accessor facility:
currentTokenPayload expose the current token object (if any). You can also ask for validity as follow:
// check if access token is still valid
BlueGPSAuthManager.instance.currentTokenPayload.accessTokenValid
// check if refresh token is still valid
BlueGPSAuthManager.instance.currentTokenPayload.refreshTokenValid
For obtain the current access token use the following function:
3.4 Guest login¶
For exec a guest login use the following function:
when (val result = BlueGPSAuthManager.instance.guestLogin()) {
is Resource.Error -> {
Log.e(TAG, result.message)
}
is Resource.Exception -> {
Log.e(TAG, result.e.localizedMessage ?: "Exception")
}
is Resource.Success -> {
Log.v(TAG, "Login in guest mode, ${result.data}")
loginGuestMode.value = "Login in guest mode"
// update access token on the environment
Environment.sdkEnvironment.sdkToken = result.data.access_token
}
}
3.5 Logout¶
For logout, there's a specific call that will clear all credentials both from your side and backend:
BlueGPSAuthManager.instance.logout(handleCallback = {
if (it) {
Log.d(TAG, "SUCCESS logged out")
} else {
Log.e(TAG, "ERROR logged out")
}
})
4. Use BlueGPS Advertising Service¶
For use the BlueGPS Advertising service, defines callbacks for service binding, passed to bindService()
private val advertisingServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
val binder = service as BlueGPSAdvertisingService.LocalBinder
blueGPSAdvertisingService = binder.serviceBlueGPS
}
override fun onServiceDisconnected(name: ComponentName) {
blueGPSAdvertisingService = null
}
}
Bind to BlueGPSAdvertisingService onStart() function:
override fun onStart() {
super.onStart()
val serviceIntent = Intent(this, BlueGPSAdvertisingService::class.java)
bindService(
serviceIntent,
advertisingServiceConnection,
Context.BIND_AUTO_CREATE
)
}
Clients should unbind from services at appropriate times
For start the advertising call:
or
where androidAdvConfiguration a device configuration for advertising as follow:
data class AndroidAdvConfiguration(
var tagid: String? = null,
var advModes: String? = null,
var advTxPowers: String? = null
)
For stop your service advertising call:
4.1 Get device configuration¶
For obtain a device configuration for advertising call this function:
if you want to submit a specific tag to be bound to your app you can use the following:
suspend fun getOrCreateConfiguration(tagId: "012345678912"): Resource<AndroidAdvConfiguration>
4.2. Optional¶
If you are interested to receiver logs and display info about the status of the Service,
subclass BroadcastReceiver and implement the onReceive(...) method.
The status of the service are: STARTED, STOPPED, ERROR.
private val advertisingServiceReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == BlueGPSAdvertisingService.ACTION_ADV) {
intent.getParcelableExtra<AdvertisingStatus>(BlueGPSAdvertisingService.DATA_ADV)?.let {
Log.d(TAG, "- Service ${it.status} ${it.message}")
}
}
}
}
then register the receiver in onResume() method and unregister the receiver in onPause()
method.
Show the demo example for more details.
5 BlueGPSMapView¶
BlueGPS comes with an handy object to deal with Maps named BlueGPSMapview. To use the object you
can import the component in your xml layout or programmatically inflate it.
Android View¶
<com.synapseslab.bluegps_sdk.component.map.BlueGPSMapView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Before can be used, BlueGPSMapView should be initialized. Otherwise you will see a loading
animation like below:

In order to configure properly the object you need call the initMap()
fun initMap(
sdkEnvironment: SdkEnvironment,
configurationMap: ConfigurationMap? = ConfigurationMap()
) {
....
}
````
with this parameters:
1. `sdkEnvironment` for authenticate the map;
2. `configurationMap` to config your map, the map start with a default configuration;
```kotlin
private var configurationMap = ConfigurationMap(
tagid = "CFFF00000001",
style = MapStyle(
icons = IconStyle(
name = "chorus",
align = "center",
vAlign = "bottom",
followZoom = true
),
navigation = NavigationStyle(
iconSource = "/api/public/resource/icons/commons/start.svg",
iconDestination = "/api/public/resource/icons/commons/end.svg",
// dictionary of target velocity calculation, the velocity is expressed in km/h
velocityOptions = mutableMapOf("foot" to 4.0, "bike" to 10.0),
// unit in meters to divide the navigation in steps
navigationStep = 1.5,
// enable or disable autoZoom capability when in navigation mode
autoZoom = true,
// debug capability to see the steps when in navigation mode
showVoronoy = false
)
),
show = ShowMap(all = true, room = true),
)
At this point the configuration is injected and the loading animation should disappear and replaced by your map:

Jetpack Compose¶
AndroidView(
modifier = Modifier
.fillMaxSize(),
factory = { it ->
BlueGPSMapView(it).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
initMap(Environment.sdkEnvironment, configurationMap)
// View -> Compose communication
setBlueGPSMapListener(object : BlueGPSMapListener {
override fun resolvePromise(
data: JavascriptCallback,
typeMapCallback: TypeMapCallback
) {
when (typeMapCallback) {
TypeMapCallback.INIT_SDK_COMPLETED -> {
}
TypeMapCallback.RESOURCE_CLICK -> {
}
TypeMapCallback.FLOOR_CHANGE -> {
}
TypeMapCallback.SUCCESS -> {
}
TypeMapCallback.ERROR -> {
}
else -> {}
}
}
})
}
}, update = {
// Compose -> View communication
}
)
5.1 Map Listener¶
BlueGPSMapView could trigger your app remotely from the server. To handle an event click on the map, it's necessary setup the listener.
private fun setListenerOnMapView() {
binding.webView.setBlueGPSMapListener(object : BlueGPSMapListener {
override fun resolvePromise(data: JavascriptCallback, typeMapCallback: TypeMapCallback) {
/**
* Callback that intercept the click on the map
*
* @param data the clicked point with all info.
* @param typeMapCallback the type of the clicked point.
*
*/
when (typeMapCallback) {
TypeMapCallback.INIT_SDK_COMPLETED -> { }
TypeMapCallback.PARK_CONF -> { }
TypeMapCallback.MAP_CLICK, TypeMapCallback.TAG_CLICK -> {
val cType = object : TypeToken<Position>() {}.type
val payloadResponse = Gson().fromJson<Position>(data.payload, cType)
if (payloadResponse.roomId != null) {
// is a room
} else if (payloadResponse.tagid != null) {
// is a tag
}
}
TypeMapCallback.BOOKING_CLICK -> {
val cType = object : TypeToken<ClickedObject>() {}.type
val payloadResponse = Gson().fromJson<ClickedObject>(data.payload, cType)
Log.d(TAG, " $TAG $payloadResponse ")
}
TypeMapCallback.NAV_STATS -> {
val cType = object : TypeToken<NavigationStats>() {}.type
val payloadResponse = Gson().fromJson<NavigationStats>(data.payload, cType)
Log.d(TAG, " $TAG $payloadResponse ")
}
TypeMapCallback.NAV_INFO -> {
val cType = object : TypeToken<NavInfo>() {}.type
val payloadResponse = Gson().fromJson<NavInfo>(data.payload, cType)
Toast.makeText(context, "${payloadResponse.message}", Toast.LENGTH_LONG).show()
}
TypeMapCallback.RESORUCE -> {
val cType = object : TypeToken<DataFilter>() {}.type
val payloadResponse = Gson().fromJson<DataFilter>(data.payload, cType)
Log.d(TAG, " $TAG $payloadResponse ")
}
TypeMapCallback.TAG_VISIBILITY -> {
val cType = object : TypeToken<TagVisibility>() {}.type
val payloadResponse = Gson().fromJson<TagVisibility>(data.payload, cType)
Log.d(TAG, " $TAG $payloadResponse ")
}
TypeMapCallback.ROOM_ENTER -> {
val cType = object : TypeToken<Position>() {}.type
val payloadResponse = Gson().fromJson<Position>(data.payload, cType)
Log.d(TAG, " $TAG $payloadResponse ")
}
TypeMapCallback.ROOM_EXIT -> {
val cType = object : TypeToken<Position>() {}.type
val payloadResponse = Gson().fromJson<Position>(data.payload, cType)
Log.d(TAG, " $TAG $payloadResponse ")
}
TypeMapCallback.FLOOR_CHANGE -> {
val cType = object : TypeToken<Floor>() {}.type
val payloadResponse = Gson().fromJson<Floor>(data.payload, cType)
Log.d(TAG, " $TAG $payloadResponse ")
}
TypeMapCallback.SUCCESS -> {
val cType = object : TypeToken<GenericInfo>() {}.type
val payloadResponse = Gson().fromJson<GenericInfo>(data.payload, cType)
payloadResponse.key = data.key
Log.d(TAG, " ${payloadResponse.message} ")
}
TypeMapCallback.ERROR -> {
val cType = object : TypeToken<GenericInfo>() {}.type
val payloadResponse = Gson().fromJson<GenericInfo>(data.payload, cType)
payloadResponse.key = data.key
Log.e(TAG, " ${payloadResponse.message} ")
}
}
}
})
}
Once implemented, you can easily test receiving remote events by tapping on a room, or a tag in your app.
The resolvePromise(::) method should be triggered appropriately.
List of the callbacks:
TypeMapCallback.INIT_SDK_COMPLETEDtriggered when init sdk is completed.TypeMapCallback.PARK_CONFtriggered if show.park is enabled.TypeMapCallback.BOOKING_CLICKtriggered if a bookable resource is clicked.TypeMapCallback.NAV_STATStriggered on any navigation update.TypeMapCallback.NAV_INFOtriggered on navigation mode when tag is proximity to specific. points.TypeMapCallback.RESORUCEtriggered when loadGenericResource is called.TypeMapCallback.TAG_VISIBILITYtriggered if ConfigurationMap.tagid is present and the tag change its visibility status.TypeMapCallback.ROOM_ENTERtriggered when user enter a room.TypeMapCallback.ROOM_EXITtriggered when user exit a room.TypeMapCallback.FLOOR_CHANGEtriggered when the user change floor.TypeMapCallback.RESOURCE_CLICKtriggered when the user click on resource on map.TypeMapCallback.PATH_RECALCULATIONtriggered when the map recalculate the path.TypeMapCallback.AUTH_ERRORtriggered when access token is expired and its necessary to update the map callinginitAuth().TypeMapCallback.SUCCESStriggered when a generic async action end with success.TypeMapCallback.ERRORtriggered when a generic async action end with error.
5.2 Map Interactions¶
BlueGPSMapView support multiple interactions that could be triggered programmatically from the code.
5.2.1 resetView¶
This action resize the map to the startup. The action is present on the map toolbox.
5.2.2 rotate¶
This action rotate the map by adding step to current location. step represent the incremental
number of degree to rotate the map.
5.2.3 rotateAbsolute¶
his action set the angle rotation of the map according to the parameter. angle represent the
absolute number of degree to rotate the map.
5.2.4 hideRoomLayer¶
This action allow to show or hide the room layer. hide if true hide the layer, false otherwise.
5.2.5 nextFloor¶
This action allow to load the next floor on the web view.
5.2.6 showTag¶
This action find the tag with the specified tagid and if found switch to the right floor and follow the tag if follow is true.
5.2.7 getFloor¶
mapView.getFloor() { result, error ->
error?.let {
Log.e(TAG, "$error")
} ?: run {
MaterialAlertDialogBuilder(this@MapActivity)
.setTitle("Floor list")
.setMessage(result.toString())
.setPositiveButton("Ok") { dialog, _ ->
dialog.dismiss()
}
.show()
}
}
Return the list of floors, in the form of [Floor].
5.2.8 gotoFloor¶
Move the map to the specified Floor.
5.2.9 gotoFloorBy¶
Move the map to the specified Floor.
5.2.10 gotoFromMe¶
This function enable path drawing for a specific destination. The path drawing will from the user position to the selected destination position.
navigationMode: if true, draw the path in navigation mode.
5.2.11 goto¶
This function enable path drawing for a specific destination. The path drawing will from the source position to the selected destination position.
navigationMode: if true, draw the path in navigation mode.
5.2.12 getMapStyle¶
mapView.getMapStyle() {result, error ->
error?.let {
Log.e(TAG, "$error")
} ?: run {
Log.d(TAG, "$result")
}
}
This function get the actual style configuration.
5.2.13 setMapStyle¶
style: represent the map style object
This function allow to change the map style, the function overwrite only the attribute present.
5.2.14 setStartBookingDate¶
date: BASIC_ISO string in format yyyy-MM-dd (ex. 2021-08-30), if not present dafault is today.
This function allow to set the start of booking selection, by default is today.
5.2.15 setBookingDate¶
date: BASIC_ISO string in format yyyy-MM-dd (ex. 2021-08-30).
This function allow to set the booking selection.
5.2.16 reloadResource¶
date: BASIC_ISO string in format yyyy-MM-dd (ex. 2021-08-30).
This function reload the map view.
5.2.17 removeNavigation¶
This function exit from navigation and remove path either on navigation mode or not.
5.2.18 loadGenericResource¶
search: the resource nametype: of the resourcesubtypeof the resource
This function load only resource that match the criteria passed by parameters.
5.2.19 selectPoi¶
poi: generic resourcechangeFloor: optional parameter with default value to true
Center the map to the poi passed as parameter.
5.2.20 selectPoiById¶
poiId: id of the poichangeFloor: optional parameter with default value to true
Center the map to the poi identified by poiId.
5.2.21 drawPin¶
position: object positionicon: a String the represent absolute or relative path to the icon.
Draw a pin in the passed position. The pin has the icon passed as parameter.
5.2.22 getCurrentFloor¶
Return the current floor on the map.
5.2.23 centerToRoom¶
roomId the id of the room
Center the map to the room identified by roomId.
5.2.24 centerToPosition¶
mapPositionthe object positionzoomthe zoom level. The range is a double [0.7, 10]
Center the map to the specified position with defined zoom level.
5.2.25 initAllBookingLayerBy¶
bookFiltera book filter
Init on map all booking layer like: Desk, Park, Meeting.
5.2.26 setDarkMode¶
darkModea boolean
To change the style of the map darkMode or lightMode
5.2.27 showResourceOnMap¶
mapView.showResourceOnMap(
resources: List<Resource>? = emptyList(),
autoFloor: Boolean = true
)
resourcesa list of [Resource]autofloorIf autofloor is enabled the map floor is changed according to resources visibility.
Show the provided resources list on map.
5.2.28 clearSelection¶
Clear the selection of resources on map.
5.2.29 activatePositionMarker¶
enablea booelan true to activate, false to deactivate
Activate/Deactivate Position marker layer.
5.2.30 clearPositionMarker¶
Clear and remove position marker.
5.2.31 getPositionMarker¶
completionHandlerreturn the position marker with format {mapId: 4, x: 23.87, y: 10.49}
Retrieve position marker.
5.2.32 forceFollowMe¶
forceif true automatically follow and center map on tag, false otherwise.
5.2.33 resetPath¶
Clear the draw path on the map.
5.2.34 resetDataAndTag¶
Clear all the data and the tag draw on the map.
5.2.35 resetAll¶
Clear all elements draw on the map.
5.2.36 setTag¶
tagIdthe tagId to draw on mapfollowif true follow the tagId, otherwise only draw the tagId
Draw the tagId on the map and follow it if true, otherwise only draw the tagId.
5.2.37 setCompass¶
degthat represent the number of degree from the north clockwiserotateMapif true rotate the map according to the compass value
Send the gps compass to map view.
This mean that:
- north = 0°
- east = 90°
- south = 180°
- west = 270° or -90°
5.2.38 resetCompass¶
resetIconif true I don't have the compass, false return the compass to the last value
Reset the gps compass on the map view.
This mean that:
- If resetIcon is true I don't have the compass and the map will not rotate.
- If resetIcon is false the map will rotate according to the last value.
5.2.39 getCurrentMapRotationDeg¶
completionHandlerthe completion handler that return the map rotation or an error
Return the actual map rotation.
If the returned value is equal to zero the map isn't rotate, otherwise the map is rotated.
6. Server Sent Events¶
The purpose of diagnostic API is to give an indication to the integrator of the status of the BlueGPS system.
The diagnostic is designed to include different info like:
- Tag tracking status
- Connector tracking status like:
- DesigoCC
- Micronpass
- Quuppa
6.1 Diagnostic SSE¶
For diagnostic if a tag is ACTIVE or NOT_ACTIVE, BlueGPSLib expose a specific call startDiagnostic(..) where:
diagnosticSseRequestis a list of tags;onCompletecallback;- and optional
onTagTracking,onCheckandonStopcallbacks.
val diagnosticSseRequest = DiagnosticSseRequest(
TrackingSseRequest(tags = listOf("BBBB00000001", "BBBB00000002"))
)
BlueGPSLib.instance.startDiagnostic(
diagnosticSseRequest = diagnosticSseRequest,
onComplete = {
// is a DiagnosticSseResponse
Log.d(TAG, "COMPLETE: $it")
},
onTagTracking = {
// is a Map<String, DiagnosticStatus>?
Log.d(TAG, "TAG_TRACKING: $it")
},
onCheck = {
// is a String
Log.d(TAG, "CHECK: $it")
},
onStop = {
Log.d(TAG, "STOPPED: $it")
}
)
diagnosticSseRequest is an object so structured:
class DiagnosticSseRequest(
val tagTracking: TrackingSseRequest? = null
)
class TrackingSseRequest(
val forgetTagMillis: Long? = 10000,
val tags: List<String>? = null,
)
where
forgetTagMillisis default to 10 seconds;tagsis a list of tags you want to monitoring.
There are 2 types of events:
Event complete¶
This event is returned as the first event and DiagnosticSseResponse object has the following format:
Event tagTracking¶
This event is returned when there is an update on list of tags:
The data response is a Map<String, DiagnosticStatus>.
Event onCheck¶
This event is a check that notifies that the diagnostic is alive.
stopDiagnostic¶
BlueGPSLib expose an accessory method for deactivate the diagnostic.
If during the life of the app it's necessary change the configuration it will be enough to call
startDiagnostic(..)because this method stop a previously job active and start the diagnostic with the new configuration.
For more info check the example app in SseDiagnosticTagActivity.kt class.
6.2 Notify region changes¶
For activate the position event detection when the user move inside building,
BlueGPSLib expose a specific call startNotifyRegionChanges(..) where the params of this function are:
tagsa list of tags to monitoring;regionsrepresents the list of the regions to monitor;callbackHandlercallback that return a map that contains the regions where the tags are currently located;onStopevent the SDK automatically stop the job and notify to the user.
BlueGPSLib.instance.startNotifyRegionChanges(
tags = listOf(element = "010001010007"),
regions = regions,
callbackHandler = { it: Map<String, MutableList<BGPRegion>> ->
},
onStop = {
}
)
6.2.1 Event callbackHandler¶
This callback return a value when an event occurred. The object BGPRegion has this structure:
data class BGPRegion(
val id: Int? = null,
val name: String? = null,
val buildingFloorId: Int? = null,
val buildingFloorName: String? = null,
val px: Double? = null,
val py: Double? = null,
val showOnApp: Boolean? = null,
val searchable: Boolean? = null,
val status: BGPRegionStatus? = null,
val type: String? = null,
val areaId: Int? = null,
val areaName: String? = null,
val area: BGPArea? = null,
var isInside: Boolean = false,
)
[!IMPORTANT] Before call
startNotifyRegionChanges()it's necessary to callblueGPSAdvertisingService?.startAdv() orblueGPSAdvertisingService?.startAdv(androidAdvConfiguration = androidAdvConfiguration!!)because when advertising service is started atagID` is assigned to the app.
6.2.2 Stop notify region changes¶
BlueGPSLib expose an accessory method for deactivate the Notify region job.
[!NOTE] If during the life of the app it's necessary change the configuration it will be enough to re-call
startNotifyRegionChanges(..)because this method stop a previously job active and start the event detection with the new configuration.
For more info check the example app in NotifyRegionActivity.kt class.
6.3 Notify position changes¶
For activate the position event detection when the user move inside building,
BlueGPSLib expose a specific call startNotifyPositionChanges() where the params of this function are:
callbackHandlercallback;onStopEventevent the SDK automatically stop the job and notify to the user
BlueGPSLib.instance.startNotifyPositionChanges(
callbackHandler = {
Log.d(TAG, "$position ${it}")
},
onStopEvent = {
}
)
6.3.1 Event callbackHandler¶
This callback return a value when an event occurred. The object returned Position has this structure:
data class Position(
var mapId: Int? = null,
var tagid: String? = null,
var roomId: Int? = null,
var areaId: Int? = null,
var x: Double? = null,
var y: Double? = null,
var data: String? = null,
var tagLabel: String? = null,
)
6.3.2 Stop notify position changes¶
BlueGPSLib expose an accessory method for deactivate the Notify position job.
[!NOTE] If during the life of the app it's necessary change the configuration it will be enough to re-call
startNotifyPositionChanges(..)because this method stop a previously job active and start the event detection with the new configuration.
For more info check the example app in NotifyPositionActivity.kt class.
6.4 Notify generic events¶
For activate the generic event detection,
BlueGPSLib expose a specific call startNotifyEventChanges() where the params of this function are:
streamTypetype of the stream.outputEventsList of events to be notified for the specific types of stream.tagIdListList of tag id to monitoring. If empty receive notification for all tags.callbackHandlerreturns a generic event.onStopcallback when the connection with the server is closed.
BlueGPSLib.instance.startNotifyEventChanges(
streamType = StreamType.TAGID_EVENT,
outputEvents = listOf("test"),
tagIdList = listOf("DADA00000001",),
callbackHandler = {
},
onStop = {
}
)
6.4.1 Event callbackHandler¶
This callback return a value when an event occurred. The object returned Event has this structure:
data class Event(
val id: String? = null,
val name: String? = null,
val data: String? = null
)
6.4.2 Stop notify event changes¶
BlueGPSLib expose an accessory method for deactivate the Notify generic job.
[!NOTE] If during the life of the app it's necessary change the configuration it will be enough to re-call
startNotifyEventChanges(..)because this method stop a previously job active and start the event detection with the new configuration.
For more info check the example app in NotifyPositionActivity.kt class.
7 Resources API¶
The BlueGPSLib perform a network call to find a list of resources.
override suspend fun findResources(
isDesc: Boolean?,
mapId: Int?,
order: String?,
search: String?,
subType: String?,
type: String?,
roomId: Int?,
roomName: String?
): Resource<List<GenericResource>?>
where
isDesca boolean that represent if is increasing or decreasingmapIdthe id of the map where the resource is locatedordersearchthe name of the resourcesubTypetypethe resource type (PARK,DESK,MEETING)roomIdthe id of the room where the resource is locatedroomNamethe name of the room where the resource is located
It's present an example activity called ShowResourcesActivity.kt that show the utility and the use of this network call.

8 Search object API¶
BlueGPSSDK provides some built-in capabilities to search for resources and objects within the Backend, providing multiple calls:
8.1 getTrackElement¶
getTrackElement returns a tracked element by passing a corresponding ID.
The resulting ResponseMessage contains a TrackedElement as follow:
data class TrackedElement(
var id: Int?,
var label: String?,
var type: String?,
var description: String?,
var imgPath: String?,
var color: String?,
var trackElementType: TrackElementType?,
var groups: List<TrackedGroup>?,
var trackAreaId: Int?,
var positionItem: PositionItem?,
var tagList: List<TrackElementTag>?,
)
8.2 getTrackElementTagHistory¶
getTrackElementTagHistory returns a tag history passing a corresponding ID.
The resulting ResponseMessage contains a list of List<TrackElementTag> as follow:
data class TrackElementTag(
var id: Int?,
var insertDate: String?,
var readOnly: Boolean = true,
var end: String?,
var start: String?,
var priority: Int?,
var trackElementId: Int?,
var trackElementLabel: String?,
var trackTagId: String?,
var trackTagLabel: String?,
)
8.3 getTrackElements¶
getTrackElements return an array of TrackElement based on the filter criteria specified.
suspend fun getTrackElements(
type: String? = null,
groupIds: List<Int>? = null,
search: String? = null,
isDesc: Boolean? = null,
order: String? = null,
)
where:
searchis the name of the track elementtypegroupIdsa list of id that represent the groupisDesca boolean that represent if is increasing or decreasingordera string that represent the order by a attributepageNumberan that represent the current pagepageSizethe elements of the page
The resulting ResponseMessage contains a List<TrackElement> as follow:
data class TrackElement(
var id: Int? = null,
var label: String? = null,
var type: String? = null,
var description: String? = null,
var imgPath: String? = null,
var email: String? = null,
var color: String? = null,
var trackElementType: TrackElementType? = null,
var groups: List<TrackedGroup>? = null,
var positionItem: PositionItem? = null
)
8.4 getTrackElementPage¶
getTrackElementPage return a track element page based on the filter criteria specified.
suspend fun getTrackElementPage(
type: String? = null,
groupIds: List<Int>? = null,
search: String? = null,
isDesc: Boolean? = null,
order: String? = null,
)
where:
searchis the name of the track elementtypegroupIdsa list of id that represent the groupisDesca boolean that represent if is increasing or decreasingordera string that represent the order by a attribute
The resulting ResponseMessage contains a PageTrackedElement as follow:
class PageTrackedElement(
var content: List<TrackedElement>,
var numberOfElements: Int?,
var first: Boolean,
var last: Boolean,
var totalElements: Int?,
var totalPages: Int?,
)
8.5. getTrackGroup¶
getTrackGroup return a list of track group based on the filter criteria specified.
The resulting ResponseMessage contains a list of List<TrackedGroup> as follow:
data class TrackedGroup(
var id: Int? = null,
var label: String? = null,
var type: String? = null,
var color: String? = null,
)
8.6 getSearchableTrackTag¶
Get a searchable track tag list filtering also by NFC code
suspend fun getSearchableTrackTag(
search: String? = null,
tagId: String? = null,
label: String? = null,
nfcCode: String? = null,
) : Resource<List<TrackTag>>
where:
searchspecifying this query param the search is performed on the label, tagid and nfcCode attributes.tagIdspecifying this parameter will return a list of tags that have exactly the specified tagid.labelspecifying this parameter will return a list of tags that have exactly the specified label.nfcCodespecifying this parameter will return a list of tags that have exactly the specified nfcCode.
The resulting ResponseMessage contains a list of List<TrackTag> as follow:
data class TrackTag(
var tagid: String? = null,
var label: String? = null,
var color: String? = null,
var nfcCode: String? = null,
var type: String? = null
)
9 Controllable items API¶
BlueGPSSDK provides a logic to interact with controllable items exposed by the backend.
Controllable items could be anything that can be remote controlled by the application.
Authenticated user could get the list of available items with the following call:
suspend fun BlueGPSLib.getControllableItems(itemControllableFilter: ItemControllableFilter? = null)
You can pass an optional filter criteria as follow:
data class ItemControllableFilter(
///full search on Item.logicName
var logicName: String? = null,
///Search the item into a specified area
var areaId: Int? = null,
///Search the item connected to a specified room
var roomId: Int? = null,
///Search the item connected to a specified map
var mapId: Int? = null,
//Filter the item inside reference point from the radius
var referencePoint: Position? = null,
//Must be combined with referencePoint
var radius: Double? = null,
///Select items of following types
var types: List<ControllableElementType>? = null,
var hasPosition: Boolean? = null,
var widgetNames: List<String>? = null
)
The resulting ResponseMesssage contains a list of List<ItemControllable> as follow:
data class ItemControllable(
var id: String,
///Internal name of the item
var logicName: String,
///Internal name of the widget connected to the item
var widgetName: String,
///name of this item
var name: String?,
///internationalization key of this item
var i18nName: String?,
///type of the current item
var type: ControllableElementType,
var position: Position?,
var buildingPositionList: List<BuildingPosition>?,
var icon: MobileIcon?,
var controls: List<ItemControl>?
)
The attribute controls contains all the available controllable items for this specific ItemControllable.
Every ItemControl, could be changed, by modifying its currentValue property.
Then, you can call the below function to save new current value.
The resulting response contains a resource of ItemCurrentValue as follow:
10 Area API¶
BlueGPSSDK provides some built-in capabilities for rooms and areas.
10.1 getRoomsCoordinates¶
getRoomsCoordinates returns a list of rooms and coordinates.
The resulting ResponseMessage contains a List<BGPRegion> as follow:
data class BGPRegion(
val id: Int? = null,
val name: String? = null,
val buildingFloorId: Int? = null,
val buildingFloorName: String? = null,
val px: Double? = null,
val py: Double? = null,
val showOnApp: Boolean? = null,
val searchable: Boolean? = null,
val status: BGPRegionStatus? = null,
val type: String? = null,
val areaId: Int? = null,
val areaName: String? = null,
val area: BGPArea? = null,
var isInside: Boolean = false,
)
10.2 getMapsList¶
getMapsList Return a list of maps.
suspend fun getMapsList(
search: String? = null,
staticResourceTypeList: List<BGPResourceType>? = null,
isDesc: Boolean? = null,
order: String? = null,
): Response<List<BGPMap>>
where:
searchthe name of the mapstaticResourceTypeLista list ofBGPResourceTypeisDesca booleanorderfor name
The resulting ResponseMessage contains a List<BGPMap> as follow:
data class BGPMap(
val id: Int? = null,
val label: String? = null,
val type: String? = null,
val order: Int? = null,
val circleRadius: Double? = null,
val name: String? = null,
val orientation: BGPMapOrientation? = null,
val ox: Double? = null,
val oy: Double? = null,
val s1x: Double? = null,
val s1y: Double? = null,
val s2x: Double? = null,
val s2y: Double? = null,
val scale: Double? = null,
val distance: Double? = null,
val fileMap: String? = null,
val mapRefreshRate: Int? = null,
val animationDurationMs: Int? = null,
val northAngle: Double? = null,
val primaryColor: String? = null,
val viewWidth: Double? = null,
val viewHeight: Double? = null,
val badgeDistance: Double? = null,
val coordNameList: List<String>? = null,
val allCoord: List<String>? = null,
)
10.3 getAreasWithTagsInside¶
getAreasWithTagsInside returns a list of area with a list of inside tags
suspend fun getAreasWithTagsInside(
areaFilterRequest: AreaFilterRequest? = null,
): Response<List<BGPMap>>
where:
areaFilterRequestan object that contains a list of areas id or maps id
The resulting ResponseMessage contains a List<AreaWithTagsInside> as follow:
data class AreaWithTagsInside(
val id: Int? = null,
val name: String? = null,
val tagIds: List<String>? = null
)
10.4 getAreasList¶
getAreasList returns a list of areas
suspend fun getAreasList(
search: String? = null,
type: String? = null,
isDesc: Boolean? = null,
order: String? = null,
): Resource<List<BGPArea>>
where:
searchthe name of the areatypeBGPAreaType// DEFAULT,FILTERisDesca Booleanorderfor name
The resulting ResponseMessage contains a List<BGPArea> as follow:
data class BGPArea(
val id: Int? = null,
val color: String? = null,
val type: BGPAreaType? = null,
val name: String? = null,
val points: List<BGPPoint>? = null,
val rtlsMapId: Int? = null
)
10.5 getAreaListRealtimeElement¶
getAreaListRealtimeElement returns a RealtimeAreaElementResponse that contains the list of areas where a realtime
element (Tag, Element, etc.) is located.
suspend fun getAreaListRealtimeElement(
realtimeAreaElementRequest: RealtimeAreaElementRequest
): Resource<RealtimeAreaElementResponse>
where:
realtimeAreaElementRequestis
data class RealtimeAreaElementRequest(
val id: String, // the id of the realtime element to locate (Tag, Element, etc.,)
val type: RealtimeElementType
)
enum class RealtimeElementType {
TAGS,
ELEMENT,
MOBILE_USER,
GROUP,
ROOM,
BUILD_ITEM,
LOCATORS,
EVENT,
NAVIGATION_ELEMENT,
RESOURCE,
}
The resulting ResponseMessage contains a RealtimeAreaElementResponse as follow:
data class RealtimeAreaElementResponse(
val id: String,
val type: RealtimeElementType,
val areas: List<BGPArea>,
val areaIds: List<Int>
)
11 Booking API¶
BlueGPS_SDK provides some built-in capabilities for booking.
11.1 getAgendaDay¶
getAgendaDay() return the agenda for the selected element.
suspend fun getAgendaDay(
id: String,
date: String,
scheduleTypes: List<ScheduleType>,
): Resource<DaySchedule>
where
idthe id of the element to be find the day scheduletscheduleTypesypethe type of the element to be find the day scheduledateExample: "2022-01-22"
11.2 getAgendaMy¶
getAgendaMy() return all agenda for the logged user.
suspend fun getAgendaMy(
dateStart: String? = null,
dateEnd: String? = null,
): Response<List<DaySchedule>> {}
where
dateStartExample : 2022-01-22dateEndExample : 2022-01-22
11.3 agendaFind¶
agendaFind() return the agenda for the selected elements and for the selected date.
suspend fun agendaFind(
resourceAgendaRequest: ResourceAgendaRequest
): Response<List<ResourceAgenda>> {}
where
resourceAgendaRequest[ResourceAgendaRequest] is
data class ResourceAgendaRequest(
val elements: List<Resource>,
/**
* example: 2023-01-21
*/
val dateStart: String,
/**
* example: 2023-01-21
*/
val dateEnd: String? = null
)
The resulting ResponseMessage contains a List<ResourceAgenda>.
data class ResourceAgenda(
/**
* unique id
*/
val id: String,
/**
* the resource searched
*/
val element: Resource,
/**
* example: 2023-01-21
*/
val dateStart: String,
/**
* example: 2023-01-21
*/
val dateEnd: String? = null,
val days: List<DaySchedule>? = null
)
11.4 schedule¶
schedule() to schedule a resource as DESK, ROOM, PARK, etc..,
where
scheduleRequest[ScheduleRequest] is
data class ScheduleRequest(
/**
* the id of the element to schedule
*/
val elementId: String,
val elementType: ResourceType,
/**
* an optional name for the meeting
*/
val meetingName: String? = null,
/**
* an optional note for the meeting
*/
val meetingNote: String? = null,
/**
* a boolean to indicate if is a video conference
*/
val videoConference: Boolean? = false,
/**
* example: 2023-01-21
*/
val dayStart: String,
/**
* example: 2023-01-21
*/
val dayEnd: String? = null,
/**
* example: 08:00
*/
val start: String? = null,
/**
* example: 18:00
*/
val end: String? = null,
/**
* a list of attendees for the meeting
*/
val attendees: List<MeetingAttendee>? = null,
/**
* the type of the schedule [RecurringType]
*/
val recurring: RecurringType? = null,
)
11.5 deleteSchedule¶
Delete a schedule based on the resourceId provided
11.6 search¶
Search resources based on the given filter
where filter is struct as follow:
data class Filter(
/**
* generic search string
*/
val search: String? = null,
val section: SectionFilterType? = null,
/**
* Possible resource, all resource in case of empty
*/
val resourceTypes: List<ResourceType>? = null,
/**
* a boolean indicate if is a favourite
*/
val favourite: Boolean? = null,
/**
* a list of [FilterElement]
*/
val filters: List<FilterElement>? = null,
val filterType: FilterType? = null
)
Returned resources are struct as follow:
data class Resource(
/**
* unique id
*/
val id: String,
/**
* the name of the resource
*/
val name: String,
/**
* the resource type [ResourceType]
*/
val type: ResourceType,
val singleInfo: InfoIcon? = null,
val i18n: String? = null,
val tagid: String? = null,
/**
* image url (if start with http/s the url is absolute, relative otherwise)
*/
val image: String? = null,
/**
* image url (if start with http/s the url is absolute, relative otherwise)
*/
val images: List<String>? = null,
val buildingPosition: BuildingPosition? = null,
val position: Position? = null,
val bookingConfig: BookingConfig? = null,
val services: List<ResourceService>? = null,
val controls: List<Control>? = null,
val favourite: Boolean? = false,
val sensors: List<SensorInfo>? = null,
val subtype: String? = null,
val i18nSubtype: String? = null,
/**
* Search tags
*/
val metadataTypes: List<String>? = null,
/**
* Groups
*/
val connectedGroupNames: List<String>? = null,
val description: String? = null,
val integrationKey: String? = null,
val additionalServices: List<AdditionalService>? = null,
val code: String? = null,
val codeUrl: String? = null,
val username: String? = null,
val imageUrl: String? = null,
val imagesUrl: List<String>? = null
)
11.7 getFilterSection¶
Return a list of SectionFilter based on the provided SectionFilterType
suspend fun getFilterSection(sectionTypes: List<SectionFilterType>? = null): Resource<List<SectionFilter>>
where SectionFilterType is:
return a list of SectionFilter as follow:
data class SectionFilter(
val sectionType: SectionFilterType,
val sectionValues: List<FilterValueElement>
)
11.8 getFilterResource¶
Return the corresponding filters into a Filter object for the provided type ResourceType
where Filter is as follow:
data class Filter(
/**
* generic search string
*/
val search: String? = null,
val section: SectionFilterType? = null,
/**
* Possible resource, all resource in case of empty
*/
val resourceTypes: List<ResourceType>? = null,
/**
* a boolean indicate if is a favourite
*/
val favourite: Boolean? = null,
/**
* a list of [FilterElement]
*/
val filters: List<FilterElement>? = null,
val filterType: FilterType? = null
)
11.9 getFilter¶
Return the corresponding filters into a Filter object for the provided type FilterType
where Filter is as follow:
data class Filter(
/**
* generic search string
*/
val search: String? = null,
val section: SectionFilterType? = null,
/**
* Possible resource, all resource in case of empty
*/
val resourceTypes: List<ResourceType>? = null,
/**
* a boolean indicate if is a favourite
*/
val favourite: Boolean? = null,
/**
* a list of [FilterElement]
*/
val filters: List<FilterElement>? = null,
val filterType: FilterType? = null
)
11.10 getElementResource¶
Get Resource specified by id
11.11 putFavourite¶
Change favourite resource specified by resource
suspend fun BlueGPSLib.putFavourite(favouriteResource: FavouriteResource): Resource<SyHttpResponse>
where favouriteResource is as follow:
data class FavouriteResource(
val resourceId: String? = null,
val favourite: Boolean? = null
)
the response is SyHttpResponse as follow:
12 Ticket¶
BlueGPS_SDK provides some capabilities to list/create/delete a Ticket.
For now 2 types of tickets are managed:
InternalTickets (managed by Bluegps)IvivaTickets (managed by the iviva platform)
12.1 getTicketTypes¶
getTycketTypes returns the types for tickets that for now are ("INTERNAL", "IVIVA").
12.2 getTicketMy¶
getTicketMy return all tickets available for the logged user.
suspend fun getTicketMy(
search: String? = null,
manager: String? = null,
status: String? = null,
): Resource<List<Ticket>>
where params are:
searchto search for tickets that have a match in the descriptionmanagerto get the tickets of a specific managerstatusto get the tickets of a specific status
the resulting ResponseMessage contains a List<Ticket>
12.3 getTicketFormManager¶
getTicketFormManager return the entire form that the interface will have to build.
where param is:
managerthe ticket manager type ("INTERNAL", "IVIVA")
the resulting ResponseMessage contains a List<FormTicket>
12.4 updateTicketFormManager¶
For dynamically updating the fields of the form based on the user's choices, the updateTicketFormManager API must be called, which simply returns a new form updated with the correct values and fields.
suspend fun updateTicketFormManager(
manager: String,
body: List<FormTicket>
): Resource<List<FormTicket>>
where param is:
managerthe ticket manager type ("INTERNAL", "IVIVA")bodythe current form
the resulting ResponseMessage contains the updated form List<FormTicket>
12.5 getTicketById¶
getTicketById return the detail of the ticket.
where param is:
idrepresent the ticket id
the resulting ResponseMessage contains a FormTicket
12.6 saveTicket¶
saveTicket to save a ticket to the backend.
suspend fun saveTicket(
manager: String,
image: MultipartBody.Part? = null,
sound: MultipartBody.Part? = null,
form: MultipartBody.Part?
): Resource<List<FormTicket>>
where params are:
managerrepresent the ticket manager ("INTERNAL", "IVIVA")image: an optional image,sound: an optional sound like vocal note,form: is required that contains aList<FormTicket>
the resulting ResponseMessage contains a <List<FormTicket>>
12.7 deleteTicket¶
deleteTicket to delete a ticket.
where:
idrepresent the ticket id
the resulting ResponseMessage contains the deleted Ticket.
13 Position¶
BlueGPS_SDK provides some capabilities to get the position of the tags inside the building.
13.1 getCurrentPosition¶
getCurrentPosition returns the current position of the tag inside the building..
where:
tagIdrepresent the current tag id
the resulting ResponseMessage contains the Position model.