Android BLE Gatt连接更改状态

时间:2017-07-12 11:34:26

标签: android bluetooth android-bluetooth android-ble bluetooth-gatt

我有一个Android应用程序连接到BLE设备并写入它。我可以成功连接,读取和写入它。作为测试的一部分,我们正在尝试不同的断开连接。

有时,如果ble设备断开连接,我将连接更改为断开,状态值为19.此外,如果存在任何绑定错误,则状态等于22.如果我以编程方式断开连接,则此状态为0。但是android documentation中没有指定除0以外的这些状态。

发布示例BluetoothGattCallback

private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        Log.i(TAG, "onConnectionStateChange status: "+status+", newState: "+newState);
        /*i need to know the posiible values for this status variable*/
        if(newState == BluetoothProfile.STATE_CONNECTED) {
            gatt.discoverServices();
        } else {
            gatt.close();
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        Log.i(TAG, "onServicesDiscovered service discovered");
    }
};

是否有人遇到同样的问题并整理出状态列表。我需要知道onConnectionStateChange方法

中状态变量的可能值

3 个答案:

答案 0 :(得分:11)

以下是我拥有的代码列表

  • 以编程方式断开连接 - 0
  • 设备超出范围 - 8
  • 由设备断开连接 - 19
  • 债券发行问题 - 22
  • 找不到设备 - 133(有些电话给62)

我在5.0.2,5.1,6.0和6.0.1中测试了断开连接方案。但只在6.0.1安卓版中找到了这个债券发行代码。

答案 1 :(得分:1)

很抱歉提出一个老问题,但这是我使用蓝牙(BLE)4.0遇到的许多问题的解决方案。再次抱歉以下大类,但请确保它们是必需的,并且没有任何方法无关或未使用。

 try {
            Connection con = (Connection) DriverManager.getConnection("jdbc:mysql://localhost/customerinfo", "root", "");
            Statement st = con.createStatement();
            ResultSet rs;
            String mysqlQuery = "SELECT `sellingprice` FROM cust_info";
            rs =st.executeQuery(mysqlQuery);
            int totalValue = 0; //<-- Create your total value outside of the while statement.
            while(rs.next()) {
                String total = rs.getString("sellingprice");
                totalValue += Integer.parseInt(total);//<-- Add the selling price from the current row to the total.
                System.out.println(totalValue); //<--This will print the latest total for each row in your result set
            }
            System.out.println(totalValue); //<-- This will print only the final total
        }catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }      

避免上面使用的问题的关键方法和功能是:

  • public abstract class AbstractBluetoothBroadcaster extends BroadcastReceiver { protected static final String LOG_TAG = BluetoothLowEnergy.LOG_TAG; protected BluetoothLowEnergy bluetoothLowEnergy; public AbstractBluetoothBroadcaster(BluetoothLowEnergy bluetoothLowEnergy, String action){ super(); this.bluetoothLowEnergy = bluetoothLowEnergy; IntentFilter intentFilterStateChange = new IntentFilter(action); intentFilterStateChange.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); this.bluetoothLowEnergy.getActivity().registerReceiver(this, intentFilterStateChange); } public void onDestroy(){ this.bluetoothLowEnergy.getActivity().unregisterReceiver(this); } } public class BluetoothBondStateBroadcaster extends AbstractBluetoothBroadcaster { private BluetoothLowEnergy bluetoothLowEnergy; private boolean deviceBonded; public BluetoothBondStateBroadcaster(BluetoothLowEnergy bluetoothLowEnergy) { super(bluetoothLowEnergy, BluetoothDevice.ACTION_BOND_STATE_CHANGED); this.bluetoothLowEnergy = bluetoothLowEnergy; this.deviceBonded = false; } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action == null){ return; } BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED) && bluetoothDevice != null && bluetoothDevice.getAddress().equals(bluetoothLowEnergy.getDeviceUUID())) { int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); switch (state) { case BluetoothDevice.BOND_NONE: Log.d(LOG_TAG, " NOT BONDED - dev " + bluetoothDevice.getAddress()); this.deviceBonded = false; break; case BluetoothDevice.BOND_BONDING: Log.d(LOG_TAG, " BONDING ... - dev " + bluetoothDevice.getAddress()); break; case BluetoothDevice.BOND_BONDED: Log.d(LOG_TAG, " BONDED - dev " + bluetoothDevice.getAddress()); deviceBonded = true; bluetoothLowEnergy.onBluetoothBonded(); break; default: break; } } } public void resetDeviceBonded(){ this.deviceBonded = false; } public boolean isDeviceBonded() { return deviceBonded; } } public class BluetoothPairingBroadcaster extends AbstractBluetoothBroadcaster { private String devicePIN; public BluetoothPairingBroadcaster(BluetoothLowEnergy bluetoothLowEnergy){ super(bluetoothLowEnergy, BluetoothDevice.ACTION_PAIRING_REQUEST); this.devicePIN = ""; } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action == null){ return; } BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); int pairingType = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR); if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST) && bluetoothDevice != null && bluetoothDevice.getAddress().equals(bluetoothLowEnergy.getDeviceUUID()) && !getDevicePIN().isEmpty()) { if (pairingType == BluetoothDevice.PAIRING_VARIANT_PIN){ bluetoothDevice.setPin(getDevicePIN().getBytes()); Log.d(LOG_TAG," Auto-entering pin - " + getDevicePIN()); bluetoothDevice.createBond(); Log.d(LOG_TAG," pin entered and request sent..."); abortBroadcast(); } } } public void setDevicePIN(String pin){ this.devicePIN = pin; } public String getDevicePIN(){ return this.devicePIN ; } } public class BluetoothLowEnergy extends BluetoothGattCallback { // listener that has the methods that the application (activity) // will use to send / receive data, or to reflect the system state // in the UI public interface BluetoothListener { /** * Triggered when the scanning has started successfully */ void onBluetoothStartScan(); /** * Triggered when the scanning stops * @param scanResults results of the scanning */ void onBluetoothStopScan(Collection<BluetoothDevice> scanResults); /** * Triggered when the device is ready to send/receive data */ void onBluetoothConnectionReady(); /** * Triggered when a bluetooth msg is received * @param msg message received */ void onBluetoothReceiveMsg(String msg); /** * Triggered whenever data is send * @param success true means data was sent fine to the remote device, false otherwise */ void onBluetoothSend(String data, boolean success); /** * Triggered if no bluetooth is connected, and we need a connection * to send / receive / discover services */ void onBluetoothNotConnected(); } // custom exceptions public class BluetoothNotEnabledException extends Exception { } public class BluetoothLowEnergyNotSupported extends Exception { } public class BluetoothDeviceNotFound extends Exception { } // service and characteristic uuids that are going to be used to // send / receive data between central and peripheral GATTs private static final String SERVICE_UUID = "FFE0-"; private static final String CHARACTERISTIC_UUID = "FFE1-"; // timeout for bluetooth scan (in ms) public static final int SCAN_TIMEOUT = 5000; // BLE LOG TAG public static final String LOG_TAG = "BLUETOOTH_BLE"; // model private boolean bluetoothScanning; private boolean bluetoothConnected; private Map<String, BluetoothDevice> bluetoothScanResults; // gui private Activity activity; // bluetooth private BluetoothAdapter bluetoothAdapter; private BluetoothLeScanner bluetoothLeScanner; private ScanCallback bluetoothScanCallback; private BluetoothGatt bluetoothGatt; private BluetoothGattCharacteristic characteristic; public BluetoothLowEnergy(Activity activity, BluetoothListener bluetoothListener){ this.activity = activity; this.bluetoothListener = bluetoothListener; // this keeps track of the scanning and connection states this.bluetoothScanning = this.bluetoothConnected = false; // keeps track of the scanning results this.bluetoothScanResults = new HashMap<>(); // set bluetooth pairing request and bonded callback // these broadcasters will be responsible to detect and validate // the bonded state of your device this.pairingRequestBroadcaster = new BluetoothPairingBroadcaster(this); this.bondedBroadcaster = new BluetoothBondStateBroadcaster(this); // set the scan callback methods that will add results to // this.bluetoothScanResults map this.bluetoothScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); addScanResult(result); } @Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); for (ScanResult result: results) { addScanResult(result); } } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); Log.e(LOG_TAG, "Scan Failed with code " + errorCode); } private void addScanResult(ScanResult result) { BluetoothDevice device = result.getDevice(); String deviceAddress = device.getAddress(); bluetoothScanResults.put(deviceAddress, device); Log.d(LOG_TAG, "Found device " + deviceAddress); } }; // Use this to determine whether BLE is supported on the device. if (!this.activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { throw new BluetoothLowEnergyNotSupported(); } } /** * This method should be called when the activity is destroyed */ public void onDestroy(){ this.bondedBroadcaster.onDestroy(); this.pairingRequestBroadcaster.onDestroy(); this.disconnect(); } /** * This method is called when we finish pairing/bonding to the device */ public void onBluetoothBonded(){ // if we have the services already discovered, then we can // send/receive data, to do so we call the bluetooth listener below if (servicesDiscovered){ this.bluetoothListener.onBluetoothConnectionReady(); // if we know we have a connection established, then we can // discover services } else if (bluetoothConnected){ bluetoothGatt.discoverServices(); } } /** * This method is called whenever a connection is established or a disconnection happens */ @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); BluetoothDevice bluetoothDevice = gatt.getDevice(); // if these conditions == true, then we have a disconnect if ( status == BluetoothGatt.GATT_FAILURE || status != BluetoothGatt.GATT_SUCCESS || newState == BluetoothProfile.STATE_DISCONNECTED) { Log.d(LOG_TAG, String.format(Locale.getDefault(), "Disconnected from %s (%s) - status %d - state %d", bluetoothDevice.getName(), bluetoothDevice.getAddress(), status, newState )); this.disconnect(); // if these conditions == true, then we have a successful connection } else if (newState == BluetoothProfile.STATE_CONNECTED) { bluetoothConnected = true; Log.d(LOG_TAG, String.format(Locale.getDefault(), "Connected to %s (%s) - status %d - state %d", bluetoothDevice.getName(), bluetoothDevice.getAddress(), status, newState )); // this sleep is here to avoid TONS of problems in BLE, that occur whenever we start // service discovery immediately after the connection is established try { Thread.sleep(600); } catch (InterruptedException e) { e.printStackTrace(); } gatt.discoverServices(); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); if (status != BluetoothGatt.GATT_SUCCESS) { return; } // BEGIN - find the service and characteristic that we want (defined as a static attribute // of the BluetoothLowEnergy class) Log.d(LOG_TAG, "Discovering services ..."); BluetoothGattService service = null; for (BluetoothGattService serv: gatt.getServices()){ Log.d(LOG_TAG, "Found service " + serv.getUuid().toString()); if (serv.getUuid().toString().toUpperCase().contains(SERVICE_UUID)){ service = serv; Log.d(LOG_TAG, "---> Selected service " + serv.getUuid().toString()); break; } } if (service == null){ return; } for (BluetoothGattCharacteristic charac: service.getCharacteristics()){ Log.d(LOG_TAG, "Found characteristic " + charac.getUuid().toString()); if (charac.getUuid().toString().toUpperCase().contains(CHARACTERISTIC_UUID)){ this.characteristic = charac; Log.d(LOG_TAG, "---> Selected characteristic " + charac.getUuid().toString()); break; } } if (this.characteristic == null){ return; } Log.d(LOG_TAG, "Setting write and notification to the characteristic ..."); bluetoothAdapter.cancelDiscovery(); // END - find the service and characteristic // set that we want to write to the selected characteristic and be notified if // it changes (the remote GATT peripheral sends data to the Android's GATT Center) this.characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); gatt.setCharacteristicNotification(this.characteristic, true); // we finished service discovery this.servicesDiscovered = true; // if we have paired/bonded then we are ready to send/receive data if (pairingRequestBroadcaster.getDevicePIN().isEmpty() || bondedBroadcaster.isDeviceBonded()) { this.bluetoothListener.onBluetoothConnectionReady(); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic charac, int status) { super.onCharacteristicRead(gatt, charac, status); restartDisconnectTimeout(); if (status != BluetoothGatt.GATT_SUCCESS) { return; } try { String characValue = new String(charac.getValue(), CHARSET) .replaceAll(DATA_FILTER_REGEX,""); Log.i(LOG_TAG, String.format(Locale.getDefault(), "Characteristic Read - %s", characValue )); if (charac.getUuid().equals(this.characteristic.getUuid())) { this.bluetoothListener.onBluetoothReceiveMsg(characValue); } } catch (UnsupportedEncodingException e) { Log.e(LOG_TAG, "Characteristic Read - Failed to convert message string to byte array"); } } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic charac, int status) { super.onCharacteristicWrite(gatt, charac, status); restartDisconnectTimeout(); try { String characValue = new String(charac.getValue(), CHARSET); Log.i(LOG_TAG, String.format(Locale.getDefault(), "Characteristic Write - SUCCESS - %s", characValue )); bluetoothListener.onBluetoothSend( characValue, (status == BluetoothGatt.GATT_SUCCESS) ); } catch (UnsupportedEncodingException e) { Log.e(LOG_TAG, "Characteristic Write - Failed to convert message string to byte array"); } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic charac) { super.onCharacteristicChanged(gatt, charac); Log.d(LOG_TAG,"Characteristic Changed"); onCharacteristicRead(gatt, charac, BluetoothGatt.GATT_SUCCESS); } /** * Remove pairing/bonding of the device * @param device Device to remove bonding */ public static void removeBond(BluetoothDevice device){ try { if (device == null){ throw new Exception(); } Method method = device.getClass().getMethod("removeBond", (Class[]) null); method.invoke(device, (Object[]) null); Log.d(LOG_TAG, "removeBond() called"); Thread.sleep(600); Log.d(LOG_TAG, "removeBond() - finished method"); } catch (Exception e) { e.printStackTrace(); } } /** * Clears the GATT services cache, so that new services can be discovered * @param bluetoothGatt GATT Client to clear service's discovery cache */ public static void refresh(BluetoothGatt bluetoothGatt){ try { Method method = bluetoothGatt.getClass().getMethod("refresh", (Class[]) null); method.invoke(bluetoothGatt, (Object[]) null); } catch (Exception e){ e.printStackTrace(); } } /** * Connect to the GATT Peripheral device * @param uuid GATT Peripheral address / mac / uuid to connect to * @param pin PIN to authenticate and pair to the device */ public void connect(String uuid, String pin) throws BluetoothNotEnabledException, BluetoothDeviceNotFound { checkBluetooth(); // do not connect twice if (this.isConnected()){ return; } // get device BluetoothDevice device = this.bluetoothScanResults.get(uuid); if (device == null){ throw new BluetoothDeviceNotFound(); } this.deviceUUID = uuid; pairingRequestBroadcaster.setDevicePIN(pin); removeBond(device); // create connection to the bluetooth device bluetoothGatt = device.connectGatt(activity, false, this); refresh(bluetoothGatt); } /** * Disconnect from BLE device. This method should be called whenever we want to * close the APP, or the BLE connection. */ public void disconnect() { Log.d(LOG_TAG, "disconnect() - executed"); if (bluetoothGatt != null) { if (characteristic != null) { bluetoothGatt.setCharacteristicNotification(characteristic, false); } //remove device authorization/ bond/ pairing removeBond(bluetoothGatt); // disconnect now bluetoothGatt.disconnect(); bluetoothGatt.close(); Log.d(LOG_TAG, "disconnect() - bluetoothGatt disconnect happened"); } bluetoothGatt = null; characteristic = null; bluetoothConnected = false; servicesDiscovered = false; // set device as not bonded anymore bondedBroadcaster.resetDeviceBonded(); } /** * bluetooth nearby devices scan is on * @return true if scanning is on, false otherwise */ public boolean isScanning(){ return (this.bluetoothScanning); } /** * Check bluetooth system state (on or off) * @return true if system is on, false otherwise */ public boolean isEnabled(){ try { checkBluetooth(); return bluetoothAdapter.isEnabled(); } catch (BluetoothNotEnabledException e) { return false; } } /** * Check bluetooth connection * @return true if connected, false otherwise */ public boolean isConnected(){ return (this.bluetoothConnected); } /** * Start bluetooth scan for nearby devices * @param filters Scan filters that define what devices to scan for */ public void startScan(List<ScanFilter> filters) throws BluetoothNotEnabledException{ checkBluetooth(); // dont run two scans simultaneously if (isScanning()) { return; } // disconnect previously connected devices if (isConnected()) { this.disconnect(); return; } // setup bluetooth scanning settings ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER) .build(); // start scanning this.bluetoothScanning = true; this.bluetoothScanResults.clear(); this.bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); // Stops scanning after a pre-defined scan period. Handler bluetoothHandler = new Handler(); bluetoothHandler.postDelayed(new Runnable() { @Override public void run() { stopScan(); } }, SCAN_TIMEOUT); // start scan with default scan callback this.bluetoothLeScanner.startScan(filters, settings, bluetoothScanCallback); // we have started successfully the BLE scanning bluetoothListener.onBluetoothStartScan(); } /** * Stop bluetooth scan for nearby devices */ public void stopScan(){ if (!bluetoothScanning) { return; } // set app scan state to false bluetoothScanning = false; if (bluetoothLeScanner != null) { bluetoothLeScanner.stopScan(bluetoothScanCallback); bluetoothLeScanner = null; } // we have stopped BLE scanning, call the user's callback bluetoothListener.onBluetoothStopScan(bluetoothScanResults.values()); } /** * Send a message via bluetooth * @param msg message to send */ public void send(String msg) { if (!bluetoothConnected || characteristic == null){ bluetoothListener.onBluetoothNotConnected(); return; } try { msg = msg.replaceAll(DATA_FILTER_REGEX, "") + TERMINATION_CHAR; Log.d(LOG_TAG, String.format(Locale.getDefault(), "Sending message: %s", msg)); characteristic.setValue(msg.getBytes(CHARSET)); bluetoothGatt.writeCharacteristic(characteristic); } catch (UnsupportedEncodingException e) { Log.e(LOG_TAG, "BluetoothLowEnergy.send: Failed to convert message string to byte array"); } } public String getDeviceUUID(){ return deviceUUID; } public Activity getActivity(){ return activity; } /** * Check if bluetooth is enabled and working properly */ private void checkBluetooth() throws BluetoothNotEnabledException{ if (bluetoothAdapter == null) { final BluetoothManager bluetoothManager = (BluetoothManager) activity.getSystemService(Context.BLUETOOTH_SERVICE); if (bluetoothManager == null){ throw new BluetoothNotEnabledException(); } 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()) { throw new BluetoothNotEnabledException(); } } }
  • Thread.sleep(600)
  • removeBond(device)
  • refresh(gatt)
  • gatt.disconnect()

答案 2 :(得分:0)

就我而言,我从蓝牙堆栈中收到了此响应,因为该设备已经与手机绑定了。我从设置中将其删除,错误22消失了。