androidbluetooth-lowenergyandroid-bluetoothandroid-ble

BLE Scan Freezes UI thread after 20 mins


I am trying to scan BLE devices continuously for a research project. I use LOW_LATENCY mode of BLE scanning. However, after 20 mins or so my UI freezes.

Basically I press button it should start scanning for BLE devices, and when I press the button again, it should stop scanning. I want to scan for at least 2 hours continuously. The following is my code.

 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    toggle = (ToggleButton) findViewById(R.id.toggleButton); // initiate a toggle button
    tv = (TextView) findViewById(R.id.tv);

        EasyPermissions.requestPermissions(this, "need permission", 1001, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.BLUETOOTH,Manifest.permission.BLUETOOTH_ADMIN);
     // Check BLE support for the device
    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        Toast.makeText(getApplicationContext(),"no bluetooth LE functionality", Toast.LENGTH_SHORT).show();
        finish();
    }
    btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
    btAdapter = btManager.getAdapter();
    bLEScanner = btAdapter.getBluetoothLeScanner();
    settings = new ScanSettings.Builder()
            .setScanMode(SCAN_MODE_LOW_LATENCY)
            .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
            .build();
    toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @TargetApi(Build.VERSION_CODES.N)
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {
                Toast.makeText(getApplicationContext(), "Scanning started",
                        Toast.LENGTH_SHORT).show();
                // The toggle is enabled
                bFileName = getBluetoothFileName("Bluetooth");
                bLEScanner.startScan(null,settings,bluetoothLeScanCallback);
            } else {
                // The toggle is disabled
                Toast.makeText(getApplicationContext(), "Scanning stopped",
                        Toast.LENGTH_SHORT).show();
                bLEScanner.stopScan(bluetoothLeScanCallback);
            }
        }
    });
}

Scan Callback code

private ScanCallback bluetoothLeScanCallback = new ScanCallback() {
 @Override
 public void onScanResult(int callbackType,  android.bluetooth.le.ScanResult result) {
     byte[] scanRecord = result.getScanRecord().getBytes();
     int startByte = 2;
     boolean patternFound = false;
     while (startByte <= 5)
     {
         if (    ((int) scanRecord[startByte + 2] & 0xff) == 0x02 && //Identifies an iBeacon
                 ((int) scanRecord[startByte + 3] & 0xff) == 0x15)
         { //Identifies correct data length
             patternFound = true;
             break;
         }
         startByte++;
     }

     if (patternFound)
     {
         //Convert to hex String
         byte[] uuidBytes = new byte[16];
         System.arraycopy(scanRecord, startByte + 4, uuidBytes, 0, 16);
         String hexString = bytesToHex(uuidBytes);

         //UUID detection
         String uuid =  hexString.substring(0,8) + "-" +
                 hexString.substring(8,12) + "-" +
                 hexString.substring(12,16) + "-" +
                 hexString.substring(16,20) + "-" +
                 hexString.substring(20,32);

         // major
         final int major = (scanRecord[startByte + 20] & 0xff) * 0x100 + (scanRecord[startByte + 21] & 0xff);

         // minor
         final int minor = (scanRecord[startByte + 22] & 0xff) * 0x100 + (scanRecord[startByte + 23] & 0xff);

         Log.i("BLE","UUID: " +uuid + " nmajor : " +major +" nminor " +minor+" time "+getCompleteDate(System.currentTimeMillis())+" rssi "+result.getRssi());
         StringBuilder bStringBuilder = new StringBuilder();
         long sysTime = System.currentTimeMillis();
         bStringBuilder.append(imei+","+sysTime+","+uuid+","+major+","+minor+","+result.getRssi()+","+getCompleteDate(sysTime)+","+"\n");
         String finalString = bStringBuilder.toString();
         exportBluetoothData(finalString, finalString.length(), "Bluetooth");

     }
 }
     @Override
 public void onScanFailed(int errorCode) {
     super.onScanFailed(errorCode);
     Log.i("BLE", "error");
 }
 };

Will it be helpful to use AsyncTask for this kind of long operation? Any guide would be highly appreciated. Thanks.


Solution

  • I used SCAN_MODE_BALANCED instead of SCAN_MODE_LOW_LATENCY Now it doesn't freeze the thread. Thank you for all your answers.