Bluetooth Data Transfer Example

Appportunity

Build your own Android App Dev Empire

Get Instant Access

The following example uses the Android Bluetooth APIs to construct a simple peer-to-peer messaging system that works between two paired Bluetooth devices.

Unfortunately the Android emulator can't currently be used to test Bluetooth functionality. In order to test this application you will need to have two physical devices.

1. Start by creating a new BluetoothTexting project featuring a BluetoothTexting Activity. Modify the manifest to include Bluetooth and bluetooth_admin permissions.

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.paad.chapter13_bluetoothtexting" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon"

android:label="@string/app_name">

<activity android:name=".BluetoothTexting"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>

<uses-sdk android:minSdkVersion="5" />

<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

</manifest>

2. Modify the main.xml layout resource. It should contain a Listview that will display the discovered Bluetooth devices above two buttons — one to start the Server Socket listener, and another to initiate a connection to a listening server.

Also include Text View and Edit Text controls to use for reading and writing messages across the connection.

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">

<EditText android:id="@+id/text_message"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true"

android:enabled="false"

<Button android:id="@+id/button_search" android:text="Search for listener" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_above="@id/text_message"

<Button android:id="@+id/button_listen" android:text="Listen for connection" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_above="@id/button_search"

<ListView android:id="@+id/list_discovered"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_above="@id/button_listen"

android:layout_alignParentTop="true"

<TextView android:id="@+id/text_messages"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_above="@id/button_listen"

android:layout_alignParentTop="true"

android:visibility="gone"

</RelativeLayout>

3. Override the onCreate method of the BluetoothTexting Activity. Make calls to a collection of stub methods that will be used to access the Bluetooth device and wire up the UI controls.

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.ArrayList;

import java.util.UUID;

import android.app.Activity;

import android.bluetooth.BluetoothAdapter;

import android.bluetooth.BluetoothDevice;

import android.bluetooth.BluetoothServerSocket;

import android.bluetooth.BluetoothSocket;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.content.IntentFilter;

import android.os.AsyncTask;

import android.os.Bundle;

import android.os.Handler;

import android.util.Log;

import android.view.KeyEvent;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.View.OnKeyListener;

import android.widget.AdapterView;

import android.widget.ArrayAdapter;

import android.widget.Button;

import android.widget.EditText;

import android.widget.ListView;

import android.widget.TextView;

import android.widget.AdapterView.OnltemClickListener;

public class BluetoothTexting extends Activity { ©Override public void onCreate(Bundle savedlnstanceState) { super.onCreate(savedlnstanceState); setContentView(R.layout.main);

// Get the Bluetooth Adapter configureBluetooth();

// Setup the ListView of discovered devices setupListView();

// Setup search button setupSearchButton();

// Setup listen button setupListenButton();

private void configureBluetooth() {} private void setupListenButton() {} private void setupListView() {} private void setupSearchButton() {}

4. Fill in the configureBluetooth stub to get access to the local Bluetooth Adapter and store it in a field variable. Take this opportunity to create a field variable for a Bluetooth Socket. This will be used to store either the server or client communications socket once a channel has been established. You should also define a UUID to identify your application when connections are being established.

private BluetoothAdapter bluetooth; private BluetoothSocket socket;

private UUID uuid = UUID.fromString("a60f35f0-b93a-11de-8a39-08002009c666");

private void configureBluetooth() {

bluetooth = BluetoothAdapter.getDefaultAdapter();

5. Create a new switchui method. It will be called once a connection is established to enable the Views used for reading and writing messages.

private void switchUI() {

final TextView messageText = (TextView)findViewById(R.id.text_messages); final EditText textEntry = (EditText)findViewById(R.id.text_message);

messageText.setVisibility(View.VISIBLE);

list.setVisibility(View.GONE);

textEntry.setEnabled(true);

6. Create the server listener by filling in the setupListenButton stub. The Listen button should prompt the user to enable discovery. When the discovery window returns, open a Bluetooth Server Socket to listen for connection requests for the discovery duration. Once a connection has been made, make a call to the switchui method you created in Step 5.

private static int DISCOVERY_REQUEST = 1;

private void setupListenButton() {

Button listenButton = (Button)findViewById(R.id.button_listen); listenButton.setOnClickListener(new OnClickListener() { public void onClick(View view) { intent disc;

disc = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); startActivityForResult(disc, DISCOVERY_REQUEST);

©Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {

if (requestCode == DISCOVERY_REQUEST) { boolean isDiscoverable = resultCode > 0; if (isDiscoverable) {

String name = "bluetoothserver"; try {

final BluetoothServerSocket btserver =

bluetooth.listenUsingRfcommWithServiceRecord(name, uuid);

AsyncTask<Integer, Void, BluetoothSocket> acceptThread = new AsyncTask<Integer, Void, BluetoothSocket>() {

©Override protected BluetoothSocket doInBackground(Integer ... params) { try {

socket = btserver.accept(params[0]*1000); return socket; } catch (IOException e) {

Log.d("BLUETOOTH", e.getMessage());

return null;

@Override protected void onPostExecute(BluetoothSocket result) { if (result != null) switchUI();

acceptThread.execute(resultCode); } catch (IOException e) {

Log.d("BLUETOOTH", e.getMessage());

7. Now create the client-side connection code. By performing discovery and displaying each of the possible devices, this code will provide a means for the client device to search for the listening server.

7.1. Start by creating a field variable to store an Array List of discovered Bluetooth Devices.

private ArrayList<BluetoothDevice> foundDevices;

7.2. Fill in the setupListView stub. Create a new Array Adapter that binds the List View to the found devices array.

private ArrayAdapter<BluetoothDevice> aa; private ListView list;

private void setupListView() {

aa = new ArrayAdapter<BluetoothDevice>(this, android.R.layout.simple_list_item_1, foundDevices); list = (ListView)findViewById(R.id.list_discovered); list.setAdapter(aa);

7.3. Create a new Broadcast Receiver that listens for Bluetooth Device discovery broadcasts, adds each discovered device to the array of found devices created in Step 7-1, and notifies the Array Adapter created in Step 7-2.

BroadcastReceiver discoveryResult = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { BluetoothDevice remoteDevice;

remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (bluetooth.getBondedDevices().contains(remoteDevice)) { foundDevices.add(remoteDevice); aa.notifyDataSetChanged();

7.4. Complete the setupSearchButton stub to register the Broadcast Receiver from the previous step and initiate a discovery session. private void setupSearchButton() {

Button searchButton = (Button)findViewById(R.id.button_search);

searchButton.setOnClickListener(new OnClickListener() { public void onClick(View view) { registerReceiver(discoveryResult, new IntentFilter(BluetoothDevice.ACTION_FOUND));

if (!bluetooth.isDiscovering()) { foundDevices.clear(); bluetooth.startDiscovery();

8. The final step to completing the connection-handling code is to extend the setupListView method from Step 7b. Extend this method to include an onItemClickListener that will attempt to asynchronously initiate a client-side connection with the selected remote Bluetooth Device. If it is successful, keep a reference to the socket it creates and make a call to the switchUI method created in Step 5.

private void setupListView() {

aa = new ArrayAdapter<BluetoothDevice>(this, android.R.layout.simple_list_item_1, foundDevices); list = (ListView)findViewById(R.id.list_discovered); list.setAdapter(aa);

list.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View view, int index, long arg3) { AsyncTask<Integer, Void, Void> connectTask = new AsyncTask<Integer, Void, Void>() { @Override protected Void doInBackground(Integer ... params) { try {

BluetoothDevice device = foundDevices.get(params[0]); socket = device.createRfcommSocketToServiceRecord(uuid); socket.connect(); } catch (IOException e) {

Log.d("BLUETOOTH_CLIENT", e.getMessage());

return null;

@Override protected void onPostExecute(Void result) {

switchViews();

connectTask.execute(index);

BluctitfliTeiniii;

00:16;FE;94:39:F2

00:23;D4:34:35:6F

If you run the application on two devices, you can click the "Listen for connection" button on one device, and the "Search for listener" button on the other. The List View should then be populated with all the bonded devices within range, as shown in Figure 13-5.

If you select the other Android device running this application from that list, a connection will be established between the two devices. The following steps will use this communications channel to send simple text messages between the devices.

Start by extending the switchui method. Add a new key listener to the text-entry Edit Text to listen for a D-pad click. When one is detected, read its contents and send them across the Bluetooth communications socket.

Listen rariûrtntiMn

Search for listener

FIGURE 13-5

private void switchUI() {

final TextView messageText = (TextView)findViewById(R.id.text_messages); final EditText textEntry = (EditText)findViewById(R.id.text_message);

messageText.setVisibility(View.VISIBLE);

list.setVisibility(View.GONE);

textEntry.setEnabled(true);

textEntry.setOnKeyListener(new OnKeyListener() {

public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { if ((keyEvent.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_DPAD_CENTER)) { sendMessage(socket, textEntry.getText().toString()); textEntry.setText(""); return true;

return false;

private void sendMessage(BluetoothSocket socket, String msg) {

OutputStream outStream; try {

outStream = socket.getOutputStream(); byte[] byteString = (msg + " ").getBytes(); stringAsBytes[byteString.length — 1] =0; outStream.write(byteString); } catch (IOException e) {

Log.d("BLUETOOTH_COMMS", e.getMessage());

11. In order to receive messages you will need to create an asynchronous listener that monitors the Bluetooth Socket for incoming messages.

11.1. Start by creating a new MessagePoster class that implements Runnable. It should accept two parameters, a Text View and a message string. The received message should be inserted into the Text View parameter. This class will be used to post incoming messages to the UI from a background thread.

private class MessagePoster implements Runnable { private TextView textView; private String message;

public MessagePoster(TextView textView, String message) { this.textView = textView; this.message = message;

textView.setText(message);

11.2. Now create a new BluetoothSocketListener that implements Runnable. It should take a Bluetooth Socket to listen to, a Text View to post incoming messages to, and a Handler to synchronize when posting updates.

When a new message is received, use the MessagePoster Runnable you created in the previous step to post the new message in the Text View.

private class BluetoothSocketListener implements Runnable {

private BluetoothSocket socket; private TextView textView; private Handler handler;

public BluetoothSocketListener(BluetoothSocket socket,

Handler handler, TextView textView) {

this.socket = socket; this.textView = textView; this.handler = handler;

int bufferSize = 1024;

byte[] buffer = new byte[bufferSize];

InputStream instream = socket.getInputStream(); int bytesRead = -1; String message = ""; while (true) { message = "";

bytesRead = instream.read(buffer); if (bytesRead != -1) {

while ((bytesRead==bufferSize)&&(buffer[bufferSize-1] != 0)) { message = message + new String(buffer, 0, bytesRead); bytesRead = instream.read(buffer);

message = message + new String(buffer, 0, bytesRead — 1); handler.post(new MessagePoster(textView, message)); socket.getInputStream();

Log.d("BLUETOOTH_COMMS", e.getMessage());

11.3. Finally, make one more addition to the swichUI method, this time creating and starting the new BluetoothSocketListener you created in the previous step. private Handler handler = new Handler();

private void switchUI() {

final TextView messageText = (TextView)findViewById(R.id.text_messages); final EditText textEntry = (EditText)findViewById(R.id.text_message);

messageText.setVisibility(View.VISIBLE);

list.setVisibility(View.GONE);

textEntry.setEnabled(true);

textEntry.setOnKeyListener(new OnKeyListener() {

public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { if ((keyEvent.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_DPAD_CENTER)) { sendMessage(socket, textEntry.getText().toString()); textEntry.setText(""); return true;

return false;

BluetoothSocketListener bsl = new BluetoothSocketListener(socket, handler, messageText); Thread messageListener = new Thread(bsr); messageListener.start();

All code snippets in this example are part of the Chapter 13 Bluetooth Texting project, available for download at Wrox.com.

If you run the application now, you should be able to configure one device to listen for a connection, use a second device to connect to it — and then, once connected, send simple text messages between the devices.

Note that this example has been kept as simple as possible to highlight the Bluetooth functionality being described. A better implementation would move all the connection state and logic code into a Service, as well as unregistering Broadcast Receivers once discovery and pairing had been completed.

MANAGING NETWORK CONNECTIVITY

The incredible growth of Internet services and the ubiquity of mobile devices have made mobile Internet access an increasingly prevalent feature on mobile phones.

With the speed, reliability, and cost of Internet connectivity dependent on the network technology being used (Wi-Fi, GPRS, 3G), letting your applications know and manage these connections can help to ensure they run efficiently and responsively.

Android broadcasts Intents that describe changes in network connectivity and offers APIs that provide control over network settings and connections.

Just as importantly, users can specify their connectivity preferences — particularly in the case of allowing background data transfers.

Android networking is principally handled via the ConnectivityManager, a Service that lets you monitor the connectivity state, set your preferred network connection, and manage connectivity failover.

Later you'll learn how to use the WifiManager to monitor and control the device's Wi-Fi connectivity specifically. The Wi-Fi Manager lets you create new Wi-Fi configurations, monitor and modify the existing Wi-Fi network settings, manage the active connection, and perform access point scans.

Was this article helpful?

+2 0
Mobile Apps Made Easy

Mobile Apps Made Easy

Quick start guide to skyrocket your offline and online business success with mobile apps. If you know anything about mobile devices, you’ve probably heard that famous phrase coined by one of the mobile device’s most prolific creators proclaiming that there’s an app for pretty much everything.

Get My Free Training Guide


Responses

  • peter
    How to use bluetooth async bluetooth read/write in android java?
    8 years ago
  • tom
    How to use bluetooth programming on android?
    6 years ago

Post a comment