0
votes

One of the features of the app I am developing involves the synchronization of data with a BLE enabled device.

I am developing the Bluetooth functionality in a separate app (which can be seen in the code below) and will include it in the main app once it is working.

My problem has to do with the scanning of BLE devices. when I execute my code, it never executes the LE ScanCallback, so I obviously cannot proceed with transferring data etc.

I have read the Android Developers documentation at https://developer.android.com/guide/topics/connectivity/bluetooth-le and I have read similar questions on Stack Overflow, like this one at Android BLE- How is onScanResult method being called in ScanCallback? without success.

The device running the app has Android version 9 (API 28) and I am sure that the BLE devices in range are discoverable (I have checked with other apps and the built in Bluetooth search).

In the manifest, I have given permission to BLUETOOTH, BLUETOOTH_ADMIN, ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION. I have ensured that my location is enabled when I run the code, all to no prevail.

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_ENABLE_BT = 0;
    private static final int REQUEST_DISCOVERABLE_BT = 0;
    private static final long SCAN_PERIOD = 20000;
    private String TAG = "Tag: ";

    private BluetoothAdapter mBluetoothAdapter;
    private boolean mScanning;
    private Handler mHandler;

    private ArrayList<BluetoothDevice> mScannedDevices;

    private ScanCallback mLeScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);

            System.out.println("BLE// onScanResult");
            Log.i("callbackType", String.valueOf(callbackType));
            Log.i("result", result.toString());
            Log.i("Device Name: ", result.getDevice().getName());

            BluetoothDevice btDevice = result.getDevice();
            mScannedDevices.add(btDevice);
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);

            System.out.println("BLE// onBatchScanResults");
            for (ScanResult sr : results) {
                Log.i("ScanResult - Results", sr.toString());
            }
        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);

            System.out.println("BLE// onScanFailed");
            Log.e("Scan Failed", "Error Code: " + errorCode);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialise variables
        mScannedDevices = new ArrayList<>();
        mHandler = new Handler();

        // Initializes Bluetooth adapter.
        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();

        // Check if device supports Bluetooth
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "Device DOES NOT support Bluetooth", Toast.LENGTH_LONG).show();
            // Disable bluetooth interactivity
            // ...
        } else {
            Toast.makeText(this, "Device DOES support Bluetooth", Toast.LENGTH_LONG).show();
        }

    }

    public void btOn(View v) {
        // Enable Bluetooth
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
            Toast.makeText(this, "Turned on", Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(this, "Already on", Toast.LENGTH_LONG).show();
        }
    }

    public void btOff(View v) {
        mBluetoothAdapter.disable();
        Toast.makeText(getApplicationContext(), "Turned off", Toast.LENGTH_LONG).show();
    }

    public void btDiscoverable(View v) {
        Intent enableBTVisibility = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        startActivityForResult(enableBTVisibility, REQUEST_DISCOVERABLE_BT);
    }

    public void btSearch(View v) {
        mScannedDevices.clear();
        scanLeDevice(true);
    }

    public void btStopSearch(View v) {
        scanLeDevice(false);
    }

    private void scanLeDevice(final boolean enable) {
        // Ensure Bluetooth and Location are on
        // ...

        // Bluetooth scanner object
        final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();

        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    bluetoothLeScanner.stopScan(mLeScanCallback);
                }
            }, SCAN_PERIOD);

            mScanning = true;
            bluetoothLeScanner.startScan(mLeScanCallback);
        } else {
            mScanning = false;
            bluetoothLeScanner.stopScan(mLeScanCallback);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        scanLeDevice(false);
        mScannedDevices.clear();
    }

}

I expect the mLeScanCallback to be executed, however it never is (I have checked with stop points in debugging mode and I have checked the logs).

I have never worked with Bluetooth in Android before, so I fear I may be misunderstanding how it works.

1

1 Answers

0
votes

Make sure that you request the BLUETOOTH, BLUETOOTH_ADMIN permissions, as well as the ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permissions. Unfortunately, if you don't request those persmissions, the scan just silently fails.