简体   繁体   中英

Unable to reconnect to a BLE device after BluetoothGatt.disconnect() in android

I'm developing an app that can connect and disconnect to a BLE device. I'm able to connect to a device and disconnect from that device. But when i try to reconnect to the same device it doesn´t work anymore.

I am using two classes, the MainActivity and the second one that extends from service.

My second activity:

public class RFduinoService extends Service {
private final static String TAG = RFduinoService.class.getSimpleName();

private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private BluetoothGattService mBluetoothGattService;

public final static String ACTION_CONNECTED =
        "com.rfduino.ACTION_CONNECTED";
public final static String ACTION_DISCONNECTED =
        "com.rfduino.ACTION_DISCONNECTED";
public final static String ACTION_DATA_AVAILABLE =
        "com.rfduino.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
        "com.rfduino.EXTRA_DATA";

public final static UUID UUID_SERVICE = BluetoothHelper.sixteenBitUuid(0x2220);
public final static UUID UUID_RECEIVE = BluetoothHelper.sixteenBitUuid(0x2221);
public final static UUID UUID_SEND = BluetoothHelper.sixteenBitUuid(0x2222);
public final static UUID UUID_DISCONNECT = BluetoothHelper.sixteenBitUuid(0x2223);
public final static UUID UUID_CLIENT_CONFIGURATION = BluetoothHelper.sixteenBitUuid(0x2902);

// Implements callback methods for GATT events that the app cares about.  For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            Log.i(TAG, "Connected to RFduino.");
            Log.i(TAG, "Attempting to start service discovery:" +
                    mBluetoothGatt.discoverServices());
        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            Log.i(TAG, "Disconnected from RFduino.");
            broadcastUpdate(ACTION_DISCONNECTED);
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            mBluetoothGattService = gatt.getService(UUID_SERVICE);
            if (mBluetoothGattService == null) {
                Log.e(TAG, "RFduino GATT service not found!");
                return;
            }

            BluetoothGattCharacteristic receiveCharacteristic =
                    mBluetoothGattService.getCharacteristic(UUID_RECEIVE);
            if (receiveCharacteristic != null) {
                BluetoothGattDescriptor receiveConfigDescriptor =
                        receiveCharacteristic.getDescriptor(UUID_CLIENT_CONFIGURATION);
                if (receiveConfigDescriptor != null) {
                    gatt.setCharacteristicNotification(receiveCharacteristic, true);

                    receiveConfigDescriptor.setValue(
                            BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                    gatt.writeDescriptor(receiveConfigDescriptor);
                } else {
                    Log.e(TAG, "RFduino receive config descriptor not found!");
                }

            } else {
                Log.e(TAG, "RFduino receive characteristic not found!");
            }

            broadcastUpdate(ACTION_CONNECTED);
        } else {
            Log.w(TAG, "onServicesDiscovered received: " + status);
        }
    }

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt,
                                     BluetoothGattCharacteristic characteristic,
                                     int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        }
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt,
                                        BluetoothGattCharacteristic characteristic) {
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
    }
};

private void broadcastUpdate(final String action) {
    final Intent intent = new Intent(action);
    sendBroadcast(intent, Manifest.permission.BLUETOOTH);
}

private void broadcastUpdate(final String action,
                             final BluetoothGattCharacteristic characteristic) {
    if (UUID_RECEIVE.equals(characteristic.getUuid())) {
        final Intent intent = new Intent(action);
        intent.putExtra(EXTRA_DATA, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0));
        sendBroadcast(intent, Manifest.permission.BLUETOOTH);
    }
}

public class LocalBinder extends Binder {
    RFduinoService getService() {
        return RFduinoService.this;
    }
}

@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

@Override
public boolean onUnbind(Intent intent) {
    // After using a given device, you should make sure that BluetoothGatt.close() is called
    // such that resources are cleaned up properly.  In this particular example, close() is
    // invoked when the UI is disconnected from the Service.
    close();
    return super.onUnbind(intent);
}

private final IBinder mBinder = new LocalBinder();

/**
 * Initializes a reference to the local Bluetooth adapter.
 *
 * @return Return true if the initialization is successful.
 */
public boolean initialize() {
    // For API level 18 and above, get a reference to BluetoothAdapter through
    // BluetoothManager.
    if (mBluetoothManager == null) {
        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        if (mBluetoothManager == null) {
            Log.e(TAG, "Unable to initialize BluetoothManager.");
            return false;
        }
    }

    mBluetoothAdapter = mBluetoothManager.getAdapter();
    if (mBluetoothAdapter == null) {
        Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
        return false;
    }

    return true;
}

/**
 * Connects to the GATT server hosted on the Bluetooth LE device.
 *
 * @param address The device address of the destination device.
 *
 * @return Return true if the connection is initiated successfully. The connection result
 *         is reported asynchronously through the
 *         {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
 *         callback.
 */
public boolean connect(final String address) {
    if (mBluetoothAdapter == null || address == null) {
        Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
        return false;
    }

    // Previously connected device.  Try to reconnect.
    if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
            && mBluetoothGatt != null) {
        Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
        return mBluetoothGatt.connect();
    }

    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
    // We want to directly connect to the device, so we are setting the autoConnect
    // parameter to false.
    mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
    Log.d(TAG, "Trying to create a new connection.");
    mBluetoothDeviceAddress = address;
    return true;
}

/**
 * Disconnects an existing connection or cancel a pending connection. The disconnection result
 * is reported asynchronously through the
 * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
 * callback.
 */
public void disconnect() {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.disconnect();
}

/**
 * After using a given BLE device, the app must call this method to ensure resources are
 * released properly.
 */
public void close() {
    if (mBluetoothGatt == null) {
        return;
    }
    mBluetoothGatt.close();
    mBluetoothGatt = null;
}

public void read() {
    if (mBluetoothGatt == null || mBluetoothGattService == null) {
        Log.w(TAG, "BluetoothGatt not initialized");
        return;
    }

    BluetoothGattCharacteristic characteristic =
            mBluetoothGattService.getCharacteristic(UUID_RECEIVE);

    mBluetoothGatt.readCharacteristic(characteristic);
}

public boolean send(byte[] data) {
    if (mBluetoothGatt == null || mBluetoothGattService == null) {
        Log.w(TAG, "BluetoothGatt not initialized");
        return false;
    }

    BluetoothGattCharacteristic characteristic =
            mBluetoothGattService.getCharacteristic(UUID_SEND);

    if (characteristic == null) {
        Log.w(TAG, "Send characteristic not found");
        return false;
    }

    characteristic.setValue(data);
    characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
    return mBluetoothGatt.writeCharacteristic(characteristic);
}

public static IntentFilter getIntentFilter() {
    IntentFilter filter = new IntentFilter();
    filter.addAction(ACTION_CONNECTED);
    filter.addAction(ACTION_DISCONNECTED);
    filter.addAction(ACTION_DATA_AVAILABLE);
    return filter;
}

}

And my MainActivity:

public class MainActivity extends Activity implements   BluetoothAdapter.LeScanCallback {

@Override
protected void onStart() {
    Log.d("ONSTART", "ONSTART");
    super.onStart();
    registerReceiver(scanModeReceiver, new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED));
    registerReceiver(bluetoothStateReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
    registerReceiver(rfduinoReceiver, RFduinoService.getIntentFilter());

}

@Override
public void onLeScan(BluetoothDevice device, final int rssi, final byte[] scanRecord) {
    scanLeDevice(false);
    bluetoothDevice = device;

    MainActivity.this.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Log.d("ONLESCAN", "ONLESCAN");
             /*obtain the name of the device based on the scanRecord*/
            BleAdvertisedData badata = BleUtil.parseAdertisedData(scanRecord);

            ListView list = discoveredDevicesDialog.getListView();
            list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                                        int position, long id) {
                    indexListClicked = position;
                    Intent rfduinoIntent = new Intent(MainActivity.this, RFduinoService.class);
                    bindService(rfduinoIntent, rfduinoServiceConnection, BIND_AUTO_CREATE);

                }
            });
            createNotification();
        }
    });
}

@Override
public void onBackPressed() {
    Log.d("CDA", "onBackPressed Called");
    if(!DisplayDiapers.getShowButton()) {
        unregisterReceiver(scanModeReceiver);
        unregisterReceiver(bluetoothStateReceiver);
        unregisterReceiver(rfduinoReceiver);
        finish();
    }else {
        moveTaskToBack(true);
    }
}


private void scanLeDevice(boolean scan){
    if(bluetoothAdapter.isEnabled()) {
        if (scan) {
            loadLoadingScanDialog(true);
            bluetoothAdapter.startLeScan(
                    new UUID[]{RFduinoService.UUID_SERVICE},
                    MainActivity.this);
        } else {
            bluetoothAdapter.stopLeScan(this);
        }
    }
}

public static void disconnect(int position){
    rfduinoService.disconnect();
}

private final BroadcastReceiver bluetoothStateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("bluetoothStateReceiver", "bluetoothStateReceiver");
        int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
        if (state == BluetoothAdapter.STATE_ON) {
            Log.d("STATE_DISCONNECTED", "STATE_DISCONNECTED");
        } else if (state == BluetoothAdapter.STATE_OFF) {
            Log.d("STATE_BLUETOOTH_OFF", "STATE_BLUETOOTH_OFF");
        }
    }
};

private final BroadcastReceiver scanModeReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("scanModeReceiver", "scanModeReceiver");
    }
};

private final ServiceConnection rfduinoServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d("rfduinoServiceConnec", "rfduinoServiceConnection_onServiceConnected");
        rfduinoService = ((RFduinoService.LocalBinder) service).getService();
        if (rfduinoService.initialize()) {
            if (rfduinoService.connect(bluetoothDevice.getAddress())) {
                Log.d("STATE_CONNECTING", "STATE_CONNECTING");
            }
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.d("rfduinoServiceConnec", "rfduinoServiceConnection_onServiceDisconnected");
    }
};

private final BroadcastReceiver rfduinoReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("rfduinoReceiver", "rfduinoReceiver");
        final String action = intent.getAction();
        if (RFduinoService.ACTION_CONNECTED.equals(action)) {
            showToast("Connected to " + diapersNames.get(indexListClicked));
        }
    }
};

}

In both times i can scan the devices, and find my device, but the second time when i click in the device that I want to connect to, i am not able to perform that action.

The flow goes like this: in onLeScan() i click on the device that i want to connect to, than the code goes to onServiceConnected() and calls the methods of my second class. When i want to disconnect the disconnect(int) will be called but the code will not enter onServiceDisconnected() . The second time onLeScan() will not do nothing, i know that the code enter on onLeScan() but that is the last print that i have, i don´t understand why is this happen. Why the behavior is not the same as the first time?

Thanks for helping.

You never call public static void disconnect(int position) .

I think you should call it in the rfduinoReceiver. Something like this :

private final BroadcastReceiver rfduinoReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("rfduinoReceiver", "rfduinoReceiver");
        if (RFduinoService.ACTION_CONNECTED.equals(action)) {
                Log.d(TAG, "RFduinoServer connected");
            } else if (RFduinoService.ACTION_DISCONNECTED.equals(action)) {
                Log.d(TAG, "RFduinoServer disconnected");
                rfduinoService.disconnect();
            } else if (RFduinoService.ACTION_DATA_AVAILABLE.equals(action)) {
                Log.d(TAG, "RFduinoServer data available");
                // Process data from intent.getByteArrayExtra(RFduinoService.EXTRA_DATA)   
            }
        }
    }
};

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