Android BLE-如何在ScanCallback中调用onScanResult方法?

时间:2016-02-17 03:19:41

标签: android bluetooth-lowenergy android-bluetooth

这是我第一次在Android项目中执行蓝牙低功耗。我正在做的项目基本上是检测所有蓝牙LE设备并连接它们以发现它们的服务。

我想问一下是否有人知道如何在ScanCallback中调用onScanResult(),onBatchScanResults()和onScanFailed()方法?

首先,运行scanLeDevice()方法。

BluetoothLeScanner mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
ScanSettings settings = new ScanSettings.Builder()
           .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
           .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
           .build();
List<ScanFilter> filters = new ArrayList<ScanFilter>();

scanLeDevice(true);

在这种方法中,它将启动扫描。所以我假设扫描结果是使用这些回调传递的。

@TargetApi(21)
private void scanLeDevice(final boolean enable) {
    if (enable) {
        //stops scanning after a pre-defined scan period
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                    System.out.println("BLE// mLEScanner.stopScan(mScanCallback) ");
                    mLEScanner.stopScan(mScanCallback);
                }
            }
        }, SCAN_PERIOD);
            System.out.println("BLE// mLEScanner.startScan(filters, settings, mScanCallback)");
            mLEScanner.startScan(filters, settings, mScanCallback);

    } else {
            System.out.println("BLE// mLEScanner.stopScan(mScanCallback)");
            mLEScanner.stopScan(mScanCallback);
    }
}

但是,在ScanCallback中,我不知道它是如何触发onScanResult并使用回调传递扫描结果的。在我的测试中(如下所示),既不调用onScanResult()也不调用onBatchScanResults()和onScanFailed()。有人可以向我解释这个概念吗?这对我有很大的帮助!

 /* Scan result for SDK >= 21 */
 private ScanCallback mScanCallback = new ScanCallback() {

    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        System.out.println("BLE// onScanResult");
        Log.i("callbackType", String.valueOf(callbackType));
        Log.i("result", result.toString());
        BluetoothDevice btDevice = result.getDevice();
        connectToDevice(btDevice);
    }

    @Override
    public void onBatchScanResults(List<ScanResult> results) {
        System.out.println("BLE// onBatchScanResults");
        for (ScanResult sr : results) {
            Log.i("ScanResult - Results", sr.toString());
        }
    }

    @Override
    public void onScanFailed(int errorCode) {
        System.out.println("BLE// onScanFailed");
        Log.e("Scan Failed", "Error Code: " + errorCode);
    }

};
02-17 10:38:38.513 878-895/? D/BluetoothManagerService: Added callback: android.bluetooth.IBluetoothManagerCallback$Stub$Proxy@8334cf4:true
02-17 10:38:38.520 782-782/? D/BluetoothAdapter: STATE_ON
02-17 10:38:38.529 21554-21590/? D/BtGatt.GattService: registerClient() - UUID=835342c6-81eb-4e09-9729-5bbe1c22bc86
02-17 10:38:38.529 21554-21570/? D/BtGatt.GattService: onClientRegistered() - UUID=835342c6-81eb-4e09-9729-5bbe1c22bc86, clientIf=5
02-17 10:38:38.530 782-793/? D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=5
02-17 10:38:38.530 21554-21599/? D/BtGatt.GattService: start scan with filters

02-17 10:38:38.532 782-782/? I/System.out: BLE// mLEScanner.startScan(filters, settings, mScanCallback)
02-17 10:38:38.532 21554-21573/? D/BtGatt.ScanManager: handling starting scan
02-17 10:38:38.534 21576-21577/? I/WCNSS_FILTER: ibs_msm_serial_clock_vote: vote UART CLK ON using UART driver's ioctl()
02-17 10:38:38.542 21554-21570/? D/BtGatt.GattService: onScanFilterEnableDisabled() - clientIf=5, status=0, action=1
02-17 10:38:38.543 21554-21570/? D/BtGatt.ScanManager: callback done for clientIf - 5 status - 0
02-17 10:38:38.543 21554-21573/? D/BtGatt.ScanManager: configureFilterParamter 500 10000 1 0
02-17 10:38:38.547 21554-21570/? D/BtGatt.GattService: onScanFilterParamsConfigured() - clientIf=5, status=0, action=0, availableSpace=15
02-17 10:38:38.547 21554-21570/? D/BtGatt.ScanManager: callback done for clientIf - 5 status - 0
02-17 10:38:38.548 21554-21573/? D/BtGatt.ScanManager: configureRegularScanParams() - queue=1
02-17 10:38:38.548 487-2827/? I/ACDB-LOADER: ACDB AFE returned = -19
02-17 10:38:38.549 21554-21573/? D/BtGatt.ScanManager: configureRegularScanParams() - ScanSetting Scan mode=0 mLastConfiguredScanSetting=-2147483648
02-17 10:38:38.549 21554-21573/? D/BtGatt.ScanManager: configureRegularScanParams - scanInterval = 8000configureRegularScanParams - scanWindow = 800
02-17 10:38:38.549 21554-21570/? D/BtGatt.GattService: onScanParamSetupCompleted : 0
02-17 10:38:38.568 21554-21574/? W/bt_hci: filter_incoming_event command complete event with no matching command. opcode: 0x0.
02-17 10:38:38.603 21554-21570/? D/bt_btif_gattc: btif_gattc_update_properties BLE device name=Polar HR Sensor len=15 dev_type=2
02-17 10:38:39.571 21576-21585/? I/WCNSS_FILTER: ibs_msm_serial_clock_vote: vote UART CLK OFF using UART driver's ioctl()

02-17 10:38:43.526 782-782/? I/System.out: BLE// mLEScanner.stopScan(mScanCallback) 
02-17 10:38:43.599 21576-21576/? I/WCNSS_FILTER: ibs_msm_serial_clock_vote: vote UART CLK ON using UART driver's ioctl()
02-17 10:38:43.967 21576-21576/? I/WCNSS_FILTER: ibs_msm_serial_clock_vote: vote UART CLK OFF using UART driver's ioctl()

使用带有API 23的Android手机

我在这里写的代码是:http://www.truiton.com/2015/04/android-bluetooth-low-energy-ble-example/

[更新的代码V1] - 无法正常工作

这是我的所有代码 我创建了一个虚拟外围设备,它处于广告模式。虚拟外围设备是通过名为LightBlue的应用程序创建的:https://itunes.apple.com/us/app/lightblue-explorer-bluetooth/id557428110?mt=8 请帮我查一下我的代码:)

@TargetApi(21)
public class BluetoothLE extends Fragment {

View view;

private BluetoothAdapter mBluetoothAdapter;
private int REQUEST_ENABLE_BT = 1;
private Handler mHandler;
private static final long SCAN_PERIOD = 5000;  // Stops scanning after 5 seconds
private BluetoothLeScanner mLEScanner;
private BluetoothGatt mGatt; //To provide bluetooth communication
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
private int permissionCheck;

public BluetoothLE(){
    //empty constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment

    view = inflater.inflate(R.layout.fragment_bluetooth, container, false);
    mHandler = new Handler();

    /* check if BLE is supported in this phone */
    if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        Toast.makeText(getActivity(), "BLE Not Supported", Toast.LENGTH_SHORT).show();
        getActivity().finish();
    }

    /* Enable bluetooth without leaving app */
    final BluetoothManager bluetoothManager =
            (BluetoothManager) getActivity().getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();

    /* Build ScanSetting */
    ScanSettings.Builder scanSetting = new ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
            .setReportDelay(5000);

    settings = scanSetting.build();


    return view;
}

@TargetApi(Build.VERSION_CODES.M)
@Override
public void onResume() {
    super.onResume();

    /* Ensures Bluetooth is available on the device and it is enabled. If not, displays a dialog requesting user permission to enable Bluetooth. */
    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {  //Unable to obtain a BluetoothAdapter
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); //trigger onActivityResult

    } else {
        if (Build.VERSION.SDK_INT >= 21) {
            mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
            settings = new ScanSettings.Builder()
                    .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
                    .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
                    .build();
            filters = new ArrayList<ScanFilter>();
        }

        if(Build.VERSION.SDK_INT >= 23){
            checkLocationPermission();
        }

        scanLeDevice(true);
    }
}

@Override
public void onPause() {
    super.onPause();
    if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
        scanLeDevice(false);
    }
}

@Override
public void onDestroy() {
    if (mGatt == null) {
        return;
    }
    mGatt.close();
    mGatt = null;
    super.onDestroy();
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    System.out.println("BLE// onActivityResult");
    if (requestCode == REQUEST_ENABLE_BT) {
        if (resultCode == Activity.RESULT_CANCELED) {
            //Bluetooth not enabled.
            getActivity().finish();
            return;
        }
    }
    super.onActivityResult(requestCode, resultCode, data);
}

private void scanLeDevice(final boolean enable) {
    if (enable) {
        //stops scanning after a pre-defined scan period
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (Build.VERSION.SDK_INT < 21) {
                    System.out.println("BLE// mBluetoothAdapter.stopLeScan(mLeScanCallback) ");
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                } else {
                    mLEScanner.stopScan(mScanCallback);
                    System.out.println("BLE// mLEScanner.stopScan(mScanCallback) ");
                }
            }
        }, SCAN_PERIOD);

        if (Build.VERSION.SDK_INT < 21) {
            System.out.println("BLE// mBluetoothAdapter.startLeScan(mLeScanCallback)");
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {

            mLEScanner.startScan(mScanCallback);
            //mLEScanner.startScan(filters, settings, mScanCallback);
            System.out.println("BLE// mLEScanner.startScan(mScanCallback) ");
        }
    } else {
        if (Build.VERSION.SDK_INT < 21) {
            System.out.println("BLE// mBluetoothAdapter.stopLeScan(mLeScanCallback)");
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        } else {
            System.out.println("BLE// mLEScanner.stopScan(mScanCallback)");
            mLEScanner.stopScan(mScanCallback);
        }
    }
}

/* Scan result for SDK >= 21 */
private ScanCallback mScanCallback = new ScanCallback() {

    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        System.out.println("BLE// onScanResult");
        super.onScanResult(callbackType, result);

        Log.i("callbackType", String.valueOf(callbackType));
        Log.i("result", result.toString());
        Log.i("Device Name: ", result.getDevice().getName());
        System.out.println("Signal: " + result.getRssi());

        BluetoothDevice btDevice = result.getDevice();
        connectToDevice(btDevice);
    }

    @Override
    public void onBatchScanResults(List<ScanResult> results) {
        System.out.println("BLE// onBatchScanResults");
        for (ScanResult sr : results) {
            Log.i("ScanResult - Results", sr.toString());
        }
    }

    @Override
    public void onScanFailed(int errorCode) {
        System.out.println("BLE// onScanFailed");
        Log.e("Scan Failed", "Error Code: " + errorCode);
    }

};

// scan results are returned here SDK < 21
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(final BluetoothDevice device, int rssi,
                         byte[] scanRecord) {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                System.out.println("BLE// DEVICDE FOUND");

                Log.i("onLeScan", device.toString());

                connectToDevice(device);
            }
        });
    }
};

public void connectToDevice(BluetoothDevice device) {
    System.out.println("BLE// connectToDevice()");
    if (mGatt == null) {
        mGatt = device.connectGatt(getActivity(), false, gattCallback); //Connect to a GATT Server
        //scanLeDevice(false);// will stop after first device detection
    }
}

private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        System.out.println("BLE// BluetoothGattCallback");
        Log.i("onConnectionStateChange", "Status: " + status);
        switch (newState) {
            case BluetoothProfile.STATE_CONNECTED:
                Log.i("gattCallback", "STATE_CONNECTED");
                gatt.discoverServices();
                break;
            case BluetoothProfile.STATE_CONNECTING:
                Log.i("gattCallback", "STATE_CONNECTING");
                break;
            case BluetoothProfile.STATE_DISCONNECTED:
                Log.e("gattCallback", "STATE_DISCONNECTED");
                break;
            default:
                Log.e("gattCallback", "STATE_OTHER");
        }
    }

    @Override
    //New services discovered
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        List<BluetoothGattService> services = gatt.getServices();
        Log.i("onServicesDiscovered", services.toString());
        gatt.readCharacteristic(services.get(1).getCharacteristics().get
                (0));
    }

    @Override
    //Result of a characteristic read operation
    public void onCharacteristicRead(BluetoothGatt gatt,
                                     BluetoothGattCharacteristic
                                             characteristic, int status) {
        Log.i("onCharacteristicRead", characteristic.toString());
        gatt.disconnect();
    }
};

public void checkLocationPermission(){
    permissionCheck = ContextCompat.checkSelfPermission(getActivity(), android.Manifest.permission.ACCESS_COARSE_LOCATION);

    switch(permissionCheck){
        case PackageManager.PERMISSION_GRANTED:
            break;

        case PackageManager.PERMISSION_DENIED:

            if(ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), android.Manifest.permission.ACCESS_COARSE_LOCATION)){
                //Show an explanation to user *asynchronouselly* -- don't block
                //this thread waiting for the user's response! After user sees the explanation, try again to request the permission

                Snackbar.make(view, "Location access is required to show Bluetooth devices nearby.",
                        Snackbar.LENGTH_LONG).setAction("Action", null).show();

            }
            else{
                //No explanation needed, we can request the permission
                ActivityCompat.requestPermissions(getActivity(), new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
            }
            break;
    }
}
}

2 个答案:

答案 0 :(得分:13)

所以..我终于找到了答案。 对于Android 6.0或更高版本的Android设备(例如我的手机是Nexus 5x),手机设置中的 GPS 蓝牙都必须打开,另外在您的清单中必须添加BLUETOOTH BLUETOOTH_ADMIN ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION权限。

现在一切正常对我来说:)

答案 1 :(得分:10)

我发现您使用的是public void startScan (List<ScanFilter> filters, ScanSettings settings, ScanCallback callback) startScan()方法,但您从未定义任何过滤器。而是传递一个空的ScanFilters ArrayList。因此,您无法获得任何回调,因为您没有为过滤器提供任何匹配标准。

由于您说要扫描所有 BLE设备,因此根本不需要使用任何过滤器。相反,请使用更简单的public void startScan (ScanCallback callback)方法,该方法不使用任何过滤器或专门设置。

关于你理解它是如何工作的请求 - 我认为你根据你的代码以及你应该触发回调的期望来理解这个概念。您开始扫描,系统关闭并执行扫描而不会阻止您的代码执行(即它是异步执行)。在扫描发生时,它会在适当的时候调用回调对象中的三个方法之一(如API文档中所述)。这就是它。

<强>更新: 确保您请求BLUETOOTH,BLUETOOTH_ADMIN权限以及ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION权限。这些是从startScan()方法接收回调所必需的。不幸的是,如果您没有请求这些持久性,那么扫描就会无声地失败。我希望系统在日志中提供警告消息或触发对onScanFailed()方法的回调,并使用错误代码指示问题。

相关问题