Via the UnitController the app can access available and nearby units, filter by type and command them to open.
To acquire the single instance of the Unit Controller call sdk.getUnitController()
The general status of the Unit Controller can be observed from the getStatus()
method.
Possible values of UnitController.Status and their expected values are:
SdkNotReady
: The unit controller can only operate when the SDK is ready (logged-in)Ready
: The SDK is ready and can be used to control units. A call to .open(iotUnit)
when the controller is not on this state will throw IllegalStateException
.NoLocationPermissio
: It’s necessary to have location permission for the controller to scan for nearby IotUnitsLocationIsOff
: It’s necessary for the location to be on in the device settings for the controller to scan for nearby IotUnitsBluetoothIsOff
: It’s necessary for bluetooth to be turned on for the controller to scan for nearby IotUnitsBluetoothError
: There was an error reported by the Bluetooth radio. The error code is inside available inside this objectBusy
: The controller is busy opening a unit after it was requested.To get the IotUnit’s call unitController.getUnits(Availability, Sorting, IotUnit.Type?): Flow<List<IotUnit>>
. You can pass some parameters for filtering.
All
: every unit the user can have access to, regardless of specific times or bookingsAvailableNow
: only the units the user can access at the moment. Takes in consideration opening times and if the unit is booked now. The LiveData will be updated when availability changes. For example: “Door A” availability starts at 8:00 AM and getUnits()
is queried at 7:59 AM. When the minute change the data will change to reflect the newly available door.None
: No sorting appliedDistance
: From closest to out-of-reach. Check the iotUnit.isNearby()
method to see if the unit is in reach.null
: no filtering, return every type of unitDOOR
: returns only doorsLOCKER_BOX
: returns only locker boxesTo open an IotUnit simply call the .open()
.
This method can only be called when the UnitController.Status
is Ready
.
In case the status is not ready, the returned Response will be failed with an IllegalStateException
.
The Response of the .open()
call contains two parameters:
- Response.data is the IotUnit this openable was resolved to
- Response.progress is an enum with the progress of the operation.
val cancelOpen = CancellationSignal()
fun onOpenButtonClicked() {
sdk.getUnitController()
.openAsLiveData(iotUnit, cancelOpen)
.observe(
lifecycleOwner,
Observer { response ->
// ... observe the progress, update UI
when (response.status) {
Response.Status.SUCCESS -> // ...
Response.Status.FAIL -> {
if(response.exception is UserCancelException) {
// the SDK successfully cancelled the operation as requested by the user
} else {
// check for other exception
}
}
Response.Status.EXECUTING -> // ...
}
}
)
}
fun onCancelButtonClicked() {
cancelOpen.cancel(UserCancelException("Canceling open of $iotUnit. User request"))
}
override fun onStop() {
// onStop cancel opening to avoid the UnitController to search (and be busy) forever
cancelOpen.cancel(Exception("Canceling open of $iotUnit. Activity stop"))
}
class UserCancelException(message:String): Exception(message:String)
The Openable
interface marks classes that can be opened by the SDK. Currently that includes:
.getUnits()
method can be called to open.The progress of the opening values are as follows:
opening.onProgress().observe(this, Observer {
when (it) {
OpeningProgress.SearchingNearby -> // sdk is trying to find the closest available unit to open
OpeningProgress.SearchingUnit -> // sdk is searching for one specific unit to open
OpeningProgress.Connecting -> // sdk is connecting/communicating with the unit
}
})
The opening.data
will contain the IotUnit
this opening is trying to open.
It’s important to remember thou, that whenever the progress of opening is SearchingNearby
the IotUnit is not known and the data will be null
.
The optional CancellationSignal
object supplied to the open method can be managed however the client application wants.
A simple example is when there’s a dedicated opening screen and the app uses ViewModel, so the cancel would be called on exit that screen.
class OpeningViewModel : ViewModel() {
val cancellationSignal = CancellationSignal()
override onCleared() {
super.onCleared()
// cancel any `open` invoked by this view model
cancellationSignal.cancel(MyException()) // or just use the default CanceledException()
}
}
It’s important to understand and remember thou, that canceling is a “best attempt” and the opening might still be SUCCESS
.
Whenever canceling happens, status will be changed to FAIL
and the exception can be found on opening.exception
. The default is CanceledException