Related
I'm new in developing with ACR or NFC Reader, especially for Android. And recently I need to use an ACR35 and I've got the SDK and the example from this acs official website. And It works just fine as an example.
And now I need to create an activity that will always be ready to check whether nfc card is tapped. But the problem is I don't know how to detect when the nfc card is tapped and I don't know what to do next, and I can't find the way out from the example as it detects nfc card when I touch the 'transmit' button, it doesn't do it automatically.
Please give me with example code.
Thanks for your answer.
A bit late, but it might help someone.
I have found following project on the git hub. It shows how to read tag id from the acr35
here
.
I have been using acr35 for some time to read the tag id. From my experience is a buggy device on Android. I tested around 10 devices and it worked only on 3...
I read from it every second. It returns results from the last card even though it is not present there anymore. Therefore; I have to reset it twice per every successful read and it takes around 6 seconds to get the device in reading state again... Also be very careful with multithreading.
My implementation based on mentioned project - added simple locking to stop querying the card after successfull reading + full device reset, filternig same uuid which was read in very short time after it was read previously:
ACR3x class
import com.acs.audiojack.AudioJackReader;
import android.media.AudioManager;
import sk.tido.util.ByteHex;
import java.util.Date;
/**
* This class allows control of the ACR35 reader sleep state and PICC commands
*/
public class Acr3x {
private Acr3xTransmitter transmitter;
private AudioManager mAudioManager;
private AudioJackReader mReader;
private boolean firstReset = true; /** Is this the first reset of the reader? */
/** APDU command for reading a card's UID */
private final byte[] apdu = { (byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
/** Timeout for APDU response (in <b>seconds</b>) */
private final int timeout = 1;
private int acr3xCardType = AudioJackReader.PICC_CARD_TYPE_ISO14443_TYPE_A
| AudioJackReader.PICC_CARD_TYPE_ISO14443_TYPE_B
| AudioJackReader.PICC_CARD_TYPE_FELICA_212KBPS
| AudioJackReader.PICC_CARD_TYPE_FELICA_424KBPS
| AudioJackReader.PICC_CARD_TYPE_AUTO_RATS;
private int acr3xStartAudioLevel = 0;
private Object locking = new Object();
private String lastUuid = "";
private Date lastUuidDate = new Date();
public Acr3x(AudioManager mAudioManager){
this.mAudioManager = mAudioManager;
}
public void start(final Acr3xNotifListener listener){
Runnable r = new Runnable(){
#Override
public void run() {
if(mReader == null){
mReader = new AudioJackReader(mAudioManager);
}
System.out.println("ACR35 reader start");
acr3xStartAudioLevel = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
System.out.println("acr3x start audio stream level: " + acr3xStartAudioLevel);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
System.out.println("acr3x set audio stream level: " + mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
mReader.start();
mReader.setSleepTimeout(30);
mReader.setOnFirmwareVersionAvailableListener(new AudioJackReader.OnFirmwareVersionAvailableListener() {
#Override
public void onFirmwareVersionAvailable(AudioJackReader reader,
String firmwareVersion) {
System.out.println("acr3x firmware version: " + firmwareVersion);
if(listener != null){
listener.onFirmwareVersionAvailable(firmwareVersion);
}
Acr3x.this.read(listener);
}
});
mReader.reset(new AudioJackReader.OnResetCompleteListener(){
#Override
public void onResetComplete(AudioJackReader arg0) {
mReader.getFirmwareVersion();
}
});
}
};
Thread t = new Thread(r, "Acr3xInitThread");
t.start();
}
/**
* Sets the ACR35 reader to continuously poll for the presence of a card. If a card is found,
* the UID will be returned to the Apache Cordova application
*
* #param callbackContext: the callback context provided by Cordova
* #param cardType: the integer representing card type
*/
public void read(final Acr3xNotifListener callbackContext){
System.out.println("acr3x setting up for reading...");
firstReset = true;
/* Set the PICC response APDU callback */
mReader.setOnPiccResponseApduAvailableListener
(new AudioJackReader.OnPiccResponseApduAvailableListener() {
#Override
public void onPiccResponseApduAvailable(AudioJackReader reader,
byte[] responseApdu) {
/* Update the connection status of the transmitter */
transmitter.updateStatus(true);
/* Print out the UID */
String uuid = ByteHex.bytesToHex(responseApdu);
if(uuid.equalsIgnoreCase("0x9000")){
return;
}
if(uuid.endsWith("9000")){
uuid = uuid.substring(0, uuid.length() - 4);
}
if(uuid.equals(lastUuid)){ // na odfiltrovanie opakujucich sa uuid z citacky z predchadzajuceho citania
if(new Date().getTime() - lastUuidDate.getTime() < 3000){
return;
}
}
lastUuid = uuid;
lastUuidDate = new Date();
synchronized(locking){
System.out.println("acr3x uuid: " + uuid);
if(callbackContext != null){
callbackContext.onUUIDAavailable(uuid);
}
System.out.println("acr3x restarting reader");
transmitter.kill();
try {
locking.wait(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
read(callbackContext);
}
});
/* Set the reset complete callback */
mReader.setOnResetCompleteListener(new AudioJackReader.OnResetCompleteListener() {
#Override
public void onResetComplete(AudioJackReader reader) {
System.out.println("acr3x reset complete");
/* If this is the first reset, the ACR35 reader must be turned off and back on again
to work reliably... */
Thread t = null;
if(firstReset){ //firstReset
t = new Thread(new Runnable() {
public void run() {
try{
/* Set the reader asleep */
mReader.sleep();
/* Wait one second */
Thread.sleep(500);
/* Reset the reader */
mReader.reset();
firstReset = false;
} catch (InterruptedException e) {
e.printStackTrace();
// TODO: add exception handling
}
}
});
} else {
/* Create a new transmitter for the UID read command */
transmitter = new Acr3xTransmitter(mReader, mAudioManager, timeout,
apdu, acr3xCardType, locking);
t = new Thread(transmitter);
}
t.start();
}
});
mReader.start();
mReader.reset();
System.out.println("acr3x setup complete");
}
public void stop(){
if(transmitter != null){
transmitter.kill();
}
System.out.println("acr3x restoring audio level: " + acr3xStartAudioLevel);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,acr3xStartAudioLevel, 0);
System.out.println("acr3x set audio stream level: " + mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
if(mReader != null){
mReader.stop();
}
}
}
Transmitter class
import com.acs.audiojack.AudioJackReader;
import android.media.AudioManager;
/**
* This class sets up an independent thread for card polling, and is linked to the
* <code>setOnPiccResponseApduAvailableListener</code> callback function
*/
public class Acr3xTransmitter implements Runnable {
private AudioJackReader mReader;
private AudioManager mAudioManager;
//private CallbackContext mContext;
private boolean killMe = false; /** Stop the polling thread? */
private int itersWithoutResponse = 0; /** The number of iterations that have passed with no
response from the reader */
private boolean readerConnected = true; /** Is the reader currently connected? */
private int cardType;
private int timeout;
private byte[] apdu;
private Object locking;
/**
* #param mReader: AudioJack reader service
* #param mAudioManager: system audio service
* #param mContext: context for plugin results
* #param timeout: time in <b>seconds</b> to wait for commands to complete
* #param apdu: byte array containing the command to be sent
* #param cardType: the integer representing card type
*/
public Acr3xTransmitter(AudioJackReader mReader, AudioManager mAudioManager,
int timeout, byte[] apdu, int cardType, Object locking){
this.mReader = mReader;
this.mAudioManager = mAudioManager;
this.timeout = timeout;
this.apdu = apdu;
this.cardType = cardType;
this.locking = locking;
}
/**
* Stops the polling thread
*/
public void kill(){
killMe = true;
}
/**
* Updates the connection status of the reader (links to APDU response callback)
*/
public void updateStatus(boolean status){
readerConnected = status;
}
/**
* Sends the APDU command for reading a card UID every second
*/
#Override
public void run() {
try {
/* Wait one second for stability */
Thread.sleep(1000);
while (!killMe) {
synchronized(locking){
if(killMe){
continue;
}
/* If the reader is not connected, increment no. of iterations without response */
if(!readerConnected){
itersWithoutResponse++;
}
/* Else, reset the number of iterations without a response */
else{
itersWithoutResponse = 0;
}
/* Reset the connection state */
readerConnected = false;
if(itersWithoutResponse == 4) {
/* Communicate to the Cordova application that the reader is disconnected */
System.out.println("acr3x disconnected");
/* Kill this thread */
kill();
} else if(!mAudioManager.isWiredHeadsetOn()) {
System.out.println("acr3x not connected");
/* Kill this thread */
kill();
} else{
System.out.println("acr3x reading...");
/* Power on the PICC */
mReader.piccPowerOn(timeout, cardType);
/* Transmit the APDU */
mReader.piccTransmit(timeout, apdu);
}
}
/* Repeat every second */
Thread.sleep(1000);
}
/* Power off the PICC */
mReader.piccPowerOff();
/* Set the reader asleep */
mReader.sleep();
/* Stop the reader service */
mReader.stop();
synchronized(locking){
locking.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
// TODO: add exception handling
}
}
}
listener interface:
public interface Acr3xNotifListener {
public void onUUIDAavailable(String uuid);
public void onFirmwareVersionAvailable(String firmwareVersion);
}
First you call the Reset command to activate the device. As the device will fall asleep (after 4 seconds by default)* the trick is to keeping it alive.
You can achieve that by relaunching a new PowerOn command every time the previous PowerOn timedOut. Something like that
void powerOn () {
if (!mReader.piccPowerOn(mPiccTimeout, mPiccCardType)) {
powerOn();
} else {
askNfcForItsId();
}
Don't forget to call powerOn after you read the nfc otherwise it will fall asleep after the 1st nfc card.
*the reset timeout can be set between 4 and 20 seconds
Hey Guys i have problem ; i can send data from Phone to arduino but i cant send data from arduino to android via Bluetooth on procesing it doesnt work for me . i dont get any Error while compiling but I cant see anything on phone screen .. i used for blueToothSerial.print(XXX); for arduino side .. and used text(readMessage , width,heigth); for processing side in order to see as a text Please check it out . Where is my fault ? . What am I missing ? Thanks in Advance
ARDUINO CODE
#include <SoftwareSerial.h>
#include <Stepper.h>
#define RxD 6 // This is the pin that the Bluetooth (BT_TX) will transmit to the Arduino (RxD)
#define TxD 7 // This is the pin that the Bluetooth (BT_RX) will receive from the Arduino (TxD)
#define DEBUG_ENABLED 1
#define RELAY 4
SoftwareSerial blueToothSerial(RxD, TxD);
int led = 9 ;
int in1Pin = 10;
int in2Pin = 12;
int in3Pin = 11;
int in4Pin = 13;
data = 100;
Stepper motor(512, in1Pin, in2Pin, in3Pin, in4Pin);
/*----------------------SETUP----------------------------*/
void setup() {
Serial.begin(9600);//low Serial communication via USB cable to computer (if required)
pinMode(RxD, INPUT); // Setup the Arduino to receive INPUT from the bluetooth shield on Digital Pin 6
pinMode(TxD, OUTPUT); // Setup the Arduino to send data (OUTPUT) to the bluetooth shield on Digital Pin 7
pinMode(13, OUTPUT); // Use onboard LED if required.
pinMode(9,OUTPUT);
motor.setSpeed(30);
pinMode(RELAY,OUTPUT);
setupBlueToothConnection(); //Used to initialise the Bluetooth shield
}
/*----------------------LOOP----------------------------*/
void loop() {
digitalWrite(13, LOW); //Turn off the onboard Arduino LED
char recvChar;
while (1) {
if (blueToothSerial.available()) {//check if there's any data sent from the remote bluetooth shield
recvChar = blueToothSerial.read();
Serial.print(recvChar); // Print the character received to the Serial Monitor (if required)
//If the character received = 'r' , then change the RGB led to display a RED colour
if (recvChar=='r') {
motor.step(300);
digitalWrite(led,HIGH);
delay(500);
}
//If the character received = 'g' , then change the RGB led to display a GREEN colour
if (recvChar=='g') {
digitalWrite(led,LOW);
motor.step(-300);
}
//If the character received = 'b' , then change the RGB led to display a BLUE colour
if (recvChar=='b') {
digitalWrite(led,HIGH);
digitalWrite(RELAY,HIGH);
}
//If the character received = 'x' , then turn RGB led OFF
if (recvChar=='x') {
digitalWrite(led,LOW);
digitalWrite(RELAY,LOW);
}
}
//You can use the following code to deal with any information coming from the Computer (serial monitor)
if (Serial.available()) {
recvChar = Serial.read();
//This will send value obtained (recvChar) to the phone. The value will be displayed on the phone.
blueToothSerial.print(recvChar);
blueToothSerial.print("burak:");
blueToothSerial.print(data); // data which is defined begin of sketch
}
}
}
//The following code is necessary to setup the bluetooth shield ------copy and paste----------------
void setupBlueToothConnection()
{
blueToothSerial.begin(9600);// BluetoothBee BaudRate to default baud rate 38400
blueToothSerial.print("\r\n+STWMOD=0\r\n"); //set the bluetooth work in slave mode
blueToothSerial.print("\r\n+STNA=HC-05\r\n"); //set the bluetooth name as "SeeedBTSlave"
blueToothSerial.print("\r\n+STOAUT=1\r\n"); // Permit Paired device to connect me
blueToothSerial.print("\r\n+STAUTO=0\r\n"); // Auto-connection should be forbidden here
delay(2000); // This delay is required.
blueToothSerial.print("\r\n+INQ=1\r\n"); //make the slave bluetooth inquirable
Serial.println("The slave bluetooth is inquirable!");
delay(2000); // This delay is required.
blueToothSerial.flush();
}
PROCESSING CODE
/* BluetoothApp1: Written by ScottC on 25 March 2013 using
Processing version 2.0b8
Tested on a Samsung Galaxy SII, with Android version 2.3.4
Android ADK - API 10 SDK platform
Apwidgets version: r44 */
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.widget.Toast;
import android.view.Gravity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import java.util.UUID;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import apwidgets.*;
public BluetoothSocket scSocket;
//Used for the GUI**************************************
APWidgetContainer widgetContainer;
APButton redButton, greenButton, blueButton, offButton,yeniButton;
String buttonText="";
int buttonWidth=0;
int buttonHeight=0;
int n=4; //number of buttons
int gap=10; //gap between buttons
boolean foundDevice=false; //When true, the screen turns green.
boolean BTisConnected=false; //When true, the screen turns purple.
String serverName = "ArduinoBasicsServer";
// Message types used by the Handler
public static final int MESSAGE_WRITE = 1;
public static final int MESSAGE_READ = 2;
String readMessage="";
//Used to send bytes to the Arduino
SendReceiveBytes sendReceiveBT=null;
//Get the default Bluetooth adapter
BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
/*The startActivityForResult() within setup() launches an
Activity which is used to request the user to turn Bluetooth on.
The following onActivityResult() method is called when this
Activity exits. */
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode==0) {
if (resultCode == RESULT_OK) {
ToastMaster("Bluetooth simdi acildi");
}
else {
ToastMaster("Programi kullanabilmek icin Bluetoot acmalisiniz!!!");
}
}
}
/* Create a BroadcastReceiver that will later be used to
receive the names of Bluetooth devices in range. */
BroadcastReceiver myDiscoverer = new myOwnBroadcastReceiver();
/* Create a BroadcastReceiver that will later be used to
identify if the Bluetooth device is connected */
BroadcastReceiver checkIsConnected = new myOwnBroadcastReceiver();
// The Handler that gets information back from the Socket
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_WRITE:
//Do something when writing
break;
case MESSAGE_READ:
//Get the bytes from the msg.obj
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
readMessage = new String(readBuf, 0, msg.arg1);
break;
}
}
};
void setup() {
orientation(LANDSCAPE);
//Setup GUI********************************
buttonWidth=((width/n)-(n*gap));
buttonHeight=(height/2);
widgetContainer = new APWidgetContainer(this); //create new container for widgets
yeniButton = new APButton(700,600,(buttonWidth/2),(buttonHeight/2),"Yeni buton");
redButton =new APButton(0,0 ,400,400, "PERDE YUKARI"); //Create a RED button
// redButton =new APButton((buttonWidth*(n-4)+(gap*1)), gap, buttonWidth, buttonHeight, "RED"); //Create a RED button
greenButton = new APButton((buttonWidth*(n-3)+(gap*2)), gap, buttonWidth, buttonHeight, "GREEN"); //Create a GREEN button
blueButton = new APButton((buttonWidth*(n-2)+(gap*3)), gap, buttonWidth, buttonHeight, "BLUE"); //Create a BLUE button
offButton = new APButton((buttonWidth*(n-1)+(gap*4)), gap, buttonWidth, buttonHeight, "OFF"); //Create a OFF button
widgetContainer.addWidget(redButton); //place red button in container
widgetContainer.addWidget(greenButton); //place green button in container
widgetContainer.addWidget(blueButton);//place blue button in container
widgetContainer.addWidget(offButton);//place off button in container
widgetContainer.addWidget(yeniButton);
background(0); //Start with a black background
/*IF Bluetooth is NOT enabled, then ask user permission to enable it */
if (!bluetooth.isEnabled()) {
Intent requestBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(requestBluetooth, 0);
}
/*If Bluetooth is now enabled, then register a broadcastReceiver to report any
discovered Bluetooth devices, and then start discovering */
if (bluetooth.isEnabled()) {
registerReceiver(myDiscoverer, new IntentFilter(BluetoothDevice.ACTION_FOUND));
registerReceiver(checkIsConnected, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED));
//Start bluetooth discovery if it is not doing so already
if (!bluetooth.isDiscovering()) {
bluetooth.startDiscovery();
}
}
}
void draw() {
//Display a green screen if a device has been found,
//Display a purple screen when a connection is made to the device
if (foundDevice) {
if (BTisConnected) {
background(170, 50, 255); // purple screen
}
else {
background(10, 255, 10); // green screen
}
}
//Change the text based on the button being pressed.
text(buttonText, 10, buttonHeight+(buttonHeight/2));
//Display anything received from Arduino
text(readMessage, 10, buttonHeight+(buttonHeight/2)+30);
}
/* This BroadcastReceiver will display discovered Bluetooth devices */
public class myOwnBroadcastReceiver extends BroadcastReceiver {
ConnectToBluetooth connectBT;
#Override
public void onReceive(Context context, Intent intent) {
String action=intent.getAction();
ToastMaster("Eylem:" + action);
//Notification that BluetoothDevice is FOUND
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
//Display the name of the discovered device
String discoveredDeviceName = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
ToastMaster("Bulunan Cihaz: " + discoveredDeviceName);
//Display more information about the discovered device
BluetoothDevice discoveredDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
ToastMaster("getAddress() = " + discoveredDevice.getAddress());
ToastMaster("getName() = " + discoveredDevice.getName());
int bondyState=discoveredDevice.getBondState();
ToastMaster("getBondState() = " + bondyState);
String mybondState;
switch(bondyState) {
case 10:
mybondState="BOND_NONE";
break;
case 11:
mybondState="BOND_BONDING";
break;
case 12:
mybondState="BOND_BONDED";
break;
default:
mybondState="INVALID BOND STATE";
break;
}
ToastMaster("getBondState() = " + mybondState);
//Change foundDevice to true which will make the screen turn green
foundDevice=true;
//Connect to the discovered bluetooth device (SeeedBTSlave)
if (discoveredDeviceName.equals("HC-05")) {
ToastMaster("BAGLANIYOR!!");
unregisterReceiver(myDiscoverer);
connectBT = new ConnectToBluetooth(discoveredDevice);
//Connect to the the device in a new thread
new Thread(connectBT).start();
}
}
//Notification if bluetooth device is connected
if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
ToastMaster("CIHAZINIZ BAGLANDI");
int counter=0;
while (scSocket==null) {
//do nothing
}
ToastMaster("scSocket" + scSocket);
BTisConnected=true; //turn screen purple
if (scSocket!=null) {
sendReceiveBT = new SendReceiveBytes(scSocket);
new Thread(sendReceiveBT).start();
String red = "r";
byte[] myByte = stringToBytesUTFCustom(red);
sendReceiveBT.write(myByte);
}
}
}
}
public static byte[] stringToBytesUTFCustom(String str) {
char[] buffer = str.toCharArray();
byte[] b = new byte[buffer.length << 1];
for (int i = 0; i < buffer.length; i++) {
int bpos = i << 1;
b[bpos] = (byte) ((buffer[i]&0xFF00)>>8);
b[bpos + 1] = (byte) (buffer[i]&0x00FF);
}
return b;
}
public class ConnectToBluetooth implements Runnable {
private BluetoothDevice btShield;
private BluetoothSocket mySocket = null;
private UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public ConnectToBluetooth(BluetoothDevice bluetoothShield) {
btShield = bluetoothShield;
try {
mySocket = btShield.createRfcommSocketToServiceRecord(uuid);
}
catch(IOException createSocketException) {
//Problem with creating a socket
Log.e("ConnectToBluetooth", "Error with Socket");
}
}
#Override
public void run() {
/* Cancel discovery on Bluetooth Adapter to prevent slow connection */
bluetooth.cancelDiscovery();
try {
/*Connect to the bluetoothShield through the Socket. This will block
until it succeeds or throws an IOException */
mySocket.connect();
scSocket=mySocket;
}
catch (IOException connectException) {
Log.e("ConnectToBluetooth", "Error with Socket Connection");
try {
mySocket.close(); //try to close the socket
}
catch(IOException closeException) {
}
return;
}
}
// Will allow you to get the socket from this class
public BluetoothSocket getSocket() {
return mySocket;
}
/* Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mySocket.close();
}
catch (IOException e) {
}
}
}
private class SendReceiveBytes implements Runnable {
private BluetoothSocket btSocket;
private InputStream btInputStream = null;
;
private OutputStream btOutputStream = null;
String TAG = "SendReceiveBytes";
public SendReceiveBytes(BluetoothSocket socket) {
btSocket = socket;
try {
btInputStream = btSocket.getInputStream();
btOutputStream = btSocket.getOutputStream();
}
catch (IOException streamError) {
Log.e(TAG, "Error when getting input or output Stream");
}
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = btInputStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
}
catch (IOException e) {
Log.e(TAG, "Error reading from btInputStream");
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
btOutputStream.write(bytes);
}
catch (IOException e) {
Log.e(TAG, "Error when writing to btOutputStream");
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
btSocket.close();
}
catch (IOException e) {
Log.e(TAG, "Error when closing the btSocket");
}
}
}
/* My ToastMaster function to display a messageBox on the screen */
void ToastMaster(String textToDisplay) {
Toast myMessage = Toast.makeText(getApplicationContext(),
textToDisplay,
Toast.LENGTH_SHORT);
myMessage.setGravity(Gravity.CENTER, 0, 0);
myMessage.show();
}
//onClickWidget is called when a widget is clicked/touched
void onClickWidget(APWidget widget) {
String sendLetter = "";
//Disable the previous Background colour changers
foundDevice=false;
BTisConnected=false;
if (widget == redButton) { //if the red button was clicked
buttonText="RED";
background(255, 0, 0);
sendLetter = "r";
}
else if (widget == greenButton) { //if the green button was clicked
buttonText="GREEN";
background(0, 255, 0);
sendLetter = "g";
}
else if (widget == blueButton) { //if the blue button was clicked
buttonText="BLUE";
background(0, 0, 255);
sendLetter = "b";
}
else if (widget == offButton) { //if the off button was clicked
buttonText="OFF";
background(0);
sendLetter = "x";
}
else if (widget == yeniButton) { //if the off button was clicked
buttonText="yeni buton";
background(100,100,100);
sendLetter = "y";
}
byte[] myByte = stringToBytesUTFCustom(sendLetter);
sendReceiveBT.write(myByte);
}
Hello i can send data from android to arduino but i cant send data from arduino to android via Bluetooth on procesing i dont get any Error but I cant see anything on display of android app.. i used for blueToothSerial.print(XXX); for arduino side .. and used text(readMessage , width,heigth); for processing side.
Please check it out . Where is my fault ? . What am I missing ?
Thanks in Advance
** on arduino side**
#include <SoftwareSerial.h>
#include <Stepper.h>
#define RxD 6 // This is the pin that the Bluetooth (BT_TX) will transmit to the Arduino (RxD)
#define TxD 7 // This is the pin that the Bluetooth (BT_RX) will receive from the Arduino (TxD)
#define DEBUG_ENABLED 1
#define RELAY 4
SoftwareSerial blueToothSerial(RxD, TxD);
int led = 9 ;
int in1Pin = 10;
int in2Pin = 12;
int in3Pin = 11;
int in4Pin = 13;
data = 100;
Stepper motor(512, in1Pin, in2Pin, in3Pin, in4Pin);
/*----------------------SETUP----------------------------*/
void setup() {
Serial.begin(9600);//low Serial communication via USB cable to computer (if required)
pinMode(RxD, INPUT); // Setup the Arduino to receive INPUT from the bluetooth shield on Digital Pin 6
pinMode(TxD, OUTPUT); // Setup the Arduino to send data (OUTPUT) to the bluetooth shield on Digital Pin 7
pinMode(13, OUTPUT); // Use onboard LED if required.
pinMode(9,OUTPUT);
motor.setSpeed(30);
pinMode(RELAY,OUTPUT);
setupBlueToothConnection(); //Used to initialise the Bluetooth shield
}
/*----------------------LOOP----------------------------*/
void loop() {
digitalWrite(13, LOW); //Turn off the onboard Arduino LED
char recvChar;
while (1) {
if (blueToothSerial.available()) {//check if there's any data sent from the remote bluetooth shield
recvChar = blueToothSerial.read();
Serial.print(recvChar); // Print the character received to the Serial Monitor (if required)
//If the character received = 'r' , then change the RGB led to display a RED colour
if (recvChar=='r') {
motor.step(300);
digitalWrite(led,HIGH);23
delay(500);
}
//If the character received = 'g' , then change the RGB led to display a GREEN colour
if (recvChar=='g') {
digitalWrite(led,LOW);
motor.step(-300);
}
//If the character received = 'b' , then change the RGB led to display a BLUE colour
if (recvChar=='b') {
digitalWrite(led,HIGH);
digitalWrite(RELAY,HIGH);
}
//If the character received = 'x' , then turn RGB led OFF
if (recvChar=='x') {
digitalWrite(led,LOW);
digitalWrite(RELAY,LOW);
}
}
//You can use the following code to deal with any information coming from the Computer (serial monitor)
if (Serial.available()) {
recvChar = Serial.read();
//This will send value obtained (recvChar) to the phone. The value will be displayed on the phone.
blueToothSerial.print(recvChar);
blueToothSerial.print("burak:");
blueToothSerial.print(data); // data which is defined begin of sketch
}
}
}
//The following code is necessary to setup the bluetooth shield ------copy and paste----------------
void setupBlueToothConnection()
{
blueToothSerial.begin(9600);// BluetoothBee BaudRate to default baud rate 38400
blueToothSerial.print("\r\n+STWMOD=0\r\n"); //set the bluetooth work in slave mode
blueToothSerial.print("\r\n+STNA=HC-05\r\n"); //set the bluetooth name as "SeeedBTSlave"
blueToothSerial.print("\r\n+STOAUT=1\r\n"); // Permit Paired device to connect me
blueToothSerial.print("\r\n+STAUTO=0\r\n"); // Auto-connection should be forbidden here
delay(2000); // This delay is required.
blueToothSerial.print("\r\n+INQ=1\r\n"); //make the slave bluetooth inquirable
Serial.println("The slave bluetooth is inquirable!");
delay(2000); // This delay is required.
blueToothSerial.flush();
}
And i have processing sketch .
*on processing side *
/* BluetoothApp1: Written by ScottC on 25 March 2013 using
Processing version 2.0b8
Tested on a Samsung Galaxy SII, with Android version 2.3.4
Android ADK - API 10 SDK platform
Apwidgets version: r44 */
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.widget.Toast;
import android.view.Gravity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import java.util.UUID;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import apwidgets.*;
public BluetoothSocket scSocket;
//Used for the GUI**************************************
APWidgetContainer widgetContainer;
APButton redButton, greenButton, blueButton, offButton,yeniButton;
String buttonText="";
int buttonWidth=0;
int buttonHeight=0;
int n=4; //number of buttons
int gap=10; //gap between buttons
boolean foundDevice=false; //When true, the screen turns green.
boolean BTisConnected=false; //When true, the screen turns purple.
String serverName = "ArduinoBasicsServer";
// Message types used by the Handler
public static final int MESSAGE_WRITE = 1;
public static final int MESSAGE_READ = 2;
String readMessage="";
//Used to send bytes to the Arduino
SendReceiveBytes sendReceiveBT=null;
//Get the default Bluetooth adapter
BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
/*The startActivityForResult() within setup() launches an
Activity which is used to request the user to turn Bluetooth on.
The following onActivityResult() method is called when this
Activity exits. */
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode==0) {
if (resultCode == RESULT_OK) {
ToastMaster("Bluetooth simdi acildi");
}
else {
ToastMaster("Programi kullanabilmek icin Bluetoot acmalisiniz!!!");
}
}
}
/* Create a BroadcastReceiver that will later be used to
receive the names of Bluetooth devices in range. */
BroadcastReceiver myDiscoverer = new myOwnBroadcastReceiver();
/* Create a BroadcastReceiver that will later be used to
identify if the Bluetooth device is connected */
BroadcastReceiver checkIsConnected = new myOwnBroadcastReceiver();
// The Handler that gets information back from the Socket
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_WRITE:
//Do something when writing
break;
case MESSAGE_READ:
//Get the bytes from the msg.obj
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
readMessage = new String(readBuf, 0, msg.arg1);
break;
}
}
};
void setup() {
orientation(LANDSCAPE);
//Setup GUI********************************
buttonWidth=((width/n)-(n*gap));
buttonHeight=(height/2);
widgetContainer = new APWidgetContainer(this); //create new container for widgets
yeniButton = new APButton(700,600,(buttonWidth/2),(buttonHeight/2),"Yeni buton");
redButton =new APButton(0,0 ,400,400, "PERDE YUKARI"); //Create a RED button
// redButton =new APButton((buttonWidth*(n-4)+(gap*1)), gap, buttonWidth, buttonHeight, "RED"); //Create a RED button
greenButton = new APButton((buttonWidth*(n-3)+(gap*2)), gap, buttonWidth, buttonHeight, "GREEN"); //Create a GREEN button
blueButton = new APButton((buttonWidth*(n-2)+(gap*3)), gap, buttonWidth, buttonHeight, "BLUE"); //Create a BLUE button
offButton = new APButton((buttonWidth*(n-1)+(gap*4)), gap, buttonWidth, buttonHeight, "OFF"); //Create a OFF button
widgetContainer.addWidget(redButton); //place red button in container
widgetContainer.addWidget(greenButton); //place green button in container
widgetContainer.addWidget(blueButton);//place blue button in container
widgetContainer.addWidget(offButton);//place off button in container
widgetContainer.addWidget(yeniButton);
background(0); //Start with a black background
/*IF Bluetooth is NOT enabled, then ask user permission to enable it */
if (!bluetooth.isEnabled()) {
Intent requestBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(requestBluetooth, 0);
}
/*If Bluetooth is now enabled, then register a broadcastReceiver to report any
discovered Bluetooth devices, and then start discovering */
if (bluetooth.isEnabled()) {
registerReceiver(myDiscoverer, new IntentFilter(BluetoothDevice.ACTION_FOUND));
registerReceiver(checkIsConnected, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED));
//Start bluetooth discovery if it is not doing so already
if (!bluetooth.isDiscovering()) {
bluetooth.startDiscovery();
}
}
}
void draw() {
//Display a green screen if a device has been found,
//Display a purple screen when a connection is made to the device
if (foundDevice) {
if (BTisConnected) {
background(170, 50, 255); // purple screen
}
else {
background(10, 255, 10); // green screen
}
}
//Change the text based on the button being pressed.
text(buttonText, 10, buttonHeight+(buttonHeight/2));
//Display anything received from Arduino
text(readMessage, 10, buttonHeight+(buttonHeight/2)+30);
}
/* This BroadcastReceiver will display discovered Bluetooth devices */
public class myOwnBroadcastReceiver extends BroadcastReceiver {
ConnectToBluetooth connectBT;
#Override
public void onReceive(Context context, Intent intent) {
String action=intent.getAction();
ToastMaster("Eylem:" + action);
//Notification that BluetoothDevice is FOUND
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
//Display the name of the discovered device
String discoveredDeviceName = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
ToastMaster("Bulunan Cihaz: " + discoveredDeviceName);
//Display more information about the discovered device
BluetoothDevice discoveredDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
ToastMaster("getAddress() = " + discoveredDevice.getAddress());
ToastMaster("getName() = " + discoveredDevice.getName());
int bondyState=discoveredDevice.getBondState();
ToastMaster("getBondState() = " + bondyState);
String mybondState;
switch(bondyState) {
case 10:
mybondState="BOND_NONE";
break;
case 11:
mybondState="BOND_BONDING";
break;
case 12:
mybondState="BOND_BONDED";
break;
default:
mybondState="INVALID BOND STATE";
break;
}
ToastMaster("getBondState() = " + mybondState);
//Change foundDevice to true which will make the screen turn green
foundDevice=true;
//Connect to the discovered bluetooth device (SeeedBTSlave)
if (discoveredDeviceName.equals("HC-05")) {
ToastMaster("BAGLANIYOR!!");
unregisterReceiver(myDiscoverer);
connectBT = new ConnectToBluetooth(discoveredDevice);
//Connect to the the device in a new thread
new Thread(connectBT).start();
}
}
//Notification if bluetooth device is connected
if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
ToastMaster("CIHAZINIZ BAGLANDI");
int counter=0;
while (scSocket==null) {
//do nothing
}
ToastMaster("scSocket" + scSocket);
BTisConnected=true; //turn screen purple
if (scSocket!=null) {
sendReceiveBT = new SendReceiveBytes(scSocket);
new Thread(sendReceiveBT).start();
String red = "r";
byte[] myByte = stringToBytesUTFCustom(red);
sendReceiveBT.write(myByte);
}
}
}
}
public static byte[] stringToBytesUTFCustom(String str) {
char[] buffer = str.toCharArray();
byte[] b = new byte[buffer.length << 1];
for (int i = 0; i < buffer.length; i++) {
int bpos = i << 1;
b[bpos] = (byte) ((buffer[i]&0xFF00)>>8);
b[bpos + 1] = (byte) (buffer[i]&0x00FF);
}
return b;
}
public class ConnectToBluetooth implements Runnable {
private BluetoothDevice btShield;
private BluetoothSocket mySocket = null;
private UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public ConnectToBluetooth(BluetoothDevice bluetoothShield) {
btShield = bluetoothShield;
try {
mySocket = btShield.createRfcommSocketToServiceRecord(uuid);
}
catch(IOException createSocketException) {
//Problem with creating a socket
Log.e("ConnectToBluetooth", "Error with Socket");
}
}
#Override
public void run() {
/* Cancel discovery on Bluetooth Adapter to prevent slow connection */
bluetooth.cancelDiscovery();
try {
/*Connect to the bluetoothShield through the Socket. This will block
until it succeeds or throws an IOException */
mySocket.connect();
scSocket=mySocket;
}
catch (IOException connectException) {
Log.e("ConnectToBluetooth", "Error with Socket Connection");
try {
mySocket.close(); //try to close the socket
}
catch(IOException closeException) {
}
return;
}
}
// Will allow you to get the socket from this class
public BluetoothSocket getSocket() {
return mySocket;
}
/* Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mySocket.close();
}
catch (IOException e) {
}
}
}
private class SendReceiveBytes implements Runnable {
private BluetoothSocket btSocket;
private InputStream btInputStream = null;
;
private OutputStream btOutputStream = null;
String TAG = "SendReceiveBytes";
public SendReceiveBytes(BluetoothSocket socket) {
btSocket = socket;
try {
btInputStream = btSocket.getInputStream();
btOutputStream = btSocket.getOutputStream();
}
catch (IOException streamError) {
Log.e(TAG, "Error when getting input or output Stream");
}
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = btInputStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
}
catch (IOException e) {
Log.e(TAG, "Error reading from btInputStream");
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
btOutputStream.write(bytes);
}
catch (IOException e) {
Log.e(TAG, "Error when writing to btOutputStream");
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
btSocket.close();
}
catch (IOException e) {
Log.e(TAG, "Error when closing the btSocket");
}
}
}
/* My ToastMaster function to display a messageBox on the screen */
void ToastMaster(String textToDisplay) {
Toast myMessage = Toast.makeText(getApplicationContext(),
textToDisplay,
Toast.LENGTH_SHORT);
myMessage.setGravity(Gravity.CENTER, 0, 0);
myMessage.show();
}
//onClickWidget is called when a widget is clicked/touched
void onClickWidget(APWidget widget) {
String sendLetter = "";
//Disable the previous Background colour changers
foundDevice=false;
BTisConnected=false;
if (widget == redButton) { //if the red button was clicked
buttonText="RED";
background(255, 0, 0);
sendLetter = "r";
}
else if (widget == greenButton) { //if the green button was clicked
buttonText="GREEN";
background(0, 255, 0);
sendLetter = "g";
}
else if (widget == blueButton) { //if the blue button was clicked
buttonText="BLUE";
background(0, 0, 255);
sendLetter = "b";
}
else if (widget == offButton) { //if the off button was clicked
buttonText="OFF";
background(0);
sendLetter = "x";
}
else if (widget == yeniButton) { //if the off button was clicked
buttonText="yeni buton";
background(100,100,100);
sendLetter = "y";
}
byte[] myByte = stringToBytesUTFCustom(sendLetter);
sendReceiveBT.write(myByte);
}
you forgot to declare the mode (int ) in data on line 14
SoftwareSerial blueToothSerial(RxD, TxD);
int led = 9 ;
int in1Pin = 10;
int in2Pin = 12;
int in3Pin = 11;
int in4Pin = 13;
int data = 100;
I see a fault on the Arduino code - don't think that 23 should be there.
if (recvChar=='r') {
motor.step(300);
digitalWrite(led,HIGH);23
Also - this code requires that you send data from the serial monitor before any Arduino data is sent through bluetooth . Try to echo back the character received by the arduino on this line
Serial.print(recvChar);
Change it to
blueToothSerial.print(recvChar);
Burak have you solved the problem? I am working with Arduino-Android communication for my project. Try to use blueToothSerial.write("burak:");
Also to test your program run some test program. Make some changes with Rx,Tx and you can test it via Arduino Serial Monitor.
/*
Pinout:
8 --> BT module Tx
9 --> BT module Rx
*/
#include <SoftwareSerial.h>
SoftwareSerial mySerial(8, 9); // RX, TX
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
Serial.println("I am ready to send some stuff!");
// set the data rate for the SoftwareSerial port
mySerial.begin(9600);
}
void loop() // run over and over
{
if (mySerial.available())
Serial.write(mySerial.read());
while (Serial.available())
mySerial.write(Serial.read());
}
Also you could try to use ready app from GooglePlay, like "Bluetooth Terminal". If it works with this then look in your code. Please check this for now and later we will be able to continue.
I am building an Android app that communicates with an Arduino board via bluetooth, I have the bluetooth code in a class of it's own called BlueComms. To connect to the device I use the following methord:
public boolean connectDevice() {
CheckBt();
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
Log.d(TAG, "Connecting to ... " + device);
mBluetoothAdapter.cancelDiscovery();
try {
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
btSocket.connect();
outStream = btSocket.getOutputStream();
Log.d(TAG, "Connection made.");
return true;
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
Log.d(TAG, "Unable to end the connection");
return false;
}
Log.d(TAG, "Socket creation failed");
}
return false;
}
private void CheckBt() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!mBluetoothAdapter.isEnabled()) {
System.out.println("Bt dsbld");
}
if (mBluetoothAdapter == null) {
System.out.println("Bt null");
}
}
This connects fine but as soon as I leave the activity I connected through it drops the connection, showing this through LogCat,
D/dalvikvm(21623): GC_CONCURRENT freed 103K, 10% free 2776K/3056K, paused 5ms+2ms, total 35ms
I can no longer connect to the device, but if I call killBt() it throws a fatal error and if I try to send data I get a 'Socket creation failed' error. My send message code is as follows:
public void sendData(String data, int recvAct) {
try {
outStream = btSocket.getOutputStream();
} catch (IOException e) {
Log.d(TAG, "Bug BEFORE Sending stuff", e);
}
String message = data;
byte[] msgBuffer = message.getBytes();
try {
outStream.write(msgBuffer);
} catch (IOException e) {
Log.d(TAG, "Bug while sending stuff", e);
}
}
How should I go about preventing the connection from being paused by the activity I connect with when I switch a different activity, I am switching activities with this code:
Intent myIntent = new Intent(v.getContext(), Timelapse.class);
startActivityForResult(myIntent, 0);
Many Thanks,
Rozz
Where did you store the instance of your BlueComms class? If you put it in the first activity then the class instance would have been killed when that activity was destroyed as you left it and moved to the next activity (NB activities also get destroyed on screen rotation)
So you need to find a way to keep the instance of BlueComms class alive for as long as you need it. You could pass it between activities via public properties and store it in onRetainNonConfigurationInstance() during rotations.
An easier trick is to create a class that extends Application use it as the application delegate for your app and add public property to it to store the instance of BlueComms class within it. That way the instance of BlueComms class would be alive for the lifetime of you app.
Extend Application
import android.app.Application;
public class cBaseApplication extends Application {
public BlueComms myBlueComms;
#Override
public void onCreate()
{
super.onCreate();
myBlueComms = new BlueComms();
}
}
Make your class the application delegate in the app manifest
<application
android:name="your.app.namespace.cBaseApplication"
android:icon="#drawable/icon"
android:label="#string/app_name" >
Access the base app from any of your Activities like this
((cBaseApplication)this.getApplicationContext()).myBlueComms.SomeMethod();
What I have done is, Created a singleton class for BluetoothConnection.
So socket creation happens only for one time.
When onCreate method of any activity is created, it first fetch instance of BluetoothConnection class.
Handler is used to send messages from thread in BluetoothConnection class to the corresponding activity by settings Handler.
Like:
Class MyBTConnection{
private static MyBTConnection connectionObj;
private Handler mHandler;
public MyBTConnection() { //constructor }
public static MyBTConnection getInstance() {
if(connectionObj == null) {
connectionObj = new MyBTConnection();
}
return connectionObj;
}
}
public void setHandler(Handler handler) {
mHandler = handler;
}
..... Code for Bluetooth Connection ....
to send message :
mHandler.obtainMessage(what).sendToTarget();
}
// in first activity
class MainActivity extends Activity {
private MyBTConnection connectionObj;
public onCreate(....) {
/*
* Since this is first call for getInstance. A new object
* of MyBTConnection will be created and a connection to
* remote bluetooth device will be established.
*/
connectionObj = MyBTConnection.getInstance();
connectionObj.setHandler(mHandler);
}
private Handler mHandler = new Handler(){
public void onReceive(...) {
/// handle received messages here
}
};
}
// in second activity
class SecondActivity extends Activity {
private MyBTConnection connectionObj;
public onCreate(....) {
/*
* Since this is second call for getInstance.
* Object for MyBTConnection was already created in previous
* activity. So getInstance will return that previously
* created object and in that object, connection to remote
* bluetooth device is already established so you can
* continue your work here.
*/
connectionObj = MyBTConnection.getInstance();
connectionObj.setHandler(mHandler);
}
private Handler mHandler = new Handler(){
public void onReceive(...) {
/// handle received messages here
}
};
}
I'm currently having exactly the same issue and I was thinking of opening/closing the Bluetooth socket each time an Activity asks for it. Each Activity has it's own BlueComms instance.
Because my application will became a bit complex and there will be Bluetooth threaded requests from different activities, I'm thinking that this way will become very difficult to use and troubleshoot.
Another way I came across by reading here...
https://developer.android.com/guide/components/services.html
A Service can be created on the background having a Bluetooth socket always on. All Bluetooth requests can be made using Intent towards this service. This also creates some fair amount of complexity but feels a lot more tidy and organized.
I'm currently having this dilemma, either to use a thread for each activity or use a service. I don't know which way is actually better.
When you are Selecting A device to connect and when you are click on the device list item for requesting a connection to the device use AsyncTask
and put the connect method inside the AsyncTask like this :-
AsyncTask.execute(new Runnable() {
#Override
public void run() {
try {
bluetoothSocket = Globals.bluetoothDevice.createRfcommSocketToServiceRecord(Globals.DEFAULT_SPP_UUID);
bluetoothSocket.connect();
// After successful connect you can open InputStream
} catch (IOException e) {
e.printStackTrace();
}
**Here is the full code for the same problem that i have cracked :-**
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
lablelexconnected.setText("Connecting ...");
bdDevice = arrayListBluetoothDevices.get(position);
//bdClass = arrayListBluetoothDevices.get(position)
// Toast.makeText(getApplicationContext()," " + bdDevice.getAddress(),Toast.LENGTH_SHORT).show();
Log.i("Log", "The dvice : " + bdDevice.toString());
bdDevice = bluetoothAdapter.getRemoteDevice(bdDevice.getAddress());
Globals.bluetoothDevice = bluetoothAdapter.getRemoteDevice(bdDevice.getAddress());
System.out.println("Device in GPS Settings : " + bdDevice);
// startService(new Intent(getApplicationContext(),MyService.class));
/* Intent i = new Intent(GpsSettings.this, MyService.class);
startService(i);*/
// finish();
// connectDevice();
AsyncTask.execute(new Runnable() {
#Override
public void run() {
try {
bluetoothSocket = Globals.bluetoothDevice.createRfcommSocketToServiceRecord(Globals.DEFAULT_SPP_UUID);
bluetoothSocket.connect();
// After successful connect you can open InputStream
InputStream in = null;
in = bluetoothSocket.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
br = new BufferedReader(isr);
while (found == 0) {
String nmeaMessage = br.readLine();
Log.d("NMEA", nmeaMessage);
// parse NMEA messages
sentence = nmeaMessage;
System.out.println("Sentence : " + sentence);
if (sentence.startsWith("$GPRMC")) {
String[] strValues = sentence.split(",");
System.out.println("StrValues : " + strValues[3] + " " + strValues[5] + " " + strValues[8]);
if (strValues[3].equals("") && strValues[5].equals("") && strValues[8].equals("")) {
Toast.makeText(getApplicationContext(), "Location Not Found !!! ", Toast.LENGTH_SHORT).show();
} else {
latitude = Double.parseDouble(strValues[3]);
if (strValues[4].charAt(0) == 'S') {
latitude = -latitude;
}
longitude = Double.parseDouble(strValues[5]);
if (strValues[6].charAt(0) == 'W') {
longitude = -longitude;
}
course = Double.parseDouble(strValues[8]);
// Toast.makeText(getApplicationContext(), "latitude=" + latitude + " ; longitude=" + longitude + " ; course = " + course, Toast.LENGTH_SHORT).show();
System.out.println("latitude=" + latitude + " ; longitude=" + longitude + " ; course = " + course);
// found = 1;
NMEAToDecimalConverter(latitude, longitude);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
});
I need to send file to a computer instead of another android application. I have looked at the bluetooth api, but it only allow connection as client-server. In my case I dont know what UUId would be on the computer. Do I need to look at obex. I haven't used it before. So any help would be benficial.
Try this.
I can send a file using this code.
ContentValues values = new ContentValues();
values.put(BluetoothShare.URI, "file:///sdcard/refresh.txt");
values.put(BluetoothShare.DESTINATION, deviceAddress);
values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_OUTBOUND);
Long ts = System.currentTimeMillis();
values.put(BluetoothShare.TIMESTAMP, ts);
getContentResolver().insert(BluetoothShare.CONTENT_URI, values);
Code of BluetoothShare.java
import android.provider.BaseColumns;
import android.net.Uri;
/**
* Exposes constants used to interact with the Bluetooth Share manager's content
* provider.
*/
public final class BluetoothShare implements BaseColumns {
private BluetoothShare() {
}
/**
* The permission to access the Bluetooth Share Manager
*/
public static final String PERMISSION_ACCESS = "android.permission.ACCESS_BLUETOOTH_SHARE";
/**
* The content:// URI for the data table in the provider
*/
public static final Uri CONTENT_URI = Uri.parse("content://com.android.bluetooth.opp/btopp");
/**
* Broadcast Action: this is sent by the Bluetooth Share component to
* transfer complete. The request detail could be retrieved by app * as _ID
* is specified in the intent's data.
*/
public static final String TRANSFER_COMPLETED_ACTION = "android.btopp.intent.action.TRANSFER_COMPLETE";
/**
* This is sent by the Bluetooth Share component to indicate there is an
* incoming file need user to confirm.
*/
public static final String INCOMING_FILE_CONFIRMATION_REQUEST_ACTION = "android.btopp.intent.action.INCOMING_FILE_NOTIFICATION";
/**
* This is sent by the Bluetooth Share component to indicate there is an
* incoming file request timeout and need update UI.
*/
public static final String USER_CONFIRMATION_TIMEOUT_ACTION = "android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT";
/**
* The name of the column containing the URI of the file being
* sent/received.
*/
public static final String URI = "uri";
/**
* The name of the column containing the filename that the incoming file
* request recommends. When possible, the Bluetooth Share manager will
* attempt to use this filename, or a variation, as the actual name for the
* file.
*/
public static final String FILENAME_HINT = "hint";
/**
* The name of the column containing the filename where the shared file was
* actually stored.
*/
public static final String _DATA = "_data";
/**
* The name of the column containing the MIME type of the shared file.
*/
public static final String MIMETYPE = "mimetype";
/**
* The name of the column containing the direction (Inbound/Outbound) of the
* transfer. See the DIRECTION_* constants for a list of legal values.
*/
public static final String DIRECTION = "direction";
/**
* The name of the column containing Bluetooth Device Address that the
* transfer is associated with.
*/
public static final String DESTINATION = "destination";
/**
* The name of the column containing the flags that controls whether the
* transfer is displayed by the UI. See the VISIBILITY_* constants for a
* list of legal values.
*/
public static final String VISIBILITY = "visibility";
/**
* The name of the column containing the current user confirmation state of
* the transfer. Applications can write to this to confirm the transfer. the
* USER_CONFIRMATION_* constants for a list of legal values.
*/
public static final String USER_CONFIRMATION = "confirm";
/**
* The name of the column containing the current status of the transfer.
* Applications can read this to follow the progress of each download. See
* the STATUS_* constants for a list of legal values.
*/
public static final String STATUS = "status";
/**
* The name of the column containing the total size of the file being
* transferred.
*/
public static final String TOTAL_BYTES = "total_bytes";
/**
* The name of the column containing the size of the part of the file that
* has been transferred so far.
*/
public static final String CURRENT_BYTES = "current_bytes";
/**
* The name of the column containing the timestamp when the transfer is
* initialized.
*/
public static final String TIMESTAMP = "timestamp";
/**
* This transfer is outbound, e.g. share file to other device.
*/
public static final int DIRECTION_OUTBOUND = 0;
/**
* This transfer is inbound, e.g. receive file from other device.
*/
public static final int DIRECTION_INBOUND = 1;
/**
* This transfer is waiting for user confirmation.
*/
public static final int USER_CONFIRMATION_PENDING = 0;
/**
* This transfer is confirmed by user.
*/
public static final int USER_CONFIRMATION_CONFIRMED = 1;
/**
* This transfer is auto-confirmed per previous user confirmation.
*/
public static final int USER_CONFIRMATION_AUTO_CONFIRMED = 2;
/**
* This transfer is denied by user.
*/
public static final int USER_CONFIRMATION_DENIED = 3;
/**
* This transfer is timeout before user action.
*/
public static final int USER_CONFIRMATION_TIMEOUT = 4;
/**
* This transfer is visible and shows in the notifications while in progress
* and after completion.
*/
public static final int VISIBILITY_VISIBLE = 0;
/**
* This transfer doesn't show in the notifications.
*/
public static final int VISIBILITY_HIDDEN = 1;
/**
* Returns whether the status is informational (i.e. 1xx).
*/
public static boolean isStatusInformational(int status) {
return (status >= 100 && status < 200);
}
/**
* Returns whether the transfer is suspended. (i.e. whether the transfer
* won't complete without some action from outside the transfer manager).
*/
public static boolean isStatusSuspended(int status) {
return (status == STATUS_PENDING);
}
/**
* Returns whether the status is a success (i.e. 2xx).
*/
public static boolean isStatusSuccess(int status) {
return (status >= 200 && status < 300);
}
/**
* Returns whether the status is an error (i.e. 4xx or 5xx).
*/
public static boolean isStatusError(int status) {
return (status >= 400 && status < 600);
}
/**
* Returns whether the status is a client error (i.e. 4xx).
*/
public static boolean isStatusClientError(int status) {
return (status >= 400 && status < 500);
}
/**
* Returns whether the status is a server error (i.e. 5xx).
*/
public static boolean isStatusServerError(int status) {
return (status >= 500 && status < 600);
}
/**
* Returns whether the transfer has completed (either with success or
* error).
*/
public static boolean isStatusCompleted(int status) {
return (status >= 200 && status < 300) || (status >= 400 && status < 600);
}
/**
* This transfer hasn't stated yet
*/
public static final int STATUS_PENDING = 190;
/**
* This transfer has started
*/
public static final int STATUS_RUNNING = 192;
/**
* This transfer has successfully completed. Warning: there might be other
* status values that indicate success in the future. Use isSucccess() to
* capture the entire category.
*/
public static final int STATUS_SUCCESS = 200;
/**
* This request couldn't be parsed. This is also used when processing
* requests with unknown/unsupported URI schemes.
*/
public static final int STATUS_BAD_REQUEST = 400;
/**
* This transfer is forbidden by target device.
*/
public static final int STATUS_FORBIDDEN = 403;
/**
* This transfer can't be performed because the content cannot be handled.
*/
public static final int STATUS_NOT_ACCEPTABLE = 406;
/**
* This transfer cannot be performed because the length cannot be determined
* accurately. This is the code for the HTTP error "Length Required", which
* is typically used when making requests that require a content length but
* don't have one, and it is also used in the client when a response is
* received whose length cannot be determined accurately (therefore making
* it impossible to know when a transfer completes).
*/
public static final int STATUS_LENGTH_REQUIRED = 411;
/**
* This transfer was interrupted and cannot be resumed. This is the code for
* the OBEX error "Precondition Failed", and it is also used in situations
* where the client doesn't have an ETag at all.
*/
public static final int STATUS_PRECONDITION_FAILED = 412;
/**
* This transfer was canceled
*/
public static final int STATUS_CANCELED = 490;
/**
* This transfer has completed with an error. Warning: there will be other
* status values that indicate errors in the future. Use isStatusError() to
* capture the entire category.
*/
public static final int STATUS_UNKNOWN_ERROR = 491;
/**
* This transfer couldn't be completed because of a storage issue.
* Typically, that's because the file system is missing or full.
*/
public static final int STATUS_FILE_ERROR = 492;
/**
* This transfer couldn't be completed because of no sdcard.
*/
public static final int STATUS_ERROR_NO_SDCARD = 493;
/**
* This transfer couldn't be completed because of sdcard full.
*/
public static final int STATUS_ERROR_SDCARD_FULL = 494;
/**
* This transfer couldn't be completed because of an unspecified un-handled
* OBEX code.
*/
public static final int STATUS_UNHANDLED_OBEX_CODE = 495;
/**
* This transfer couldn't be completed because of an error receiving or
* processing data at the OBEX level.
*/
public static final int STATUS_OBEX_DATA_ERROR = 496;
/**
* This transfer couldn't be completed because of an error when establishing
* connection.
*/
public static final int STATUS_CONNECTION_ERROR = 497;
}
For Ice Cream Sandwich this code is not working so you have to use this code
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
Intent sharingIntent = new Intent(
android.content.Intent.ACTION_SEND);
sharingIntent.setType("image/jpeg");
sharingIntent
.setComponent(new ComponentName(
"com.android.bluetooth",
"com.android.bluetooth.opp.BluetoothOppLauncherActivity"));
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(sharingIntent);
} else {
ContentValues values = new ContentValues();
values.put(BluetoothShare.URI, uri.toString());
Toast.makeText(getBaseContext(), "URi : " + uri,
Toast.LENGTH_LONG).show();
values.put(BluetoothShare.DESTINATION, deviceAddress);
values.put(BluetoothShare.DIRECTION,
BluetoothShare.DIRECTION_OUTBOUND);
Long ts = System.currentTimeMillis();
values.put(BluetoothShare.TIMESTAMP, ts);
getContentResolver().insert(BluetoothShare.CONTENT_URI,
values);
}
You can use the obex library. It seemed that android didn't provide the obex library, but I solved the problem and the solution is posted here.
Further Explanation (please start reading from here if you're busy)
I was trying to create an android phone remote controller (and something similar to telnet server) which helps controlling the phone remotely with my old feature phone.
Main content :Bluetooth FTP client
My first plan was to make the app check the list of files of my feature phone's directory.
But I didn't know how to connect to my feature phone's ftp server.
I googled a lot about how to connect to a ftp server via bluetooth but I could only find that Bluetoorh FTP server used the OBEX Protocol.
I found a useful material (PDF file) in a SO thread and studied about OBEX connect requests, put and get operations.
So I finally wrote some codes that tries to connect to the Bluetooth FTP server. I want to show them to you, but I lost it :( The codes were like just directly writting byte sequences to the output stream.
I also had difficult time finding out what UUID makes the app connect as FTP client. But I tried every UUIDs retrieved using the code below.
String parcels="";
ParcelUuid[] uuids=mBtDevice.getUuids();
int i=0;
for (ParcelUuid p:uuids)
{
parcels += "UUID UUID" + new Integer(i).toString() + "=UUID.fromString((\"" + p.getUuid().toString() + "\"));\n\n";
++i;
}
Nothing seemed to bring me to the answer I wanted. So I googled more and found out that I not only should I use UUID 00001106-0000-1000-8000-00805f9b34fb to connect to OBEX FTP server, but also shold I transmit target header ** with UUID **F9EC7BC4-953C-11D2-984E-525400DC9E09 when sending OBEX connect request.
The code below shows how to connect to a bluetooth FTP server as a client.
try
{
mBtSocket = mBtDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(" 00001106-0000-1000-8000-00805f9b34fb"));
}
catch (Exception e)
{
//e.printStackTrace();
}
Thread thread=new Thread(new Runnable() {
public void run()
{
UUID uuid=UUID.fromString("F9EC7BC4-953C-11D2-984E-525400DC9E09");
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
byte [] bytes=bb.array();
Operation putOperation=null;
Operation getOperation=null;
try
{
// connect the socket
mBtSocket.connect();
//I will explain below
mSession = new ClientSession((ObexTransport)(mTransport = new BluetoothObexTransport(mBtSocket)));
HeaderSet headerset = new HeaderSet();
headerset.setHeader(HeaderSet.TARGET, bytes);
headerset = mSession.connect(headerset);
if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK)
{
mConnected = true;
}
else
{
mSession.disconnect(headerset);
}
...
Then you are now connected as FTP client and are ready to use OBEX operations to send files, request for files, list directories, etc.
However I didn't want to wait an hour to send my command to my android phone. (And it would be inefficient if I increase frequency of polling, as every polling methods are.)
Start reading from here if you are busy
Main content: OBEX OPP
For the reason I mentioned above, I greedly searched for ways to manipulate OPP which I discovered from the OBEX documentation.
You may want to transfer files via bluetooth normally (without defining your protocol and building a new desktop application just for it) to your computer, right? Then sending to OBEX OPP inbox service that is running natively on your desktop windows computer is the best solution. So how can we connect to the OPP (Obex Object Push) inbox service?
Setup OBEX library
Add import javax.obex; to your source code.
If your compiler doesn't support OBEX library, download sources and add to your project from here.
Implement ObexTransport
You should provide a class that implements ObexTransport to the library when you use it. It defines how the library should send data (like by RFCOMM, TCP,...). A sample implementation is here. This can cause some runtime or compilation errors such as there's no method. But you can partially fix those by replacing the method calls to constants like return 4096 instead of return mSocket.getMaxTransmitPacketSize();, outcommenting the if statements of public int getMaxTransmitPacketSize(). Or you can try using reflection to get those methods runtime.
Get BluetoothSocket
Get a bluetooth socket using mBtDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(" 00001105-0000-1000-8000-00805f9b34fb" )); And call connect().
Create ClientSession
Create a instance of your ObexTransport implementation, and create a new ClientSession like mSession = new ClientSession((ObexTransport)(mTransport = new BluetoothObexTransport(mBtSocket)));.
Send OBEX connect request to your computer OPP inbox service.
HeaderSet headerset = new HeaderSet();
// headerset.setHeader(HeaderSet.COUNT,n);
headerset = mSession.connect(null);
if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK)
{
mConnected = true;
}
Send OBEX put requests using the ClientSession.
protected boolean Put(ClientSession session, byte[] bytes, String as, String type)
{
// TODO: Implement this method
//byte [] bytes;
String filename=as;
boolean retry=true;
int times=0;
while (retry && times < 4)
{
Operation putOperation=null;
OutputStream mOutput = null;
//ClientSession mSession = null;
//ArrayUtils.reverse(bytes);
try
{
// Send a file with meta data to the server
final HeaderSet hs = new HeaderSet();
hs.setHeader(HeaderSet.NAME, filename);
hs.setHeader(HeaderSet.TYPE, type);
hs.setHeader(HeaderSet.LENGTH, new Long((long)bytes.length));
Log.v(TAG,filename);
//Log.v(TAG,type);
Log.v(TAG,bytes.toString());
putOperation = session.put(hs);
mOutput = putOperation.openOutputStream();
mOutput.write(bytes);
mOutput.close();
putOperation.close();
}
catch (Exception e)
{
Log.e(TAG, "put failed", e);
retry = true;
times++;
continue;
//e.printStackTrace();
}
finally
{
try
{
if(mOutput!=null)
mOutput.close();
if(putOperation!=null)
putOperation.close();
}
catch (Exception e)
{
Log.e(TAG, "put finally" , e);
retry = true;
times++;
continue;
}
//updateStatus("[CLIENT] Connection Closed");
}
retry = false;
return true;
}
return false;
}
Finally, disconnect.
private void FinishBatch(ClientSession mSession) throws IOException
{
mSession.disconnect(null);
try
{
Thread.sleep((long)500);
}
catch (InterruptedException e)
{}
mBtSocket.close();
}
Then here is a wrapper class.
import android.bluetooth.*;
import android.util.*;
import java.io.*;
import java.util.*;
import javax.obex.*;
public class BluetoothOPPHelper
{
String address;
BluetoothAdapter mBtadapter;
BluetoothDevice device;
ClientSession session;
BluetoothSocket mBtSocket;
protected final UUID OPPUUID=UUID.fromString(("00001105-0000-1000-8000-00805f9b34fb"));
private String TAG="BluetoothOPPHelper";
public BluetoothOPPHelper(String address)
{
mBtadapter=BluetoothAdapter.getDefaultAdapter();
device=mBtadapter.getRemoteDevice(address);
try
{
mBtSocket = device.createRfcommSocketToServiceRecord(OPPUUID);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
public ClientSession StartBatch(int n)
{
ClientSession mSession = null;
// TODO: Implement this method
boolean retry=true;
int times=0;
while (retry && times < 4)
{
//BluetoothConnector.BluetoothSocketWrapper bttmp=null;
try
{
mBtSocket.connect();
//bttmp = (new BluetoothConnector(device,false,BluetoothAdapter.getDefaultAdapter(),Arrays.asList(new UUID[]{OPPUUID,OPPUUID, OPPUUID}))).connect();//*/ device.createInsecureRfcommSocketToServiceRecord(OPPUUID);
/*if(mBtSocket.isConnected())
{
mBtSocket.close();
}*/
}
catch (Exception e)
{
Log.e(TAG, "opp fail sock " + e.getMessage());
retry = true;
times++;
continue;
}
try
{
//mBtSocket=bttmp.getUnderlyingSocket();
// mBtSocket.connect();
BluetoothObexTransport mTransport = null;
mSession = new ClientSession((ObexTransport)(mTransport = new BluetoothObexTransport(mBtSocket)));
HeaderSet headerset = new HeaderSet();
// headerset.setHeader(HeaderSet.COUNT,n);
headerset = mSession.connect(null);
if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK)
{
boolean mConnected = true;
}
else
{
Log.e(TAG, "SEnd by OPP denied;");
mSession.disconnect(headerset);
times++;
continue;
}
}
catch (Exception e)
{
Log.e(TAG, "opp failed;" , e);
retry = true;
times++;
continue;
//e.rintStackTrace();
}
retry=false;
}
return mSession;
}
protected boolean Put(ClientSession session, byte[] bytes, String as, String type)
{
// TODO: Implement this method
//byte [] bytes;
String filename=as;
boolean retry=true;
int times=0;
while (retry && times < 4)
{
Operation putOperation=null;
OutputStream mOutput = null;
//ClientSession mSession = null;
//ArrayUtils.reverse(bytes);
try
{
// Send a file with meta data to the server
final HeaderSet hs = new HeaderSet();
hs.setHeader(HeaderSet.NAME, filename);
hs.setHeader(HeaderSet.TYPE, type);
hs.setHeader(HeaderSet.LENGTH, new Long((long)bytes.length));
Log.v(TAG,filename);
//Log.v(TAG,type);
Log.v(TAG,bytes.toString());
putOperation = session.put(hs);
mOutput = putOperation.openOutputStream();
mOutput.write(bytes);
mOutput.close();
putOperation.close();
}
catch (Exception e)
{
Log.e(TAG, "put failed", e);
retry = true;
times++;
continue;
//e.printStackTrace();
}
finally
{
try
{
if(mOutput!=null)
mOutput.close();
if(putOperation!=null)
putOperation.close();
}
catch (Exception e)
{
Log.e(TAG, "put finally" , e);
retry = true;
times++;
continue;
}
//updateStatus("[CLIENT] Connection Closed");
}
retry = false;
return true;
}
return false;
}
protected boolean Put(ClientSession s, OPPBatchInfo info)
{
return Put(s,info.data,info.as,info.type);
}
private void FinishBatch(ClientSession mSession) throws IOException
{
mSession.disconnect(null);
try
{
Thread.sleep((long)500);
}
catch (InterruptedException e)
{}
mBtSocket.close();
}
public boolean flush() throws IOException
{
if (sendQueue.isEmpty())
{
return true;
}
try
{
Thread.sleep((long)2000);
}
catch (InterruptedException e)
{}
ClientSession session=StartBatch(sendQueue.size());
if (session == null)
{
return false;
}
while (!sendQueue.isEmpty())
{
if (Put(session, sendQueue.remove()) == false)
{
Log.e(TAG, "Put failed");
}
}
FinishBatch(session);
return true;
}
Queue<OPPBatchInfo> sendQueue;
public boolean AddTransfer(String as,String mimetype,byte[] data)
{
return sendQueue.add(new OPPBatchInfo(as,mimetype,data));
}
class OPPBatchInfo
{
String as;
String type;
byte[] data;
public OPPBatchInfo(String as,String type,byte[] data)
{
this.as=as;
this.data=data;
this.type=type;
}
}
}
You need to implement FTP over OBEX. Once you implement the standard protocol and profile, your Android FTP implementation will inter-operate with virtually any Bluetooth FTP server. You'll also need to implement OPP for maximum inter-operability. The OBEX protocol is not so difficult to implement and the specs is freely available.
I know this question is old, but for anyone having to deal with this still:
With this library you can send files via OBEX and commands via RFCOMM:
https://github.com/ddibiasi/Funker
Once connected to your target device, you can manipulate its filesystem.
The following example sends a file:
val rxOBEX = RxObex(device)
rxOBEX
.putFile("rubberduck.txt", "text/plain", "oh hi mark".toByteArray(), "example/directory") // Name of file, mimetype, bytes of file, directory
.subscribeBy(
onComplete = {
Log.d(TAG, "Succesfully sent a testfile to device")
},
onError = { e ->
Log.e(TAG, "Received error!")
}
)
The library is built on Rx, so all calls are non blocking.