Class BlukiiClient

java.lang.Object
com.blukii.sdk.discovery.BlukiiClient

public final class BlukiiClient extends Object
Main controller class of package discovery, for discovering BLE modules and their advertised data

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:

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.