@SuppressWarnings("PMD.CompareObjectsWithEquals") public void execute(BluetoothGattCallback callback) { NeatleLogger.d("Execute " + callback); boolean wasIdle; synchronized (lock) { wasIdle = currentCallback == DO_NOTHING_CALLBACK; if (currentCallback == callback || queue.contains(callback)) { NeatleLogger.d("Restarting " + callback); } else { NeatleLogger.d("Queueing up " + callback); queue.add(callback); } } if (wasIdle && areServicesDiscovered()) { resume(); } else { connect(); } }
@SuppressWarnings("PMD.CompareObjectsWithEquals") public void executeFinished(BluetoothGattCallback callback) { synchronized (lock) { if (callback == currentCallback) { this.currentCallback = DO_NOTHING_CALLBACK; NeatleLogger.d("Finished " + callback); handler.post(new Runnable() { @Override public void run() { resume(); } }); } else { this.queue.remove(callback); NeatleLogger.d("Removed from queue " + callback); } } }
@Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { NeatleLogger.d("createCharacteristicRead"); BluetoothGattCallback target; synchronized (lock) { target = currentCallback; } target.onCharacteristicRead(gatt, characteristic, status); }
@Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { BluetoothGattCallback target; synchronized (lock) { target = currentCallback; } target.onCharacteristicChanged(gatt, characteristic); notifyCharacteristicChange(CommandResult.createCharacteristicChanged(characteristic)); }
/** * 连接状态改变回调 * 系统自带API * @param gatt * @param status * @param newState */ @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (BleLog.isPrint) { BleLog.i(TAG, "onConnectionStateChange status: " + status + " ,newState: " + newState + " ,thread: " + Thread.currentThread().getId()); } if (newState == BluetoothGatt.STATE_CONNECTED) { connectionState = STATE_CONNECTED; // 连接成功 onConnectSuccess(gatt, status); } else if (newState == BluetoothGatt.STATE_DISCONNECTED) { connectionState = STATE_DISCONNECTED; // 连接失败 onConnectFailure(new ConnectException(gatt, status)); } else if (newState == BluetoothGatt.STATE_CONNECTING) { connectionState = STATE_CONNECTING; } // 遍历回调回所有传进了的回调, 给子类处理 for (BluetoothGattCallback call : callbackList) { call.onConnectionStateChange(gatt, status, newState); } }
/** * 处理向特征码写入数据的回调 * @param bleCallback */ private void handleCharacteristicWriteCallback(final BleCharactCallback bleCallback) { if (bleCallback != null) { // 添加连接回调到LiteBluetooth的回调集合中 listenAndTimer(bleCallback, MSG_WRIATE_CHA, new BluetoothGattCallback() { @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { handler.removeMessages(MSG_WRIATE_CHA, this); if (status == BluetoothGatt.GATT_SUCCESS) { bleCallback.onSuccess(characteristic); } else { bleCallback.onFailure(new GattException(status)); } } }); } }
/** * 写描述符 * @param bleCallback */ private void handleDescriptorWriteCallback(final BleDescriptorCallback bleCallback) { if (bleCallback != null) { listenAndTimer(bleCallback, MSG_WRIATE_DES, new BluetoothGattCallback() { @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { handler.removeMessages(MSG_WRIATE_DES, this); if (status == BluetoothGatt.GATT_SUCCESS) { bleCallback.onSuccess(descriptor); } else { bleCallback.onFailure(new GattException(status)); } } }); } }
/** * 读特征码 * @param bleCallback */ private void handleCharacteristicReadCallback(final BleCharactCallback bleCallback) { if (bleCallback != null) { listenAndTimer(bleCallback, MSG_READ_CHA, new BluetoothGattCallback() { AtomicBoolean msgRemoved = new AtomicBoolean(false); @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { // 将原子设置为给定值并返回旧值 if (!msgRemoved.getAndSet(true)) { // 只能进来执行一次 handler.removeMessages(MSG_READ_CHA, this); } if (status == BluetoothGatt.GATT_SUCCESS) { bleCallback.onSuccess(characteristic); } else { bleCallback.onFailure(new GattException(status)); } } }); } }
/** * 读描述符 * @param bleCallback */ private void handleDescriptorReadCallback(final BleDescriptorCallback bleCallback) { if (bleCallback != null) { listenAndTimer(bleCallback, MSG_READ_DES, new BluetoothGattCallback() { AtomicBoolean msgRemoved = new AtomicBoolean(false); @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { if (!msgRemoved.getAndSet(true)) { handler.removeMessages(MSG_READ_DES, this); } if (status == BluetoothGatt.GATT_SUCCESS) { bleCallback.onSuccess(descriptor); } else { bleCallback.onFailure(new GattException(status)); } } }); } }
/** * 读取RSSI, 回调返回 * @param bleCallback */ private void handleRSSIReadCallback(final BleRssiCallback bleCallback) { if (bleCallback != null) { listenAndTimer(bleCallback, MSG_READ_RSSI, new BluetoothGattCallback() { @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { handler.removeMessages(MSG_READ_RSSI, this); if (status == BluetoothGatt.GATT_SUCCESS) { bleCallback.onSuccess(rssi); } else { bleCallback.onFailure(new GattException(status)); } } }); } }
/** * 读取特征码刷新数据 * @param bleCallback */ private void handleCharacteristicNotificationCallback(final BleCharactCallback bleCallback) { if (bleCallback != null) { listenAndTimer(bleCallback, MSG_NOTIY_CHA, new BluetoothGattCallback() { AtomicBoolean msgRemoved = new AtomicBoolean(false); @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { if (!msgRemoved.getAndSet(true)) { handler.removeMessages(MSG_NOTIY_CHA, this); } bleCallback.onSuccess(characteristic); } }); } }
/** * 读取描述符刷新数据 * @param bleCallback */ private void handleDescriptorNotificationCallback(final BleDescriptorCallback bleCallback) { if (bleCallback != null) { listenAndTimer(bleCallback, MSG_NOTIY_DES, new BluetoothGattCallback() { @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { handler.removeMessages(MSG_NOTIY_DES, this); if (status == BluetoothGatt.GATT_SUCCESS) { bleCallback.onSuccess(descriptor); } else { bleCallback.onFailure(new GattException(status)); } } }); } }
@Override public BluetoothGatt connect(P_NativeDeviceLayer device, Context context, boolean useAutoConnect, BluetoothGattCallback callback) { m_gattIsNull = false; m_explicitDisconnect = false; m_device.getManager().getPostManager().postToUpdateThreadDelayed(new Runnable() { @Override public void run() { if (!m_explicitDisconnect) { setToConnecting(); } } }, 100); m_device.getManager().getPostManager().postToUpdateThreadDelayed(new Runnable() { @Override public void run() { if (!m_explicitDisconnect) { setToConnected(); } } }, 250); return device.connect(context, useAutoConnect, callback); }
private void resume() { BluetoothGattCallback target; BluetoothGatt targetGatt; boolean doResume; synchronized (lock) { if (currentCallback == DO_NOTHING_CALLBACK) { BluetoothGattCallback newCallback = queue.poll(); if (newCallback == null) { if (changeListeners.isEmpty()) { disconnectOnIdle(); } return; } currentCallback = newCallback; } target = currentCallback; doResume = areServicesDiscovered(); targetGatt = this.gatt; } if (doResume) { NeatleLogger.i("Resuming with " + target); currentCallback.onServicesDiscovered(targetGatt, BluetoothGatt.GATT_SUCCESS); } else { NeatleLogger.i("Will resume after services are discovered with " + target); connect(); } }
private void connectionFailed(int status) { BluetoothGattCallback current; int oldState; int newState; LinkedList<BluetoothGattCallback> queueCopy; synchronized (lock) { oldState = state; state = BluetoothGatt.STATE_DISCONNECTED; newState = state; serviceDiscovered = false; current = currentCallback; queueCopy = new LinkedList<>(queue); } NeatleLogger.i("Connection attempt failed. Notifying all pending operations"); current.onConnectionStateChange(this.gatt, status, BluetoothGatt.STATE_DISCONNECTED); for (BluetoothGattCallback cb : queueCopy) { cb.onConnectionStateChange(gatt, status, BluetoothGatt.STATE_DISCONNECTED); } synchronized (lock) { this.gatt = null; } notifyConnectionStateChange(oldState, newState); }
@Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { NeatleLogger.d("onCharacteristicWrite " + status); BluetoothGattCallback target; synchronized (lock) { target = currentCallback; } target.onCharacteristicWrite(gatt, characteristic, status); }
@Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { NeatleLogger.d("onReliableWriteCompleted"); BluetoothGattCallback target; synchronized (lock) { target = currentCallback; } target.onReliableWriteCompleted(gatt, status); }
@Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { BluetoothGattCallback target; synchronized (lock) { target = currentCallback; } target.onDescriptorRead(gatt, descriptor, status); }
@Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { BluetoothGattCallback target; synchronized (lock) { target = currentCallback; } target.onDescriptorWrite(gatt, descriptor, status); }
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { BluetoothGattCallback target; synchronized (lock) { target = currentCallback; } target.onMtuChanged(gatt, mtu, status); }
@Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { BluetoothGattCallback target; synchronized (lock) { target = currentCallback; } target.onReadRemoteRssi(gatt, rssi, status); }
/** * 连接失败 * LiteBleGattCallback : 自定义回调方法 * @param exception */ @Override public void onConnectFailure(BleException exception) { bluetoothGatt = null; for (BluetoothGattCallback call : callbackList) { if (call instanceof LiteBleGattCallback) { // 如果传入的是LiteBleGattCallback, 回调给子类连接失败 ((LiteBleGattCallback) call).onConnectFailure(exception); } } }
/** * 连接成功 * LiteBleGattCallback : 自定义回调方法 * @param gatt * @param status */ @Override public void onConnectSuccess(BluetoothGatt gatt, int status) { bluetoothGatt = gatt; for (BluetoothGattCallback call : callbackList) { if (call instanceof LiteBleGattCallback) { ((LiteBleGattCallback) call).onConnectSuccess(gatt, status); } } }
/** * 设备连接后, 调用gatt.discoverServices(); 如果发现了service, 执行此方法 * @param gatt * @param status */ @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { connectionState = STATE_SERVICES_DISCOVERED; for (BluetoothGattCallback call : callbackList) { call.onServicesDiscovered(gatt, status); } }
/** * BLE终端数据被读的回调 * @param gatt * @param characteristic * @param status */ @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { for (BluetoothGattCallback call : callbackList) { call.onCharacteristicRead(gatt, characteristic, status); } }
/** * BLE终端数据被写时的回调 * @param gatt * @param characteristic * @param status */ @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { for (BluetoothGattCallback call : callbackList) { call.onCharacteristicWrite(gatt, characteristic, status); } }
/** * 相当于一个监听器, 当蓝牙设备有数据返回时执行 * @param gatt * @param characteristic */ @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { for (BluetoothGattCallback call : callbackList) { call.onCharacteristicChanged(gatt, characteristic); } }
/** * 获取RSSI值, 计算距离 * @param gatt * @param rssi * @param status */ @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { for (BluetoothGattCallback call : callbackList) { call.onReadRemoteRssi(gatt, rssi, status); } }
/** * listen bluetooth gatt callback, and send a delayed message. * 添加回调监听 * 启动超时定时器 */ private void listenAndTimer(final BleCallback bleCallback, int what, BluetoothGattCallback callback) { bleCallback.setBluetoothGattCallback(callback); liteBluetooth.addGattCallback(callback); Message msg = handler.obtainMessage(what, bleCallback); handler.sendMessageDelayed(msg, timeOutMillis); }
private BluetoothGatt connectGattCompat(BluetoothGattCallback bluetoothGattCallback, BluetoothDevice device, boolean autoConnect) { RxBleLog.v("Connecting without reflection"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return device.connectGatt(context, autoConnect, bluetoothGattCallback, TRANSPORT_LE); } else { return device.connectGatt(context, autoConnect, bluetoothGattCallback); } }
private boolean connectUsingReflection(BluetoothGatt bluetoothGatt, BluetoothGattCallback bluetoothGattCallback, boolean autoConnect) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException { RxBleLog.v("Connecting using reflection"); setAutoConnectValue(bluetoothGatt, autoConnect); Method connectMethod = bluetoothGatt.getClass().getDeclaredMethod("connect", Boolean.class, BluetoothGattCallback.class); connectMethod.setAccessible(true); return (Boolean) (connectMethod.invoke(bluetoothGatt, true, bluetoothGattCallback)); }
@Override public BluetoothGatt connect(Context context, boolean useAutoConnect, BluetoothGattCallback callback) { if (m_native_device != null) { if (Utils.isMarshmallow()) { return M_Util.connect(m_native_device, useAutoConnect, context, callback); } else { return m_native_device.connectGatt(context, useAutoConnect, callback); } } return null; }
@Test public void testConnect() { BleConnector connector = new BleConnector(mock(Context.class)); BluetoothDevice device = mock(BluetoothDevice.class); connector.connect(device, false); verify(device, times(1)).connectGatt(Mockito.eq(connector.mContext), Mockito.eq(false), any(BluetoothGattCallback.class)); }
@RequiresPermission(Manifest.permission.BLUETOOTH) public void connect(BluetoothDevice bluetoothDevice) { if (btAdapter != null && btAdapter.isEnabled()) { if (bluetoothGatt != null) { bluetoothGatt.disconnect(); } updateState(BluetoothStatus.CONNECTING); /* About this issue: https://code.google.com/p/android/issues/detail?id=92949 http://stackoverflow.com/q/27633680/2826279 */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // If android verion is greather or equal to Android M (23), then call the connectGatt with TRANSPORT_LE. bluetoothGatt = bluetoothDevice.connectGatt(mConfig.context, false, btleGattCallback, mConfig.transport); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // From Android LOLLIPOP (21) the transport types exists, but them are hide for use, // so is needed to use relfection to get the value try { Method connectGattMethod = bluetoothDevice.getClass().getDeclaredMethod("connectGatt", Context.class, boolean.class, BluetoothGattCallback.class, int.class); connectGattMethod.setAccessible(true); bluetoothGatt = (BluetoothGatt) connectGattMethod.invoke(bluetoothDevice, mConfig.context, false, btleGattCallback, mConfig.transport); } catch (Exception ex) { Log.d(TAG, "Error on call BluetoothDevice.connectGatt with reflection.", ex); } } // If any try is fail, then call the connectGatt without transport if (bluetoothGatt == null) { bluetoothGatt = bluetoothDevice.connectGatt(mConfig.context, false, btleGattCallback); } } }
/** * Connect to GATT Server hosted by this device. */ @Nullable public static BluetoothGatt connectGatt(@NonNull BluetoothDevice device, @NonNull Context context, boolean autoConnect, @NonNull BluetoothGattCallback callback, int transport) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return device.connectGatt(context, autoConnect, callback, transport); } else { return device.connectGatt(context, autoConnect, callback); } }
@Implementation public BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) { final BluetoothGatt bluetoothGatt = ReflectionHelpers.newInstance(BluetoothGatt.class); final ShadowBluetoothGatt shadow = BuruberiShadows.shadowOf(bluetoothGatt); shadow.setAutoConnect(autoConnect); shadow.setGattCallback(callback); return bluetoothGatt; }
/** * open a connection with the device the returning connection is a shadow object that can be * queue with the mockito framework * @param c * @param b * @param callback * @return */ @Implementation public BluetoothGatt connectGatt(Context c,boolean b,BluetoothGattCallback callback){ mGattConnection = spy(Shadow.newInstanceOf(BluetoothGatt.class)); BluetoothGattShadow shadowGatt = ((BluetoothGattShadow)ShadowExtractor.extract(mGattConnection)); shadowGatt.setGattCallBack(callback); shadowGatt.setServices(mServices); mGattConnection.connect(); return mGattConnection; }
@Test public void connectEmptyNode(){ BluetoothDevice device = spy(Shadow.newInstanceOf(BluetoothDevice.class)); Node node = createNode(device); Assert.assertEquals(Node.State.Idle, node.getState()); node.connect(RuntimeEnvironment.application); TestUtil.execAllAsyncTask(); verify(device).connectGatt(eq(RuntimeEnvironment.application), eq(false), any(BluetoothGattCallback.class)); Assert.assertEquals(Node.State.Dead, node.getState()); }
@Test public void connectNodeWithDebug(){ BluetoothDevice device = spy(Shadow.newInstanceOf(BluetoothDevice.class)); BluetoothDeviceShadow shadowDevice = (BluetoothDeviceShadow)ShadowExtractor.extract(device); BluetoothGattService debugService = new BluetoothGattService(BLENodeDefines.Services .Debug.DEBUG_SERVICE_UUID,BluetoothGattService.SERVICE_TYPE_PRIMARY); debugService.addCharacteristic( new BluetoothGattCharacteristic(BLENodeDefines.Services.Debug.DEBUG_STDERR_UUID, BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE, BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic .PROPERTY_NOTIFY)); debugService.addCharacteristic( new BluetoothGattCharacteristic(BLENodeDefines.Services.Debug.DEBUG_TERM_UUID, BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE, BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic .PROPERTY_NOTIFY) ); shadowDevice.addService(debugService); Node node = createNode(device); Assert.assertEquals(Node.State.Idle, node.getState()); node.connect(RuntimeEnvironment.application); TestUtil.execAllAsyncTask(); verify(device).connectGatt(eq(RuntimeEnvironment.application), eq(false), any(BluetoothGattCallback.class)); Assert.assertEquals(Node.State.Connected, node.getState()); Assert.assertTrue(node.getDebug()!=null); }