Class BlukiiClient
BlukiiClient class contains discovery functions as follows:
- Discovery of BLE modules and extracting BLE advertised data
- Decryption of blukii SecureBeacon advertising.
A. Discover BLE modules and extract their BLE data
To do this you have to do the following steps:
1. Initialize and start discovery
Call initDiscovery(OnDiscoveryListener)
and implement the
BlukiiClient.OnDiscoveryListener
callbacks. Now you can start and stop the discovery as needed.
Note: Do not forget to terminate blukii discovery (terminateDiscovery()
)
for releasing resources if you do not need the discovery any more.
@Override
protected void onCreate(Bundle savedInstanceState) {
// Initialize blukii discovery (see also BlukiiController
)
mBlukiiClient = BlukiiController.getInstance().getDiscoveryClient();
mBlukiiClient.initDiscovery(blukiiDiscoveryListener);
mBlukiiClient.startDiscovery();
}
BlukiiClient.OnDiscoveryListener blukiiDiscoveryListener = new BlukiiClient.OnDiscoveryListener() {
@Override
public void onDiscoveryResult(List<DiscoveryData> discoveryResultList) {
// retrieve BLE results
}
@Override
public void onError(BlukiiDiscoveryError errorCode) {
// retrieve errors
}
@Override
public void onInfo(BlukiiDiscoveryInfo infoCode) {
// retrieve infos and changed states
}
};
public void startDiscovery() {
// start BLE scan
mBlukiiClient.startDiscovery();
}
public void stopDiscovery() {
// stop BLE scan
mBlukiiClient.stopDiscovery();
}
@Override
public void onDestroy() {
// Terminate blukii discovery
if(mBlukiiClient != null) {
mBlukiiClient.terminateDiscovery();
}
}
2. Configure discovery settings
Use the DiscoverySettings
object for configuring discovery.
Call getDiscoverySettings()
to retrieve the settings property set.
@Override
protected void onCreate(Bundle savedInstanceState) {
mBlukiiClient = BlukiiController.getInstance().getDiscoveryClient();
mBlukiiClient.initDiscovery(blukiiDiscoveryListener);
// change discovery settings
DiscoverySettings discoverySettings = mBlukiiClient.getDiscoverySettings();
discoverySettings.setRssiThreshold(-100);
discoverySettings.setScanDuration(10000);
discoverySettings.setProfile(DiscoveryProfile.FOREGROUND);
// ...
mBlukiiClient.startDiscovery();
}
When BLE scanner is started the BLE discovery is acting according
to the DiscoverySettings
:
- The scanner is searching for BLE modules inside the defined rssi range
(
DiscoverySettings.getRssiThreshold()
). - After one scan duration (
DiscoverySettings.getScanDuration()
) the results are called back to (BlukiiClient.OnDiscoveryListener.onDiscoveryResult(List)
). - The BLE scanner is effectively scanning according the discovery profile setting
(see
DiscoverySettings.setProfile(int)
. It defines whether the scan is running on foreground, background and screen off. - blukii SDK is managing intelligently the internal start and stop of the BLE scanner.
These state changes are told by the callback
BlukiiClient.OnDiscoveryListener.onInfo(com.blukii.sdk.discovery.BlukiiDiscoveryInfo)
3. Retrieve results
The callback BlukiiClient.OnDiscoveryListener.onDiscoveryResult(List)
will be called after
finishing every discovery phase. It retrieves the discovered list of DiscoveryData objects.
Note: If no BLE modules have been found discoveryResultList is empty (not null).
@Override
public void onDiscoveryResult(List<DiscoveryData> discoveryDataList) {
// Discovery phase has finished: list of DiscoveryData objects are retrieved
int count = discoveryResultList.size();
for (DiscoveryData discoveryData : discoveryDataList) {
String id = discoveryData.getBlukiiId();
short rssi = discoveryData.getRssi();
// ...
}
}
Note: As default advertising data packets of one device are bundled to one DiscoveryData
list item. See DiscoverySettings.setListEveryFrame(boolean)
if you want to retrieve each
advertising packet as single item.
4. Retrieve errors and infos
The callbacks BlukiiClient.OnDiscoveryListener.onError(com.blukii.sdk.discovery.BlukiiDiscoveryError)
and BlukiiClient.OnDiscoveryListener.onInfo(com.blukii.sdk.discovery.BlukiiDiscoveryInfo)
will be called if there is important information about the discovery process.
@Override
public void onError(BlukiiDiscoveryError errorCode) {
// An error has been sent from discovery
}
@Override
public void onInfo(BlukiiDiscoveryInfo infoCode) {
// An info has been sent from discovery
}
5. Permissions
For getting access to Android Bluetooth the app user has to give the permission.
For Bluetooth LE you need to insert the following permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
For Apps with targetSdkVersion 23 (Android 6) and later you need to add the following permission.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
For Apps with targetSdkVersion 31 (Android 12) and later you need to add the following permission:
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
For Apps with targetSdkVersion 29 (Android 10) and later that should use discovery in background
you additionally have to handle the following permission in combination with ACCESS_FINE_LOCATION
.
Therefore please read Google's manual about
access to device location in the background.
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
Please be aware that you have to handle Runtime Permissions in your App since Android 6. This blog gives you a good instruction.
Example:
@Override
protected void onCreate(Bundle savedInstanceState) {
mBlukiiClient = BlukiiController.getInstance().getDiscoveryClient();
if(!mBlukiiClient.isDiscoveryInitialized()) {
mBlukiiClient.initDiscovery(blukiiDiscoveryListener);
}
if (checkPermissions()) {
// Permission has been granted before
mBlukiiClient.startDiscovery();
} else {
// Permission has not been granted before
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT}, REQUEST_CODE_ASK_PERMISSIONS);
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_ASK_PERMISSIONS);
}
}
}
private boolean checkPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android 6 and later
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
return false;
}
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
// Permission granted or Android 5.x and earlier
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode != REQUEST_CODE_ASK_PERMISSIONS) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
return;
}
for(int grantResultIndex=0; grantResultIndex < grantResults.length; grantResultIndex++) {
if(grantResults[grantResultIndex] == PackageManager.PERMISSION_DENIED) {
// At least one permission denied
Log.e("PermissionResult", "Permission denied: code=" + grantResultIndex);
return;
}
}
// Permission Granted
mBlukiiClient.startDiscovery();
}
B. Decryption of SecureBeacon advertising
blukii SecureBeacons are encrypted to prevent third parties from misusing the Beacon identification.
The encryption is affecting the mac address and the iBeacon Major and Minor value.
You can decrypt DiscoveryData by calling decryptSecureBeacons(List, OnDecryptSecureBeaconsListener)
.
The callback BlukiiClient.OnDecryptSecureBeaconsListener.onDecryptSecureBeacons(List, int)
is
retrieving a copy of the input parameter list containing decrypted values. Each DiscoveryData
object, that has been decrypted is marked with DiscoveryData.getSecureBeaconState()
as SecureBeaconState.DECRYPTED
.
mBlukiiClient.decryptSecureBeacons(discoveryResultList, new BlukiiClient.OnDecryptSecureBeaconsListener() {
@Override
public void onDecryptSecureBeacons(List<DiscoveryData> decryptedDiscoveryDataList, int decryptedCount) {
Log.d("BlukiiClient.onDiscoveryResult: DecryptSecureBeacons successful: Count=" + decryptedCount);
}
@Override
public void onError(BlukiiCloudError error) {
Log.w("BlukiiClient.onDiscoveryResult: DecryptSecureBeacons failed: error=" + error.toString());
}
});
Note: SecureBeacons can only be decrypted by its owner, so the corresponding user needs
to be logged in (@see BlukiiCloud
).
Additionally, android.permission.INTERNET
has to be declared as 'user-permission'
in your apps manifest.
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic interface
Listener interface for callbacks ofdecryptSecureBeacons(List, OnDecryptSecureBeaconsListener)
.static interface
Callbacks for the BLE discovery. -
Field Summary
Modifier and TypeFieldDescriptionstatic final int
Default cache timeout for secure beacon decryption: 180000 milliseconds (30 minutes) -
Method Summary
Modifier and TypeMethodDescriptionvoid
decryptSecureBeacons
(List<DiscoveryData> discoveryDataList, BlukiiClient.OnDecryptSecureBeaconsListener listener) Tries to decrypt theDiscoveryData
list items that are marked withDiscoveryData.getSecureBeaconState()
asSecureBeaconState.ENCRYPTED
.int
Gets the current cache timeout for secure beacon decryption.Gets the discovery settings object.void
initDiscovery
(BlukiiClient.OnDiscoveryListener onDiscoveryListener) Initializes the discovery client and loads the needed resources.boolean
Gets the state if BLE scanner is actually running.boolean
Gets the state if the discovery is initialized.void
setDecryptSecureBeaconCacheTimeout
(int decryptSecureBeaconCacheTimeout) Sets the current cache timeout for secure beacon decryption.void
Starts the BLE scanning.void
Stops the BLE scanner.void
Terminates the discovery client.
-
Field Details
-
SECUREBEACON_CACHETIMEOUT_DEFAULT
public static final int SECUREBEACON_CACHETIMEOUT_DEFAULTDefault cache timeout for secure beacon decryption: 180000 milliseconds (30 minutes)
-
-
Method Details
-
getDiscoverySettings
Gets the discovery settings object.It is null, if discovery is not initialized!
- Returns:
DiscoverySettings
object- See Also:
-
isDiscovering
public boolean isDiscovering()Gets the state if BLE scanner is actually running.- Returns:
- true, if BLE scanner is scanning
- See Also:
-
startDiscovery
@RequiresPermission(allOf={"android.permission.BLUETOOTH","android.permission.BLUETOOTH_ADMIN","android.permission.ACCESS_FINE_LOCATION"}) public void startDiscovery()Starts the BLE scanning.If not successful an error is send by the
BlukiiClient.OnDiscoveryListener.onError(BlukiiDiscoveryError)
callbacks.During BLE scanning the BLE scanner is started and stopped internally according the discovery settings (see
DiscoverySettings
. You are getting informed by theBlukiiClient.OnDiscoveryListener.onInfo(BlukiiDiscoveryInfo)
callbacks.It only can be started if the discovery service has been initialized before by calling
initDiscovery(OnDiscoveryListener)
!You can stop scanning by calling
stopDiscovery()
. -
stopDiscovery
public void stopDiscovery()Stops the BLE scanner.You can start scanning by calling
startDiscovery()
. -
initDiscovery
Initializes the discovery client and loads the needed resources.This is required before calling
startDiscovery()
andstopDiscovery()
for starting and stopping the discovery for BLE modules.Without
startDiscovery()
DeviceDiscoveryService is not doing any action and therefore not using the battery.Note: DeviceDiscoveryService is not reliably unbound by android garbage collector. Please call
terminateDiscovery()
if you do not need the discovery any more or if you need to re-instantiate the BlukiiClient object.- Parameters:
onDiscoveryListener
- listener interface for callbacks- See Also:
-
terminateDiscovery
public void terminateDiscovery()Terminates the discovery client.Call this action if you do need the discovery client any more for releasing resources.
- See Also:
-
isDiscoveryInitialized
public boolean isDiscoveryInitialized()Gets the state if the discovery is initialized.- Returns:
- true, if discovery is initialized
-
getDecryptSecureBeaconCacheTimeout
public int getDecryptSecureBeaconCacheTimeout()Gets the current cache timeout for secure beacon decryption.If value is 0, cache is off.
- Returns:
- cache timeout in milliseconds
-
setDecryptSecureBeaconCacheTimeout
public void setDecryptSecureBeaconCacheTimeout(int decryptSecureBeaconCacheTimeout) Sets the current cache timeout for secure beacon decryption.If value is 0, cache is off.
- Parameters:
decryptSecureBeaconCacheTimeout
- cache timeout in milliseconds
-
decryptSecureBeacons
public void decryptSecureBeacons(@NonNull List<DiscoveryData> discoveryDataList, @NonNull BlukiiClient.OnDecryptSecureBeaconsListener listener) Tries to decrypt theDiscoveryData
list items that are marked withDiscoveryData.getSecureBeaconState()
asSecureBeaconState.ENCRYPTED
.If successful
BlukiiClient.OnDecryptSecureBeaconsListener.onDecryptSecureBeacons(List, int)
is called with the result list, otherwiseBlukiiClient.OnDecryptSecureBeaconsListener.onError(BlukiiCloudError)
is called.Therefore an blukii Manager user authentication via
BlukiiCloud.login(BlukiiCloud.OnLoginListener)
is needed.- Parameters:
discoveryDataList
- discoverData list that needs to be decrypted.listener
- listener forBlukiiClient.OnDecryptSecureBeaconsListener
callbacks.- See Also:
-