Three ways to send data over bluetooth with android

Bluetooth

My recent app that I am developing involves bluetooth and I had to do quite some research about the whole thing and the android API. I had to do lots of searching, but in the end it was ok.
Anyway, while I was searching I had to scrape bits and pieces from every corner of the internet and put them together, so I decided I’ll make one general post about ways to send data over bluetooth in android. I’ll explain everything as we go.


Let’s start from the easiest one:

Intent intent = new Intent();  
intent.setAction(Intent.ACTION_SEND);   
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File("somefile.mp3")));
startActivity(intent);

This is a more intuitive way than the rest 3 but you has the least control with it. What this does is prompt the user which application to use to open the file with – it displays a list. Of course the user selects Bluetooth and then it displays bluetooth settings where the user picks out the device and the transfer is initiated. Needless to say it uses in-built services.
Good for simple things, but isn’t very professional. Also you cannot send any file type you want because of the MIME types.

A bit more complicated is the next snippet:

ContentValues values = new ContentValues();
String address = device.getAddress();
values.put(BluetoothShare.URI, Uri.fromFile(new File("somefile.mp3")).toString());
values.put(BluetoothShare.DESTINATION, address);
values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_OUTBOUND);
Long ts = System.currentTimeMillis();
values.put(BluetoothShare.TIMESTAMP, ts);
Uri contentUri = getContentResolver().insert(BluetoothShare.CONTENT_URI, values);

To use this snippet, you will need this class. Save it as BluetoothShare.java.
Now this snippet is a bit more professional. It still uses the in-built bluetooth service and I heard it doesn’t work on many devices, but no one has confirmed that.
This snippet doesn’t prompt the user for action, instead it sends the data to a ContentResolver then it gets re-routed to the Bluetooth service and put into the stack. From there the file transfer is programatically initiated.
It’s good for sending a file, but you don’t have much control over the process – you cannot programatically cancel the transfer, you cannot empty the stack, you cannot receive feedback through callbacks… Once the last line is executed you don’t have control any more.
Still for file transfer it’s the best solution and you can send any kind of file you want, as long as the receiver accepts it.

Last snippet is the hardest:

public void sendFile(Uri uri, BluetoothSocket bs) throws IOException {
	BufferedInputStream bis = new BufferedInputStream(getContentResolver().openInputStream(uri));
	OutputStream os = bs.getOutputStream();
    try {
        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];
 
        // we need to know how may bytes were read to write them to the byteBuffer
        int len = 0;
        while ((len = bis.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
    } finally {
    	bis.close();
        os.flush();
        os.close();
        bs.close();
    }
}

Needless to say that this only works if you have the Client-Server architecture on both your devices.
To use this, you need to initiate a connection to the device and call this method passing the file URI and active socket as a parameter. It converts the file in chunks and writes them to the stream.

Looks simple, but it is completely different from the first two snippets because it uses the socket to send and receive data which establishes the RFCOMM channel. In-built services use an OBEX OPP mode which have its own packets and headers. You can read more on OBEX PUSH profile in this document (specifically what kind of headers must be included are defined on page 21).

16 comments

  1. germanDeveloper says:

    Hello,

    I just read your blog entry and got a question:
    Is there a way of establishing a bluetooth connection to transfer files with only the remote MAC address? My problem is that my application should only be installed on one side and also don’t want to use the built-in bluetooth app.

    I would really appreciate to get a solution because I have been searching for several weeks without getting a solution.

    Thanks,

    germanDeveloper

  2. Kulverstukas says:

    Hello,

    If your app has to be installed only on one side, there is no way to not use the built-in app for that other end to receive. Otherwise it would be like a security hole – people could send anything to the phone without the user knowing.

    Something has to pick the signal up. You best bet would be making a service that listens for BT connections and accepts them as they come, even then I don’t know if it will work without informing the user… I haven’t played that much with Bluetooth, frankly.

    Working with Bluetooth on android is a massive b*tch :D

  3. mukesh says:

    hi….
    i m trying a bluetooth chat app but can’t a find a proper code to send or receive strings. can get some hep here

  4. Kulverstukas says:

    Hello,
    The code I gave is basic and should get you on your track. You can ask questions when you are stuck at something…

  5. James says:

    does the 2nd method still work in current versions of android? i.e. 4.4.2?

  6. Kulverstukas says:

    I didn’t try, but I don’t see why not?

  7. Diego says:

    Great post! How can I transfer more than one file?

    Uri.fromFile(new File(“somefile.mp3”)));

    Example: I have a folder “photosCam” and I want to transfer all pictures.

  8. Kulverstukas says:

    One way would be to list all your image files and then call that in a loop.

  9. Diego says:

    Thanks for your reply! I have another problem now! I need to delete all the pictures after the transfer. This is my code:

    private void blTRansfer() {
        String origen = Environment.getExternalStorageDirectory().getAbsolutePath() + "/fotosComodin/";
        File directorio = new File(origen);
        File[] archivos = directorio.listFiles(); 
        try { 
            for(File file:archivos) 
            { 
            String	nombredearchivo = origen + file.getName();
                add_multiSelect_file(nombredearchivo);
     
                //
            }
     
            ArrayList uris = new ArrayList();
            int length = mMultiSelectData.size();
            Intent i = new Intent();
            i.setAction(android.content.Intent.ACTION_SEND_MULTIPLE);
            i.setType("image/*");
            for(int a = 0; a < length; a++) {
                File file = new File(mMultiSelectData.get(a));
                uris.add(Uri.fromFile(file));
     
            }
            i.setComponent(
                    new ComponentName("com.android.bluetooth",                         
           "com.android.bluetooth.opp.BluetoothOppLauncherActivity"));
                i.putExtra(Intent.EXTRA_STREAM, uris);
                startActivity(i);
     
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  10. Kulverstukas says:

    I cleaned up the post for ya, as for your question, refer to these posts on SO:
    http://stackoverflow.com/questions/5486529/delete-file-from-internal-storage
    http://stackoverflow.com/questions/1248292/how-to-delete-a-file-from-sd-card

    You would either need to implement a callback which would delete each file after it has been sent, or a callback that fires when an activity finishes and delete all your files in one go. I’d use the first one tho.

  11. Diego says:

    I am new in android , Iwould appreciate if you help me changing my code , the method I throw by a button. I want to delete the full directory after the transfer. I try this “directorio.delete();” After the block of “try catch” and don’t delete the directory…

  12. Kulverstukas says:

    Google is your friend, such simple things were discussed on SO like millions of times: http://stackoverflow.com/questions/4943629/how-to-delete-a-whole-folder-and-content

  13. MM says:

    The second code seems ok as it deal with all types of file..
    Can i get the complete code to how can i implement this thing in an app..??
    Reply asap..PLZ..

  14. Kulverstukas says:

    You need to start using the search function, or at least look at the index page: http://9v.lt/blog/bluequeue-opensource/

  15. MW says:

    Hello, I’m trying to implement the third way in your guide here. I have a server set up on a raspberry pi and a client set up on an android application and I want to send a video file from the raspberry pi to the android app and play the video on the application. So from what I understand, the third code segment you have here is to be executed on the server side (since that’s the one sending the file), however do you have any insight for the client side code or can you point me in the right direction? I’m having trouble finding it on google.

    At this point, once the server executes the third code segment, the entire file should be present on the output stream, now it’s just a matter of taking that data from the stream and saving it somewhere on the app and then playing the video file right?

  16. Kulverstukas says:

    Oh it’s been so long since I dealt with Bluetooth… can’t remember the specifics. I don’t have the client code, but the phone/client should handle receiving files itself. Server only has to write to the stream, from what I remember :P
    Read the document I linked at the end of the post, it explains the how protocol works :)

Leave a Reply

Your email address will not be published. Required fields are marked *