public void removeNotify(
      UUID serviceUUID, UUID characteristicUUID, Callback success, Callback fail) {

    Log.d(LOG_TAG, "removeNotify");

    if (gatt == null) {
      fail.invoke("BluetoothGatt is null");
      return;
    }

    BluetoothGattService service = gatt.getService(serviceUUID);
    BluetoothGattCharacteristic characteristic =
        findNotifyCharacteristic(service, characteristicUUID);
    // String key = generateHashKey(serviceUUID, characteristic);

    if (characteristic != null) {

      if (gatt.setCharacteristicNotification(characteristic, false)) {
        success.invoke();
      } else {
        // TODO we can probably ignore and return success anyway since we removed the notification
        // callback
        fail.invoke("Failed to stop notification for " + characteristicUUID);
      }

    } else {
      fail.invoke("Characteristic " + characteristicUUID + " not found");
    }
  }
  @Override
  public void onCharacteristicWrite(
      BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    super.onCharacteristicWrite(gatt, characteristic, status);
    // Log.d(LOG_TAG, "onCharacteristicWrite " + characteristic);

    if (writeCallback != null) {

      if (writeQueue.size() > 0) {
        byte[] data = writeQueue.get(0);
        writeQueue.remove(0);
        // Log.d(LOG_TAG, "rimangono in coda: " + writeQueue.size());
        doWrite(characteristic, data);
      } else {

        if (status == BluetoothGatt.GATT_SUCCESS) {
          writeCallback.invoke();
          // Log.e(LOG_TAG, "writeCallback invocato");
        } else {
          // writeCallback.error(status);
          Log.e(LOG_TAG, "errore onCharacteristicWrite:" + status);
          writeFailCallback.invoke("Error writing status: " + status);
        }

        writeCallback = null;
        writeFailCallback = null;
      }
    } else Log.e(LOG_TAG, "Nessun callback su write");
  }
 @Override
 public void onServicesDiscovered(BluetoothGatt gatt, int status) {
   super.onServicesDiscovered(gatt, status);
   connectCallback.invoke();
   connectCallback = null;
   connectFailCallback = null;
 }
 public void connect(Callback connectCallback, Callback failCallback, Activity activity) {
   if (!connected) {
     BluetoothDevice device = getDevice();
     this.connectCallback = connectCallback;
     this.connectFailCallback = failCallback;
     gatt = device.connectGatt(activity, false, this);
   } else {
     connectCallback.invoke();
   }
 }
  public void read(
      UUID serviceUUID, UUID characteristicUUID, Callback successCallback, Callback failCallback) {

    if (gatt == null) {
      failCallback.invoke("BluetoothGatt is null");
      return;
    }

    BluetoothGattService service = gatt.getService(serviceUUID);
    BluetoothGattCharacteristic characteristic =
        findReadableCharacteristic(service, characteristicUUID);

    if (characteristic == null) {
      failCallback.invoke("Characteristic " + characteristicUUID + " not found.");
    } else {
      readCallback = successCallback;
      readFailCallback = failCallback;
      if (!gatt.readCharacteristic(characteristic)) {
        readCallback = null;
        failCallback.invoke("Read failed");
      }
    }
  }
  @Override
  public void onCharacteristicRead(
      BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    super.onCharacteristicRead(gatt, characteristic, status);
    Log.d(LOG_TAG, "onCharacteristicRead " + characteristic);

    if (readCallback != null) {

      if (status == BluetoothGatt.GATT_SUCCESS) {
        byte[] dataValue = characteristic.getValue();
        String value = BleManager.bytesToHex(dataValue);

        if (readCallback != null) {
          readCallback.invoke(value);
          readCallback = null;
        }
      } else {
        readFailCallback.invoke("Error reading " + characteristic.getUuid() + " status=" + status);
        readFailCallback = null;
      }

      readCallback = null;
    }
  }
  @Override
  public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

    Log.d(
        LOG_TAG,
        "onConnectionStateChange da "
            + status
            + " a "
            + newState
            + " peripheral:"
            + device.getAddress());

    this.gatt = gatt;

    if (newState == BluetoothGatt.STATE_CONNECTED) {

      connected = true;
      gatt.discoverServices();

    } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {

      if (connected) {
        connected = false;

        if (gatt != null) {
          gatt.close();
          gatt = null;
        }

        WritableMap map = Arguments.createMap();
        map.putString("peripheral", device.getAddress());
        sendEvent("BleManagerDisconnectPeripheral", map);
        Log.d(LOG_TAG, "BleManagerDisconnectPeripheral peripheral:" + device.getAddress());
      }
      if (connectFailCallback != null) {
        connectFailCallback.invoke();
        connectFailCallback = null;
        connectCallback = null;
      }
    }
  }
  public void write(
      UUID serviceUUID,
      UUID characteristicUUID,
      byte[] data,
      Callback successCallback,
      Callback failCallback,
      int writeType) {

    Log.d(LOG_TAG, "write interno peripheral");

    if (gatt == null) {
      failCallback.invoke("BluetoothGatt is null");

    } else {

      BluetoothGattService service = gatt.getService(serviceUUID);
      BluetoothGattCharacteristic characteristic =
          findWritableCharacteristic(service, characteristicUUID, writeType);
      characteristic.setWriteType(writeType);

      if (characteristic == null) {
        failCallback.invoke("Characteristic " + characteristicUUID + " not found.");
      } else {

        if (writeQueue.size() > 0) {
          failCallback.invoke("Scrittura con byte ancora in coda");
        }

        if (writeCallback != null) {
          failCallback.invoke("Altra scrittura in corso");
        }

        if (writeQueue.size() == 0 && writeCallback == null) {

          if (BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT == writeType) {
            writeCallback = successCallback;
            writeFailCallback = failCallback;
          } else successCallback.invoke();

          if (data.length > 20) {
            int dataLength = data.length;
            int count = 0;
            byte[] firstMessage = null;
            while (count < dataLength && (dataLength - count > 20)) {
              if (count == 0) {
                firstMessage = Arrays.copyOfRange(data, count, count + 20);
              } else {
                byte[] splitMessage = Arrays.copyOfRange(data, count, count + 20);
                writeQueue.add(splitMessage);
              }
              count += 20;
            }
            if (count < dataLength) {
              // Rimangono byte in coda
              byte[] splitMessage = Arrays.copyOfRange(data, count, data.length);
              Log.d(LOG_TAG, "Lunghezza ultimo messaggio: " + splitMessage.length);
              writeQueue.add(splitMessage);
            }

            Log.d(LOG_TAG, "Messaggi in coda: " + writeQueue.size());
            doWrite(characteristic, firstMessage);
          } else {
            characteristic.setValue(data);

            if (gatt.writeCharacteristic(characteristic)) {
              Log.d(LOG_TAG, "write completato");
            } else {
              writeCallback = null;
              failCallback.invoke("Write failed");
            }
          }
        }
      }
    }
  }
  // This seems way too complicated
  public void registerNotify(
      UUID serviceUUID, UUID characteristicUUID, Callback success, Callback fail) {

    Log.d(LOG_TAG, "registerNotify");

    if (gatt == null) {
      fail.invoke("BluetoothGatt is null");
      return;
    }

    BluetoothGattService service = gatt.getService(serviceUUID);
    BluetoothGattCharacteristic characteristic =
        findNotifyCharacteristic(service, characteristicUUID);
    // String key = generateHashKey(serviceUUID, characteristic);

    if (characteristic != null) {
      Log.d(LOG_TAG, "characteristic ok");

      if (gatt.setCharacteristicNotification(characteristic, true)) {

        BluetoothGattDescriptor descriptor =
            characteristic.getDescriptor(UUID.fromString(CHARACTERISTIC_NOTIFICATION_CONFIG));
        if (descriptor != null) {
          Log.d(LOG_TAG, "trovato descriptor");

          // prefer notify over indicate
          if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
            Log.d(LOG_TAG, "Characteristic " + characteristicUUID + " set NOTIFY");
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
          } else if ((characteristic.getProperties()
                  & BluetoothGattCharacteristic.PROPERTY_INDICATE)
              != 0) {
            Log.d(LOG_TAG, "Characteristic " + characteristicUUID + " set INDICATE");
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
          } else {
            Log.d(
                LOG_TAG,
                "Characteristic "
                    + characteristicUUID
                    + " does not have NOTIFY or INDICATE property set");
          }

          if (gatt.writeDescriptor(descriptor)) {
            // Tutto ok
            Log.d(LOG_TAG, "registerNotify completato");
            success.invoke();
          } else {
            fail.invoke(
                "Failed to set client characteristic notification for " + characteristicUUID);
          }

        } else {
          fail.invoke("Set notification failed for " + characteristicUUID);
        }

      } else {
        fail.invoke("Failed to register notification for " + characteristicUUID);
      }

    } else {
      fail.invoke("Characteristic " + characteristicUUID + " not found");
    }
  }