@Override public final void onConnectionStateChange( final BluetoothGatt gatt, final int status, final int newState) { Logger.d( mLogSession, "[Callback] Connection state changed with status: " + status + " and new state: " + newState + " (" + stateToString(newState) + ")"); if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) { // Notify the parent activity/service Logger.i(mLogSession, "Connected to " + gatt.getDevice().getAddress()); mConnected = true; mCallbacks.onDeviceConnected(); /* * The onConnectionStateChange event is triggered just after the Android connects to a device. * In case of bonded devices, the encryption is reestablished AFTER this callback is called. * Moreover, when the device has Service Changed indication enabled, and the list of services has changed (e.g. using the DFU), * the indication is received few milliseconds later, depending on the connection interval. * When received, Android will start performing a service discovery operation itself, internally. * * If the mBluetoothGatt.discoverServices() method would be invoked here, if would returned cached services, * as the SC indication wouldn't be received yet. * Therefore we have to postpone the service discovery operation until we are (almost, as there is no such callback) sure, that it had to be handled. * Our tests has shown that 600 ms is enough. It is important to call it AFTER receiving the SC indication, but not necessarily * after Android finishes the internal service discovery. * * NOTE: This applies only for bonded devices with Service Changed characteristic, but to be sure we will postpone * service discovery for all devices. */ mHandler.postDelayed( new Runnable() { @Override public void run() { // Some proximity tags (e.g. nRF PROXIMITY) initialize bonding automatically when // connected. if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDING) { Logger.v(mLogSession, "Discovering Services..."); Logger.d(mLogSession, "gatt.discoverServices()"); gatt.discoverServices(); } } }, 600); } else { if (newState == BluetoothProfile.STATE_DISCONNECTED) { if (status != BluetoothGatt.GATT_SUCCESS) Logger.w( mLogSession, "Error: (0x" + Integer.toHexString(status) + "): " + GattError.parseConnectionError(status)); onDeviceDisconnected(); mConnected = false; if (mUserDisconnected) { Logger.i(mLogSession, "Disconnected"); mCallbacks.onDeviceDisconnected(); close(); } else { Logger.w(mLogSession, "Connection lost"); mCallbacks.onLinklossOccur(); // We are not closing the connection here as the device should try to reconnect // automatically. // This may be only called when the shouldAutoConnect() method returned true. } return; } // TODO Should the disconnect method be called or the connection is still valid? Does this // ever happen? Logger.e( mLogSession, "Error (0x" + Integer.toHexString(status) + "): " + GattError.parseConnectionError(status)); mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status); } }
private void onError(final String message, final int errorCode) { Logger.e( mLogSession, "Error (0x" + Integer.toHexString(errorCode) + "): " + GattError.parse(errorCode)); mCallbacks.onError(message, errorCode); }