@Override
    public void send(@Nonnull final Payment payment) {
      super.backgroundHandler.post(
          new Runnable() {
            @Override
            public void run() {
              log.info("trying to send tx to {}", url);

              HttpURLConnection connection = null;
              OutputStream os = null;
              InputStream is = null;

              try {
                connection = (HttpURLConnection) new URL(url).openConnection();

                connection.setInstanceFollowRedirects(false);
                connection.setConnectTimeout(Constants.HTTP_TIMEOUT_MS);
                connection.setReadTimeout(Constants.HTTP_TIMEOUT_MS);
                connection.setUseCaches(false);
                connection.setDoInput(true);
                connection.setDoOutput(true);

                connection.setRequestMethod("POST");
                connection.setRequestProperty("Content-Type", PaymentProtocol.MIMETYPE_PAYMENT);
                connection.setRequestProperty("Accept", PaymentProtocol.MIMETYPE_PAYMENTACK);
                connection.setRequestProperty(
                    "Content-Length", Integer.toString(payment.getSerializedSize()));
                if (userAgent != null) connection.addRequestProperty("User-Agent", userAgent);
                connection.connect();

                os = connection.getOutputStream();
                payment.writeTo(os);
                os.flush();

                log.info("tx sent via http");

                final int responseCode = connection.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK) {
                  is = connection.getInputStream();

                  final Protos.PaymentACK paymentAck = Protos.PaymentACK.parseFrom(is);

                  final boolean ack =
                      !"nack".equals(PaymentProtocol.parsePaymentAck(paymentAck).getMemo());

                  log.info("received {} via http", ack ? "ack" : "nack");

                  onResult(ack);
                } else {
                  final String responseMessage = connection.getResponseMessage();

                  log.info("got http error {}: {}", responseCode, responseMessage);

                  onFail(R.string.error_http, responseCode, responseMessage);
                }
              } catch (final IOException x) {
                log.info("problem sending", x);

                onFail(R.string.error_io, x.getMessage());
              } finally {
                if (os != null) {
                  try {
                    os.close();
                  } catch (final IOException x) {
                    // swallow
                  }
                }

                if (is != null) {
                  try {
                    is.close();
                  } catch (final IOException x) {
                    // swallow
                  }
                }

                if (connection != null) connection.disconnect();
              }
            }
          });
    }
    @Override
    public void send(@Nonnull final Payment payment) {
      super.backgroundHandler.post(
          new Runnable() {
            @Override
            public void run() {
              log.info("trying to send tx via bluetooth {}", bluetoothMac);

              if (payment.getTransactionsCount() != 1)
                throw new IllegalArgumentException("wrong transactions count");

              final BluetoothDevice device =
                  bluetoothAdapter.getRemoteDevice(Bluetooth.decompressMac(bluetoothMac));

              BluetoothSocket socket = null;
              DataOutputStream os = null;
              DataInputStream is = null;

              try {
                socket =
                    device.createInsecureRfcommSocketToServiceRecord(
                        Bluetooth.BIP70_PAYMENT_PROTOCOL_UUID);
                socket.connect();

                log.info("connected to payment protocol {}", bluetoothMac);

                is = new DataInputStream(socket.getInputStream());
                os = new DataOutputStream(socket.getOutputStream());

                payment.writeDelimitedTo(os);
                os.flush();

                log.info("tx sent via bluetooth");

                final Protos.PaymentACK paymentAck = Protos.PaymentACK.parseDelimitedFrom(is);

                final boolean ack =
                    "ack".equals(PaymentProtocol.parsePaymentAck(paymentAck).getMemo());

                log.info("received {} via bluetooth", ack ? "ack" : "nack");

                onResult(ack);
              } catch (final IOException x) {
                log.info("problem sending", x);

                onFail(R.string.error_io, x.getMessage());
              } finally {
                if (os != null) {
                  try {
                    os.close();
                  } catch (final IOException x) {
                    // swallow
                  }
                }

                if (is != null) {
                  try {
                    is.close();
                  } catch (final IOException x) {
                    // swallow
                  }
                }

                if (socket != null) {
                  try {
                    socket.close();
                  } catch (final IOException x) {
                    // swallow
                  }
                }
              }
            }
          });
    }