5

When I start ble(Bluetooth Le) scan for seconds, then stop scan. Then start, then stop... after about 5-8 Loops, the start action will be No effect ,this means no scan record can be received. 1.This condition only appears on Android 7.0 or above(7.1.1); 2.I have tried two scan method: BluetoothAdapter.startLeScan() and Scanner.startScan(), no difference .

private void scanToggle(final boolean enable) {
    mScanHandler.removeCallbacks(scanTask);
    if (enable) {
        TelinkLog.i("ADV#scanner#startScan");
        scanner = mBluetoothAdapter.getBluetoothLeScanner();
        scanner.startScan(null, settings, scanCallback);
        mScanning = true;
        mDeviceList.clear();
        mListAdapter.notifyDataSetChanged();
       //mBluetoothAdapter.startLeScan(leScanCallback);
        mScanHandler.postDelayed(scanTask, SCAN_PERIOD);
    } else {
        TelinkLog.i("ADV#scanToggle#stopScan");
        mScanning = false;
        //mBluetoothAdapter.stopLeScan(leScanCallback);
        scanner.stopScan(scanCallback);
    }
    invalidateOptionsMenu();
}


private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
        TelinkLog.d("scan:" + device.getName());
        for (AdvDevice advDevice : mDeviceList) {
            if (device.getAddress().equals(advDevice.device.getAddress())) return;
        }
        mDeviceList.add(new AdvDevice(device, rssi, scanRecord));
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mListAdapter.notifyDataSetChanged();
            }
        });
    }
};

private ScanCallback scanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);
        for (AdvDevice advDevice : mDeviceList) {
            if (result.getDevice().getAddress().equals(advDevice.device.getAddress())) return;
        }
        mDeviceList.add(new AdvDevice(result.getDevice(), result.getRssi(), result.getScanRecord().getBytes()));
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mListAdapter.notifyDataSetChanged();
            }
        });
    }

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

    @Override
    public void onScanFailed(int errorCode) {
        super.onScanFailed(errorCode);
    }
};
Daniel.Kee
  • 51
  • 1
  • 3

4 Answers4

9

You are probably running into the new and undocumented behavior changes in Android 7 that prevent apps from scanning too often.

I wrote a blog post about it: https://blog.classycode.com/undocumented-android-7-ble-behavior-changes-d1a9bd87d983

Alex Suzuki
  • 1,083
  • 10
  • 18
4

I had also this kind of problem. It is solved by enabling Location. In android, we need to enable Location for scan near by devices. So please check location is enable or not. Below code is useful. I hope it works, in my case it works good.

LocationManager manager = (LocationManager) mainActivity.getSystemService(Context.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
    buildAlertMessageNoGps(mainActivity);
}else{ //scanning part}


public void  buildAlertMessageNoGps(MainActivity mainActivity){
    final AlertDialog.Builder builder = new AlertDialog.Builder(mainActivity);
    builder.setMessage("Your GPS seems to be disabled, do you want to enable it? It is required for this application.")
            .setCancelable(false)
            .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(final DialogInterface dialog, final int id) {
                    mainActivity.startActivityForResult(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS), MainActivity.LOCATION_ENABLE);
                }
            })
            .setNegativeButton("No", new DialogInterface.OnClickListener() {
                public void onClick(final DialogInterface dialog, final int id) {
                    dialog.cancel();
                    mainActivity.finishAffinity();
                }
            });
    final AlertDialog alert = builder.create();
    alert.show();
}

After on location start scanning and get scanning result.

Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
Joshi Tushar
  • 116
  • 9
  • 1
    Tks for reply. However I test this on location opened. – Daniel.Kee Jun 20 '17 at 11:24
  • 1
    This is one possible cause, but on Android 7 other factors can come into play. Check my answer below, maybe it's the case for you. – Alex Suzuki Jun 23 '17 at 08:50
  • You will see this in Logcat : `java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results`. I don't know if `GPS_PROVIDER ` is the right permission here ... it seens a bit overkill to start a bt scan ? And undocumented... – Marcel Falliere Jan 19 '19 at 18:23
1

You need to make sure that you stop and re-start your scan only after 6 seconds for all devices with Android N and above.

This is as per the introduced restriction where apps are allowed to scan a maximum of 5 times in 30 seconds.

We’ve changed the BLE Scanning behavior starting in DP4. We’ll prevent applications from starting and stopping scans more than 5 times in 30 seconds. For long running scans, we’ll convert them into opportunistic scans.

Refer to this discussion here

Kriti Sharan
  • 281
  • 1
  • 3
  • 10
1

You will also have to include location permissions in your Manifest or else your search will not return anything. This is mandatory I would say for Bluetooth and Wifi searches.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

As the in the developer section for BLE in Android.

enter image description here

bayram.cicek
  • 193
  • 2
  • 9
Haroun Hajem
  • 5,223
  • 3
  • 26
  • 39