Explains how to use the Android Bluetooth to use the Android Bluetooth APIs to accomplish the four major tasks necessary to communicate using Bluetooth.
Transfer File Via Bluetooth
What is the purpose of the Bluetooth?
Bluetooth is a wireless technology standard for exchanging data over short distances from fixed and mobile devices. The Android platform includes support for the Bluetooth network. The application framework provides access to the Bluetooth functionality through the Android Bluetooth APIs.These APIs let applications wirelessly connect to other Bluetooth devices.
Using the Bluetooth APIs, an Xamarin application can perform the following:
- Scan for other Bluetooth devices
- Query the local Bluetooth adapter for paired Bluetooth devices
- Establish connection
- Transfer data to and from other devices.
Bluetooth APIs is used to accomplish the four major tasks necessary to communicate using Bluetooth: setting up your Bluetooth, finding devices that are either paired or available in the local area, connecting devices, and transferring data between devices.
How do I get started with the Bluetooth in Xamarin Android?
In order to use Bluetooth features in your application, you need to declare the Bluetooth permission BLUETOOTH to perform any Bluetooth communication, such as requesting a connection, accepting a connection, and transferring data. and to initiate device discovery or manipulate Bluetooth settings, you need to declare the BLUETOOTH_ADMIN permission in addition to the BLUETOOTH permission.
Set the Bluetooth permission(s) in your Android application manifest file. For example:
<manifest ... >
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
...</manifest>
Here are the basic steps for working with a profile:-
Step 1 - Get the default adapter.
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
bluetoothAdapter = BluetoothAdapter.DefaultAdapter;
if (bluetoothAdapter == null)
{
Toast.MakeText(this, "Bluetooth is not available",ToastLength.Long).Show();
Finish();
return;
}
}
Step 2- Setting Up Bluetooth
if (!BluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Step 3 - Discovering Devices
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Setup the window
SetContentView(Resource.Layout.device_list);
// Set result CANCELED incase the user backs out
SetResult (Result.Canceled);
// Initialize the button to perform device discovery
var scanButton = FindViewById<Button>(Resource.Id.button_scan);
scanButton.Click += (sender, e) =>
{
DoDiscovery();
(sender as View).Visibility = ViewStates.Gone;
};
// Initialize array adapters. One for already paired devices and
// one for newly discovered devices
pairedDevicesArrayAdapter = new ArrayAdapter<string> (this, Resource.Layout.device_name);
newDevicesArrayAdapter = new ArrayAdapter<string> (this, Resource.Layout.device_name);
// Find and set up the ListView for paired devices
var pairedListView = FindViewById<ListView> (Resource.Id.paired_devices);
pairedListView.Adapter = pairedDevicesArrayAdapter;
pairedListView.ItemClick += DeviceListClick;
// Find and set up the ListView for newly discovered devices
var newDevicesListView = FindViewById<ListView> (Resource.Id.new_devices);
newDevicesListView.Adapter = newDevicesArrayAdapter;
newDevicesListView.ItemClick += DeviceListClick;
// Register for broadcasts when a device is discovered
receiver = new Receiver (this);
var filter = new IntentFilter (BluetoothDevice.ActionFound);
RegisterReceiver (receiver, filter);
// Register for broadcasts when discovery has finished
filter = new IntentFilter (BluetoothAdapter.ActionDiscoveryFinished);
RegisterReceiver (receiver, filter);
// Get the local Bluetooth adapter
btAdapter = BluetoothAdapter.DefaultAdapter;
// Get a set of currently paired devices
var pairedDevices = btAdapter.BondedDevices;
// If there are paired devices, add each one to the ArrayAdapter
if (pairedDevices.Count > 0) {
FindViewById<View> (Resource.Id.title_paired_devices).Visibility = ViewStates.Visible;
foreach (var device in pairedDevices) {
pairedDevicesArrayAdapter.Add (device.Name + "\n" + device.Address);
}
} else {
String noDevices = Resources.GetText (Resource.String.none_paired);
pairedDevicesArrayAdapter.Add (noDevices);
}
}
protected override void OnDestroy ()
{
base.OnDestroy ();
// Make sure we're not doing discovery anymore
if (btAdapter != null) {
btAdapter.CancelDiscovery();
}
// Unregister broadcast listeners
UnregisterReceiver(receiver);
}
/// <summary>
/// Start device discover with the BluetoothAdapter
/// </summary>
private void DoDiscovery ()
{
if (Debug)
Log.Debug (TAG, "doDiscovery()");
// Indicate scanning in the title
SetProgressBarIndeterminateVisibility (true);
SetTitle (Resource.String.scanning);
// Turn on sub-title for new devices
FindViewById<View> (Resource.Id.title_new_devices).Visibility = ViewStates.Visible;
// If we're already discovering, stop it
if (btAdapter.IsDiscovering) {
btAdapter.CancelDiscovery ();
}
// Request discover from BluetoothAdapter
btAdapter.StartDiscovery ();
}
void DeviceListClick (object sender, AdapterView.ItemClickEventArgs e)
{
// Cancel discovery because it's costly and we're about to connect
btAdapter.CancelDiscovery ();
// Get the device MAC address, which is the last 17 chars in the View
var info = (e.View as TextView).Text.ToString ();
var address = info.Substring (info.Length - 17);
// Create the result Intent and include the MAC address
Intent intent = new Intent ();
intent.PutExtra (EXTRA_DEVICE_ADDRESS, address);
// Set result and finish this Activity
SetResult (Result.Ok, intent);
Finish ();
}
public class Receiver : BroadcastReceiver
{
Activity _chat;
public Receiver (Activity chat)
{
_chat = chat;
}
public override void OnReceive (Context context, Intent intent)
{
string action = intent.Action;
// When discovery finds a device
if (action == BluetoothDevice.ActionFound) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = (BluetoothDevice)intent.GetParcelableExtra (BluetoothDevice.ExtraDevice);
// If it's already paired, skip it, because it's been listed already
if (device.BondState != Bond.Bonded) {
newDevicesArrayAdapter.Add (device.Name + "\n" + device.Address);
}
// When discovery is finished, change the Activity title
} else if (action == BluetoothAdapter.ActionDiscoveryFinished) {
_chat.SetProgressBarIndeterminateVisibility (false);
_chat.SetTitle (Resource.String.select_device);
if (newDevicesArrayAdapter.Count == 0) {
var noDevices = _chat.Resources.GetText (Resource.String.none_found).ToString ();
newDevicesArrayAdapter.Add (noDevices);
}
}
}
Step 4- Connecting as a Client
To connect two devices, one must act as a server by holding an open BluetoothServerSocket
. The purpose of the server socket is to listen for incoming connection requests and provide a connected BluetoothSocket
after a request is accepted. Once the BluetoothSocket
is acquired from the BluetoothServerSocket
, the BluetoothServerSocket
should be discarded.
protected class ConnectThread : Thread
{
private BluetoothSocket mmSocket;
private BluetoothDevice mmDevice;
private BluetoothChatService _service;
public ConnectThread(BluetoothDevice device, BluetoothChatService service)
{
mmDevice = device;
_service = service;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try
{
tmp = device.CreateRfcommSocketToServiceRecord(MY_UUID);
}
catch (Java.IO.IOException e)
{
}
mmSocket = tmp;
}
public override void Run()
{
Name = "ConnectThread";
// Always cancel discovery because it will slow down a connection
_service._adapter.CancelDiscovery();
// Make a connection to the BluetoothSocket
try
{
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.Connect();
}
catch (Java.IO.IOException e)
{
_service.ConnectionFailed();
// Close the socket
try
{
mmSocket.Close();
}
catch (Java.IO.IOException e2)
{
}
// Start the service over to restart listening mode
_service.Start();
return;
}
// Reset the ConnectThread because we're done
lock (this)
{
_service.connectThread = null;
}
// Start the connected thread
_service.Connected(mmSocket, mmDevice);
}
public void Cancel()
{
try
{
mmSocket.Close();
}
catch (Java.IO.IOException e)
{
}
}
Step 5- Connecting as a server
private class AcceptThread : Thread
{
private BluetoothServerSocket mmServerSocket;
private BluetoothChatService _service;
public AcceptThread(BluetoothChatService service)
{
_service = service;
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try
{
tmp = _service._adapter.ListenUsingRfcommWithServiceRecord(NAME, MY_UUID);
}
catch (Java.IO.IOException e)
{
Log.Error(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
public override async void Run()
{
Name = "AcceptThread";
BluetoothSocket socket = null;
// Listen to the server socket if we're not connected
while (_service._state != BluetoothChatService.STATE_CONNECTED)
{
try
{
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.Accept();
}
catch (Java.IO.IOException e)
{
break;
}
// If a connection was accepted
if (socket != null)
{
lock (this)
{
switch (_service._state)
{
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
_service.Connected(socket, socket.RemoteDevice);
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate new socket.
try
{
socket.Close();
}
catch (Java.IO.IOException e)
{
}
break;
}
}
}
}
}
public void Cancel()
{
try
{
mmServerSocket.Close();
}
catch (Java.IO.IOException e)
{
Log.Error(TAG, "close() of server failed", e);
}
}
}
Step 6 - Managing a Connection
private class ConnectedThread : Thread
{
private BluetoothSocket mmSocket;
private Stream mmInStream;
private Stream mmOutStream;
private BluetoothChatService _service;
public ConnectedThread(BluetoothSocket socket, BluetoothChatService service)
{
Log.Debug(TAG, "create ConnectedThread: ");
mmSocket = socket;
_service = service;
Stream tmpIn = null;
Stream tmpOut = null;
// Get the BluetoothSocket input and output streams
try
{
tmpIn = socket.InputStream;
tmpOut = socket.OutputStream;
}
catch (Java.IO.IOException e)
{
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
byte[] memoryBuffer ;
public override void Run()
{
int bytes;
byte[] aa;
var filePath = CreateNewImagePath();
using (var ms = new MemoryStream())
{
try
{
int i = 10;
while (i > 0)
{
bytes = mmInStream.Read(memoryBuffer, 0, memoryBuffer.Length);
ms.Write(memoryBuffer, 0, bytes);
aa = ms.ToArray();
if (i == 1)
{
Xamarin.Forms.Device.BeginInvokeOnMainThread(async () =>
{
var answer = await App.Current.MainPage.DisplayAlert("Bluetooth Transfer", "Do you wish to recieve the file", "Accept", "Reject");
if (answer)
{
System.IO.File.WriteAllBytes(filePath, aa);
Toast.MakeText(Application.Context, "File received", ToastLength.Short).Show();
}
});
}
i--;
}
}
catch
{
}
}
}
public void Write(byte[] buffer)
{
try
{
mmOutStream.Write(buffer, 0, buffer.Length);
memoryBuffer = buffer;
}
catch (Java.IO.IOException e)
{
}
}
public void Cancel()
{
try
{
mmSocket.Close();
}
catch (Java.IO.IOException e)
{
}
}
Once the necessary stream has been acquired,the thread waits for data to come through the Input Stream. This method calls write(byte[])
to send the data to the remote device.