我想知道BLE gatt like callback设置完成时间

I want to know the finished time of setting of BLE gatt like callback

我英语不好。敬请谅解。

我想知道蓝牙设置何时完成。我想在蓝牙连接和设置完成后向我的设备发送数据。我如何知道流打开何时完成?

当我尝试了所有的BLE设置时,我只是睡了几秒钟,但我想将其更改为顺序代码。

private class GattClientCallback extends BluetoothGattCallback {
@Override
        public void onServicesDiscovered( BluetoothGatt _gatt, int _status ) {
            super.onServicesDiscovered( _gatt, _status );
            // check if the discovery failed
            if( _status != BluetoothGatt.GATT_SUCCESS ) {
                Log.e( TAG, "Device service discovery failed, status: " + _status );
                return;
            }
            // find discovered characteristics
            List<BluetoothGattCharacteristic> matching_characteristics= BluetoothUtils.findBLECharacteristics(_gatt);
            if( matching_characteristics.isEmpty() ) {
                Log.e( TAG, "Unable to find characteristics" );
                return;
            }
            // log for successful discovery
            Log.d( TAG, "Services discovery is successful" );

            // find command characteristics from the GATT server
            cmd_characteristic= BluetoothUtils.findCommandCharacteristic( ble_gatt_ );

            //setCharacteristicNotification
            ble_gatt_.setCharacteristicNotification(cmd_characteristic, true);
            BluetoothGattDescriptor descriptor = cmd_characteristic.getDescriptor(CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID);
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            ble_gatt_.writeDescriptor(descriptor); //descriptor write operation successfully started?
            // stream open complete.

            // update the connection status message
            msg_handler(SET_TV_STATUS,"connection complete");
        }

}
String result = pref.getString("first_device", "0");
        if(result.equals("0")) {
            ble_info.startScan();
        } else {
            ble_info.connectSavedDevice();
        }
        packet_sleep(5000); //I have to send data after ble connecting finished.

        if(!ble_info.connected_) {
            return;
        }

        while(ble_info.connected_ && state_check != ACK_COMM_START) {
            ble_info.sendData(SET_COMM_START);
            packet_sleep(ACK_TERM);
        }

ble_info class

public class BluetoothInfo {

    protected static final int SET_TV_STATUS = 0;
    protected static final int SET_TV_CONNECTION = 1; 
    protected static final UUID CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    protected static PacketReceive packetReceive = new PacketReceive();
    //-------------------------------

    //mac address
    public String devAddress;

    // ble adapter
    public BluetoothAdapter ble_adapter_;
    // flag for scanning
    public boolean is_scanning_= false;
    // flag for connection
    public boolean connected_= false;
    // scan results
    public Map<String, BluetoothDevice> scan_results_;
    // scan callback
    public ScanCallback scan_cb_;
    // ble scanner
    public BluetoothLeScanner ble_scanner_;
    // scan handler
    public Handler scan_handler_;
    // BLE Gatt
    public BluetoothGatt ble_gatt_;

    BluetoothGattCharacteristic cmd_characteristic;

    // to save data
    SharedPreferences pref;
    SharedPreferences.Editor editor;

    //constructor
    BluetoothInfo(BluetoothManager ble_manager, SharedPreferences pref) {
        ble_adapter_= ble_manager.getAdapter();
        ble_scanner_ = ble_adapter_.getBluetoothLeScanner();
        //to save data
        this.pref = pref;

    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    public void startScan() {

        // check if location permission
        if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            requestLocationPermission();
            Log.d(TAG, "Scanning Failed: no fine location permission");
            return;
        }
        // disconnect gatt server
        disconnectGattServer();

        scan_handler_= new Handler();
        scan_handler_.postDelayed( this::stopScan, SCAN_PERIOD ); 

        scan_results_= new HashMap<>();
        scan_cb_= new BLEScanCallback( scan_results_ );

        Log.d(TAG,"Scanning...");

        // check ble adapter and ble enabled
        if (ble_adapter_ == null || !ble_adapter_.isEnabled()) {
            requestEnableBLE();
            Log.d(TAG, "Scanning Failed: ble not enabled");
            return;
        }

        // now ready to scan
        ble_scanner_.startScan(scan_cb_); //scan filter 사용x
        // set scanning flag
        is_scanning_= true;
    }

    /*
    Stop scanning
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void stopScan() {
        // check pre-conditions
        if( is_scanning_ && ble_adapter_ != null && ble_adapter_.isEnabled() && ble_scanner_ != null ) {
            // stop scanning
            ble_scanner_.stopScan( scan_cb_ );
            scanComplete();
        }
        // reset flags
        scan_cb_= null;
        is_scanning_= false;
        scan_handler_= null;
        Log.d(TAG,"scanning stopped");
    }

    /*
    Handle scan results after scan stopped
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void scanComplete() {
        Toast.makeText(context, "scan finished", Toast.LENGTH_LONG).show();
        // check if nothing found
        if( scan_results_.isEmpty() ) {
            Log.d( TAG, "scan results is empty" );
            return;
        }

        ArrayList<BluetoothDevice> found_devices = new ArrayList<>();
        ArrayList<String> found_devices_names = new ArrayList<>();

        // loop over the scan results and connect to them
        for( String device_name : scan_results_.keySet() ) {
            Log.d( TAG, "Found device: " + device_name );
            if(device_name==null)
                continue;
            BluetoothDevice device= scan_results_.get( device_name );

            if( device_name.contains( BLE_NAME) ) {
                found_devices.add(device);
                found_devices_names.add(device_name);
            }
        }
        // exist device
        if(found_devices.size() >= 1) {
            CharSequence[] items = found_devices_names.toArray(new String[found_devices_names.size()]);

            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setTitle("select device");
            builder.setItems(items, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int pos) {
                    String selectedText = items[pos].toString();
                    connectDevice(found_devices.get(pos));
                    Toast.makeText(context, selectedText, Toast.LENGTH_SHORT).show();
                }
            });
            builder.show();
        } else {
            Toast.makeText(context, "not found", Toast.LENGTH_SHORT).show();
        }

    }

    /*
    Connect to the ble device
    */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void connectDevice(BluetoothDevice _device ) {
        // update the status
        msg_handler(SET_TV_CONNECTION, "connecting");
        devAddress = _device.getAddress();
        editor = pref.edit();
        editor.putString("first_device",devAddress);
        editor.apply();

        Log.d(TAG,"Connecting to " + devAddress);
        GattClientCallback gatt_client_cb= new GattClientCallback();
        ble_gatt_= _device.connectGatt( context, false, gatt_client_cb );// %CONNECT% 
    }

    /*
    Disconnect Gatt Server
    */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void disconnectGattServer() {
        Log.d( TAG, "Closing Gatt connection" );
        msg_handler(SET_TV_STATUS,"disconnect");
        // reset the connection flag
        connected_= false;
        // disconnect and close the gatt
        if( ble_gatt_ != null ) {
            ble_gatt_.disconnect();
            ble_gatt_.close();
        }
    }

    /*
    Request BLE enable
    */
    private void requestEnableBLE() {
        Intent ble_enable_intent= new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE );
        ((MainActivity)context).startActivityForResult( ble_enable_intent, REQUEST_ENABLE_BT );
    }

    /*
    Request Fine Location permission
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    private void requestLocationPermission() {
        ((MainActivity)context).requestPermissions( new String[]{ Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION );
    }

    /*
    connect to the saved device
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public boolean connectSavedDevice() {
        String result = pref.getString("first_device", "0");
        if(result.equals("0")) {
            Log.d(TAG,"no saved device");
            return false;
        }

        BluetoothDevice device = ble_adapter_.getRemoteDevice(result);
        GattClientCallback gatt_client_cb= new GattClientCallback();
        ble_gatt_= device.connectGatt( context, false, gatt_client_cb ); //  %connect%뜨는거
        return true;
    }

    /*
    Send Data
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void sendData(byte[] strByte) {
        // check connection
        if( !connected_ )
        {
            Log.e( TAG, "Failed to sendData due to no connection" );

            return;
        }

        // disconnect if the characteristic is not found
        if( cmd_characteristic == null ) {
            Log.e( TAG, "Unable to find cmd characteristic" );
            disconnectGattServer();
            return;
        }

        System.out.print("len : " + strByte.length + "->");
        for(int i=0;i<strByte.length;i++) {
            System.out.print((int)strByte[i] + " ");
        }
        System.out.println();

        // start stimulation
        startStimulation( cmd_characteristic, strByte );
    }

    /*
    Start stimulation
    @param cmd_characteristic command characteristic instance
    @param program_id stimulation program id
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void startStimulation(BluetoothGattCharacteristic _cmd_characteristic, byte[] strByte ) {
        _cmd_characteristic.setValue( strByte );
        boolean success= ble_gatt_.writeCharacteristic( _cmd_characteristic );

        if( success ) {
            Log.d( TAG, "send data complete" );
        }
        else
        {
            Log.e( TAG, "Failed to write command" );
        }
    }

    final Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case SET_TV_STATUS: 
                    ((MainActivity)context).tv_status_handler(msg.obj.toString());
                    break;
                case SET_TV_CONNECTION: 
                    ((MainActivity)context).tv_connection_handler(msg.obj.toString());
                    break;
            }
        }
    };

    public void msg_handler(int set_tv, String text) {
        Message msg = handler.obtainMessage();
        msg.what = set_tv;
        msg.obj = text;
        handler.sendMessage(msg);
        return;
    }

    /*
    BLE Scan Callback class
    */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private class BLEScanCallback extends ScanCallback {
        private Map<String, BluetoothDevice> cb_scan_results_;

        /*
        Constructor
         */
        BLEScanCallback( Map<String, BluetoothDevice> _scan_results ) {
            cb_scan_results_= _scan_results;
        }

        @Override
        public void onScanResult( int _callback_type, ScanResult _result ) {
            Log.d( TAG, "onScanResult" );
            addScanResult( _result );
        }

        @Override
        public void onBatchScanResults( List<ScanResult> _results ) {
            for( ScanResult result: _results ) {
                addScanResult( result );
            }
        }

        @Override
        public void onScanFailed( int _error ) {
            Log.e( TAG, "BLE scan failed with code " +_error );
        }

        /*
        Add scan result
         */
        private void addScanResult( ScanResult _result ) {
            // get scanned device
            BluetoothDevice device= _result.getDevice();
            // save devices for name
            String device_name = device.getName();
            // add the device to the result list
            cb_scan_results_.put( device_name, device );
            // log
            Log.d( TAG, "scan results device: " + device_name );
            msg_handler(SET_TV_STATUS,"scanned device : " + device_name);
        }
    }

    /*
    Gatt Client Callback class
    */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    private class GattClientCallback extends BluetoothGattCallback {
//        @Override
//        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
//            super.onDescriptorWrite(gatt, descriptor, status);
//        }

        @Override
        public void onConnectionStateChange(BluetoothGatt _gatt, int _status, int _new_state ) {
            super.onConnectionStateChange( _gatt, _status, _new_state );
            if( _status == BluetoothGatt.GATT_FAILURE ) {
                disconnectGattServer();
                return;
            } else if( _status != BluetoothGatt.GATT_SUCCESS ) {
                disconnectGattServer();
                return;
            }
            if( _new_state == BluetoothProfile.STATE_CONNECTED ) {
//                // 연결완료 되었을 시 1. set communication, 2. get standby state, 3. get basic data 동기화하기.
//                sendData(SET_COMM_START);
//                MainActivity.packet_sleep(200);
//                sendData(GET_STANDBY_STATE); //get airtop standby state(1.3)
//                MainActivity.packet_sleep(200);
//                if(airtopDevice.standby_state == ACTIVE_STATE) //device active 상태이면 basic data 확인
//                    sendData(GET_BASIC_DATA); //get airtop basic data(1.1)

//                // update the connection status message
//                msg_handler(SET_TV_STATUS,"연결 완료");
//                msg_handler(SET_TV_CONNECTION,"연결됨");
                // set the connection flag
                connected_= true;
                Log.d( TAG, "Connected to the GATT server" );
                _gatt.discoverServices();
            } else if ( _new_state == BluetoothProfile.STATE_DISCONNECTED ) {
                disconnectGattServer();
            }
        }

        @Override
        public void onServicesDiscovered( BluetoothGatt _gatt, int _status ) {
            super.onServicesDiscovered( _gatt, _status );
            // check if the discovery failed
            if( _status != BluetoothGatt.GATT_SUCCESS ) {
                Log.e( TAG, "Device service discovery failed, status: " + _status );
                return;
            }
            // find discovered characteristics
            List<BluetoothGattCharacteristic> matching_characteristics= BluetoothUtils.findBLECharacteristics(_gatt);
            if( matching_characteristics.isEmpty() ) {
                Log.e( TAG, "Unable to find characteristics" );
                return;
            }
            // log for successful discovery
            Log.d( TAG, "Services discovery is successful" );

            // find command characteristics from the GATT server
            cmd_characteristic= BluetoothUtils.findCommandCharacteristic( ble_gatt_ );

            //setCharacteristicNotification
            ble_gatt_.setCharacteristicNotification(cmd_characteristic, true);
            BluetoothGattDescriptor descriptor = cmd_characteristic.getDescriptor(CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID);
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            ble_gatt_.writeDescriptor(descriptor); //descriptor write operation successfully started?
            // stream open complete.

            // update the connection status message
            msg_handler(SET_TV_STATUS,"connect complete");

            // stream open 이후 send data -> main에서 sleep 이후 보내줌.
//            sendData(SET_COMM_START);
//            MainActivity.packet_sleep(200);
//            sendData(GET_STANDBY_STATE); //get airtop standby state(1.3)
//            MainActivity.packet_sleep(200);
//            if(airtopDevice.standby_state == ACTIVE_STATE) //device active 상태이면 basic data 확인
//                sendData(GET_BASIC_DATA); //get airtop basic data(1.1)
        }

        @Override
        public void onCharacteristicChanged( BluetoothGatt _gatt, BluetoothGattCharacteristic _characteristic ) {
            super.onCharacteristicChanged( _gatt, _characteristic );

            Log.d( TAG, "characteristic changed: " + _characteristic.getUuid().toString() );
            readCharacteristic( _characteristic );
        }

        @Override
        public void onCharacteristicWrite( BluetoothGatt _gatt, BluetoothGattCharacteristic _characteristic, int _status ) {
            super.onCharacteristicWrite( _gatt, _characteristic, _status );
            if( _status == BluetoothGatt.GATT_SUCCESS ) {
                Log.d( TAG, "Characteristic written successfully" );
            } else {
                Log.e( TAG, "Characteristic write unsuccessful, status: " + _status) ;
                disconnectGattServer();
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.d (TAG, "Characteristic read successfully" );
                readCharacteristic(characteristic);
            } else {
                Log.e( TAG, "Characteristic read unsuccessful, status: " + status);
                // Trying to read from the Time Characteristic? It doesnt have the property or permissions
                // set to allow this. Normally this would be an error and you would want to:
                // disconnectGattServer();
            }
        }

        /*
        Log the value of the characteristic
        @param characteristic
         */
        private void readCharacteristic( BluetoothGattCharacteristic _characteristic ) {
            byte[] msg = _characteristic.getValue();
            String str = new String(msg);

            for(int i=0;i<str.length();i++) {
                packetReceive.input_byte(str.charAt(i)); 
            }

            String prt = new String();
            for(int i=0;i<msg.length;i++) {
                prt += " "+(int)msg[i];
            }
            Log.d(TAG,"msg len"+msg.length + ": " +prt);
        }
    }
}

您可以执行 onConnectionStateChange.This 会让您知道您的连接是否成功。

@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,int newState) {
    if (newState == BluetoothProfile.STATE_CONNECTED) {
      // you can send data here
    } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {

    }
}