Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bluetooth LE Scanning Sometimes Doesn't Find Devices

Tags:

I am scanning for Bluetooth LE devices and running as a Peripheral (running Android 6.0 on a Moto G 2nd Gen)

The problem I am having is that sometimes (randomly it seems but often) it will not find any of my other peripheral devices, the other times it works fine.

I have a companion iOS device running similar code (both scanning for peripherals and acting as a peripheral), and when the Android scanning can't find the iOS device, my iOS finds the Android device acting as a peripheral just fine. So it seems only to be a problem with the scanning side of things.

It's not only just not finding my companion iOS device, but doesn't find any Bluetooth devices. When it works, it finds my companion iOS device as well as a bunch of other devices.

I have tried it with and without ScanFilters, and get the same issue. I am building against SDK 26 with a minimum SDK of 23.

I am setting the permissions that are needed, as it sometimes works.

Relevant code below:

private void startScanning() {
    mHandler = new Handler(mContext.getMainLooper());

    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            ScanSettings settings = new ScanSettings.Builder()
                                        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                                        .setReportDelay(0)
                                        .build();

            mBluetoothLeScanner.startScan(null, settings, mScanCallback);
        }
    }, 1000);
}

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

        if( result == null || result.getDevice() == null )
            return;

        Log.e("myTest", "Found Device");

        BluetoothDevice device = result.getDevice();
        final String deviceAddress = device.getAddress();

        List<ParcelUuid> parcel = result.getScanRecord().getServiceUuids();

        if (parcel != null) {
            String parcelUUID = parcel.toString().substring(1,37);

            if (parcelUUID.equalsIgnoreCase(mContext.getString(R.string.service_uuid))) {
                final BluetoothDevice bleDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(deviceAddress);

                if (!seenPeripherals.contains(deviceAddress)) {
                    stopScanning();

                    mHandler = new Handler(mContext.getMainLooper());

                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            Log.e("AppToApp", "Trying to connect to device " + deviceAddress);

                            mGatt = bleDevice.connectGatt(mContext, false, mGattCallback);
                        }
                    }, 1000);
                }
            }
        }   
    }
}
like image 653
kdbdallas Avatar asked Oct 31 '17 18:10

kdbdallas


People also ask

How do I find hidden Bluetooth devices on Android?

Using this property of Bluetooth, an app called Wunderfind for iPhone or Android can help you physically locate a lost, hidden, or unknown Bluetooth device using your smartphone. This includes PCs, laptops, tablets, smartphones, Bluetooth headphones, Airpods, smartwatches, smart home devices, and more.

How do I find Bluetooth nearby devices?

Using the BluetoothAdapter , you can find remote Bluetooth devices either through device discovery or by querying the list of paired devices. Make sure you have the appropriate Bluetooth permissions and set up your app for Bluetooth before attempting to find Bluetooth devices.


2 Answers

I face the same issue. This is because Google policy has been changed for Marshmallow API 23 and higher version, to use BLE user need to turn ON GPS. For Google Docs check this Permission @ Runtime link. To fix it you have to enable "Location" in the settings of the phone as well as request location permission in the app at Runtime. Both need to be done for scanning to work properly.

To request the location permission put the following in a dialog or the likes:

myActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_COURSE_LOCATION}, yourPermissionRequestCode);

and implement:

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] Results){
    if(requestCode == yourPermissionRequestCode)
    {
        ... //Do something based on Results
    }
}

in myActivity handle whatever the user selects. You also need to do the following to turn on your device's location services:

Intent enableLocationIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
myActivity.startActivityForResult(enableLocationIntent, yourServiceRequestCode);

You can check if the user turned on the location services by implementing:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    if(requestCode == yourServiceRequestCode)
    {
        ...//Do whatever you need to
    }
}

in myActivity. You can also manually turn on location services by doing:

Enter phone settings -> Select "Apps" -> Select your app -> Select the "Permissions" option -> Switch the "Location" permission on.

Once the user has enabled the permission and started location services then you could start scanning for peripherals. I've noticed that if you are already scanning while you enable the permission/turn on the location service it will still not put anything in your onScanResults

This allow companies to see your location and direct you to where they want.

while SCANNING for device, Once you are connected to the BLE device you can Turn Off the location service on your phone and you will still stay connected to your peripheral device. However, once you connected to a firmware (peripheral) you cannot then connect to any new peripheral until you disconnect the connection to the paired device, and all other scanning devices(mobile) cannot see the peripheral device name in their scanned list (when user search for near by peripheral device) when the peripheral is already connected to any other mobile device, because a peripheral can be connect to only 1 device at a time. For BLE basic sample you can check this Truiton Ble tutorial. This snippet will fix your Issue I think. Happy coding :)

like image 95
anand krish Avatar answered Dec 01 '22 00:12

anand krish


It might just simply be the case that the Android phone has a crappy Bluetooth chip. Have you looked at the hci log? Or logcat?

Bluetooth 4.0 chips (which is in your moto g) have strict limitations that you can't be a central and a peripheral at the same time, even though scanning should be allowed all the time. Therefore I wouldn't make a product that depends on the peripheral feature in Android until BT 4.0 is phased out.

You should test with a newer phone that has at least a Bluetooth 4.1 chip.

like image 31
Emil Avatar answered Nov 30 '22 23:11

Emil