简体   繁体   中英

Problem in scanning Bluetooth LE devices (no callback)

I am trying to develop an Android app capable to connect to a BLE device. But i have a problem to find ble devices. The scanLeDevice methods run but I have no callback. You can find my code below: I use Log.i() to display ble devices. With another app (downloaded from the store) I can find my ble device and others bluetooth around. So It's not my phone's problem.

Thanks for help!




public class MainActivity extends AppCompatActivity {
    private BluetoothAdapter bluetoothAdapter;
    private final int REQUEST_ENABLE_BT = 1;
    private boolean mScanning;

    // Stops scanning after 10 seconds.
    private static final long SCAN_PERIOD = 10000;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i("MainActivity", "Begin");

        // Initializes Bluetooth adapter.
        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();
        // Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
        if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }
        Log.i("MainActivity", "End for permissions");

        if(Build.VERSION.SDK_INT < 21){
            scanLeDevice(true);
        }else{
            scanDevice(true);
        }

    }

    private Handler handler = new Handler();
    private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    bluetoothAdapter.stopLeScan(leScanCallback);
                }
            }, SCAN_PERIOD);

            mScanning = true;
            bluetoothAdapter.startLeScan(leScanCallback);
            Log.i("MainActivity", "scanning");
        } else {
            mScanning = false;
            bluetoothAdapter.stopLeScan(leScanCallback);
        }

    }

    // Device scan callback.
    private BluetoothAdapter.LeScanCallback leScanCallback =
            new BluetoothAdapter.LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice device, int rssi,
                                     byte[] scanRecord) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //Ici///////////////////////////////////////
                            Log.i("MainActivity", "Nam: "+device.getName()+" Adresse: "+device.getAddress());
                            if(device.getName() != null && device.getName().equals("RN4871-85D7"))
                                scanLeDevice(false);
                        }
                    });
                }
            };

    ///////////////////Scan for API 21
    private ScanSettings settings;
    private List<ScanFilter> filters;
    private BluetoothLeScanner mLEScanner;
    private void scanDevice(final boolean enable){
        if (mLEScanner==null){
            mLEScanner = bluetoothAdapter.getBluetoothLeScanner();
            settings = new ScanSettings.Builder()
                    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                    .build();
            filters = new ArrayList<ScanFilter>();
        }

        if (enable) {
            if (mScanning) return;
            // Stops scanning after a pre-defined scan period.
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (!mScanning) return;
                    try {
                        mScanning = false;
                        //Log.d("MainActivity","STOP SCAN AFTER DELAY");
                        mLEScanner.stopScan(mScanCallback);
                        Log.i("MainActivity", "stop scanning API 21");
                    } catch (Exception e){Log.e("MainActivity",e.getMessage());}
                }
            }, SCAN_PERIOD);

            mScanning = true;
            //Log.d("MainActivity","START SCAN FROM EXPLICIT CALL");
            mLEScanner.startScan(filters, settings, mScanCallback);
            Log.i("MainActivity", "scanning API 21");
        } else  if (mLEScanner!=null){
            if (!mScanning) return;
            mScanning = false;
            try {
                //Log.d("MainActivity","STOP SCAN FROM EXPLICIT CALL");
                mLEScanner.stopScan(mScanCallback);
                Log.i("MainActivity", "stop scanning API 21");
            } catch (Exception e){Log.i("MainActivity",e.getMessage());}
        }
    }

    //call back for API 21
    //@TargetApi(21)
    private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            Log.i("MainActivity", "onScanResult API 21");
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);
            Log.i("MainActivity", "onBatchScanResults API 21");
        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
            Log.i("MainActivity", "onScanFailed API 21");
        }
    };

}

Thanks for your help``

I found what was the problem about the location. In fact, if you work with a API >= 23, you have to authorize you app to access to the location (not only in the Manifest file, but in you code it self). So if you have the same problem:

  1. First, manualy, go to your phon's setting and autorize your app to access to location: to be sure that was the problem.
  2. Then add the code below so that, The application ask the user to authorize the application to access the location

    /////////////////////////Location/////
    @TargetApi(Build.VERSION_CODES.M)
    private void loadPermissions(String perm,int requestCode) {
        if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, perm)) {
                ActivityCompat.requestPermissions(this, new String[]{perm},requestCode);
            }
        } else if (checkLocationEnabled())
            initScanner();
    }
    private boolean checkLocationEnabled(){
        LocationManager lm = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
        boolean gps_enabled = false;
        boolean network_enabled = false;

        try {
            gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        } catch(Exception ex) {}

        try {
            network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        } catch(Exception ex) {}

        if(!gps_enabled && !network_enabled) {
            // notify user
            AlertDialog.Builder dialog = new AlertDialog.Builder(this);
            dialog.setMessage("GPS desabled");
            dialog.setPositiveButton("Open GPS settings", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                    // TODO Auto-generated method stub
                    Intent myIntent = new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivity(myIntent);
                    //get gps
                }
            });
            dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                    // TODO Auto-generated method stub

                }
            });
            dialog.show();
            return false;
        } else return true;
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQUEST_FINE_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // granted
                    if (checkLocationEnabled())
                        initScanner();
                }
                else{
                    // no granted
                }
                return;
            }

        }

    }

I had this problem too because I was using ACCESS_COARSE_LOCATION on the permission.

When I changed to ACCESS_FINE_LOCATION , it finally works for me!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM