Getting started guide¶
This guide aims to cover all the main features of the API and how to use them in an app.
All the needed interactions are explained in detail with snippets of code.
All public API classes are documented using javadoc. See it here.
Integration¶
The library is supplied as an aar
archive. To import it to your project,
create a folder named aarlibs
inside your app module folder.
Add the following snippet to your project base build.gradle
file:
repositories {
...
flatDir {
dirs 'aarlibs'
}
}
Add the following snippet to your app build.gradle
file replacing version
for the correct value:
dependencies {
...
implementation 'com.elvishew:xlog:1.3.0'
implementation 'no.nordicsemi.android:dfu:1.3.1'
implementation (name:'kallistoapi-release-[version]', ext:'aar')
}
Usage¶
The following guide provides a step-by-step on how to interact with the API in order to build a full app. Some code is omitted for brevity.
Starting the system¶
Get an instance of a KallistoManager
. Since only a
KallistoSensorManager
is implemented, it is used.
When an instance of a manager is requested for the first time, the remote service is created if is not running.
A broadcast with a SENSOR_SERVICE_CONNECTED
or SERVICE_FAILED
is received detailing the service
status.
The service will keep the Bluetooth adapter on at all times and will turn it on automatically if turned off.
When destroying the app, do not forget to call KallistoManager.disconnect()
or the system will leak resources.
public class YourClass extends Activity {
private ServiceBroadcastReceiver mBroadcastReceiver = new ServiceBroadcastReceiver();
private KallistoManager mKallistoManager;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Register a broadcast receiver.
IntentFilter i = new IntentFilter();
i.addAction(KallistoManager.SENSOR_SERVICE_CONNECTED);
i.addAction(KallistoManager.SERVICE_DISCONNECTED);
i.addAction(KallistoManager.SERVICE_FAILED);
registerReceiver(mBroadcastReceiver, i);
mKallistoManager = KallistoSensorManager.getInstance(this)
}
@Override
protected void onDestroy() {
super.onDestroy();
//Destroy the system
mKallistoManager.disconnect();
}
//Simple broadcast receiver
private class ServiceBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (KallistoManager.SENSOR_SERVICE_CONNECTED.equals(action)) {
//From now on, the service is up and running!
//We can start requesting operations using the KallistoManager.
} else if (KallistoManager.SERVICE_DISCONNECTED.equals(action)) {
//From now on, the service is dead
} else if (KallistoManager.SERVICE_FAILED.equals(action)) {
//Service failed. Impossible to continue.
}
}
}
The static method KallistoSensorManager.getInstance(Context context)
is used to get the instance with default configurations. Several parameters can be configured
using the full
builder method.
Scanning for devices¶
If the scanning method is not configured explicitly while starting the system, it will default to a cyclic behavior where it scans for a few seconds and then stops. No explicit configuration is needed.
To receive information from the system a callback architecture is used. The app
must register
a
SystemEventListener
to receive SystemEvents
.
Should unregister
when done.
For scanning, the most interesting events are SCAN_STARTED
,
SCAN_STOPPED
, SCAN_FOUND_DEVICE
,
SCAN_LOST_DEVICE
.
public class KallistoActivity extends Activity implements SystemEventListener {
(...)
@Override
protected void onDestroy() {
super.onDestroy();
//Unregister the listener
mKallistoManager.unregisterSystemListener(this);
}
@Override
public void onSystemChanged(SystemEvent event) {
if (event.type.equals(SystemEventType.SCAN_FOUND_DEVICE)) {
//A new device was found. Add it to a list or something
}
if (event.type.equals(SystemEventType.SCAN_LOST_DEVICE)) {
//A device stopped advertising. Remove it from a list or something
}
}
private class ServiceBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (KallistoManager.SENSOR_SERVICE_CONNECTED.equals(action)) {
//Register listener for System events.
mKallistoManager.registerSystemListener(Homescreen.this, SystemEventType.TYPE_INFO);
}
(...)
}
}
Since scanning is an expensive operation in terms of power consumption, it is not recommended to keep the default behavior. Full control is given to the developer to start and stop scans as desired.
Use KallistoManager.updateScannerConfiguration()
to update the scanner state.
See ScannerConfiguration.Builder
for on how
to build a scanner configuration.
private void startScan(){
mKallistoManager.updateScannerConfiguration(new ScannerConfiguration.Builder()
.withResponsiveCycle()
.build());
}
private void stopScan(){
mKallistoManager.updateScannerConfiguration(new ScannerConfiguration.Builder()
.stop()
.build());
}
To be reported to the app, the device must pass a scanning filter that is fully configurable. By default, no filter is used and all devices are reported.
Use KallistoManager.updateScannerFilter()
to update the scanner filter.
See ScannerFilter.Builder
for on how
to build a scanner filter.
Receive sensor data¶
After getting an instance of the desired Kallisto
device, sensor data can now be requested.
For that, an instance of a KallistoSensor
must be acquired.
For that, KallistoSensorManager
has methods to get it
like KallistoSensorManager.getSensorList(int type)
.
The sensors of a given device can be obtained using Kallisto.getSensors()
.
Use KallistoSensorManager.registerListener(SensorEventListener listener, KallistoSensor sensor, final int rateUs)
to register to receive sensor data.
Should unregister
when done.
Beware that the sensor registering is synchronous so it must not be performed in the main thread.
Since to receive sensor data a connection is established, it can disconnect at any time.
In order to be notified of that, the system events LINK_LOSS
,
LINK_RECOVERED
and LINK_REMOVED
are supplied and should be used to present information to the user.
During a Link Loss, a quick scan is started in order to recover the connection to the device. The scanner returns to its previous state when the connection is recovered or a timeout passed.
public class SensorActivity extends Activity implements SensorEventListener, SystemEventListener {
@Override
protected void onResume() {
super.onResume();
//Start sensor register task
new RegisterSensorsTask().execute();
//Register system listener
mKallistoManager.registerSystemListener(this, SystemEventType.TYPE_INFO);
}
@Override
protected void onPause() {
super.onDestroy();
//Unregister the listeners
mKallistoManager.unregisterListener(this);
mKallistoManager.unregisterSystemListener(this);
}
@Override
public void onAccuracyChanged(KallistoSensor sensor, int i) {
//Not used
}
@Override
public void onSensorChanged(SensorEvent event) {
//Do something with the event
}
@Override
public void onSystemChanged(SystemEvent event) {
if (event.Kallisto == null || !event.Kallisto.equals(mKallisto)) {
//Ignore events that aren't for our device
return;
}
if (event.type.equals(SystemEventType.LINK_LOSS)) {
//Connection dropped, system is trying to recover
}
if (event.type.equals(SystemEventType.LINK_RECOVERED)) {
//Connection recovered
}
if (event.type.equals(SystemEventType.LINK_REMOVED)) {
//Timeout passed, device was lost!
}
}
private class RegisterSensorsTask extends AsyncTask<Void, Void, Boolean> {
protected Boolean doInBackground(Void... notUsed) {
//Register to all sensors in the device
for (KallistoSensor p : mKallisto.getSensors()) {
if (!mKallistoManager.registerListener(Device.this, p, KallistoSensorManager.SENSOR_DELAY_NORMAL)) {
//Failed to register to the sensor
return false;
}
}
}
(...)
}
}
Other features¶
Beyond reporting sensor data, several other features are supported by the library.
Battery¶
A Kallisto
device may support the reporting of battery data.
Check if the device supports it by using Kallisto.supportsBatteryChanges()
.
Register to receive battery events using KallistoManager.registerBatteryListener()
and implement the BatteryEventListener
.
Unregister using KallistoManager.unregisterBatteryListener()
.
Calibration¶
A KallistoSensor
may support calibration.
Check if the device supports it by using KallistoSensor.supportsCalibration()
.
Start a calibration using KallistoSensorManager.startCalibration()
and implement the CalibrationEventListener
.
A calibration can be stopped using KallistoSensorManager.stopCalibration()
.
Device Firmware Update¶
A Kallisto
firmware can be updated over-the-air.
Start an update using KallistoManager.startDfu()
and implement the DfuEventListener
.
An update can be stopped using KallistoManager.stopDfu()
.
Final Remarks¶
Some key aspects of the library must be taken into account while integrating it in an app:
The library is synchronous in all calls that may trigger a connection to a device. This choice was made to supply an API as close as possible to the Android Sensor Manager. An asynchronous interface will be added in the future;
The connections are opportunistic. A connection is only established when it is needed and is dropped when the device is not in use.
The function
KallistoManager.stayConnected()
can be used to override this behavior. Set it totrue
and a connection operation is executed (if device is not already connected) and will be kept.A bonded device, once connected, will stay connected.
The device metadata is only downloaded when the device connects for the first time or when request before any connection is made.
The Bluetooth adapter will be fully controlled by the system. If it is turned off it will be forced on again.
Sometimes, the Bluetooth adapter can enter into an abnormal state where it can’t be turned on without a reboot. A system event
STACK_IRREPARABLE
is triggered when this happens to allow an app to warn an user.