I am facing a issue where in instead of using a thread the UI is blocked and shows blank screen. Here I am trying to connect to bluetooth scanner LPR device using my code but it somehow blocks the UI while it is connecting, which is little annoying. I tried to show toast which I thought will notify user while connecting. But no luck with that, it still shows blank screen till it connects and once its connected it shows connecting message.
public class BluetoothDeviceConnector : IDeviceConnector
{
private const string Tag = nameof(BluetoothDeviceConnector);
private const int StateNone = 0; // we're doing nothing
private const int StateConnecting = 2; // now initiating an outgoing connection
private const int StateConnected = 3; // now connected to a remote device
protected readonly BluetoothAdapter BluetoothAdapter;
private readonly IMessageHandler _handler;
private readonly string _mAddress;
private ConnectThread _mConnectThread;
private ConnectedThread _mConnectedThread;
private int _mState;
private readonly ILog _log;
///<summary>
/// Prepare a new Bluetooth session.
/// #param handler A Handler to send messages back to the UI Activity
///</summary>
public BluetoothDeviceConnector(IMessageHandler handler, string address, ILog log)
{
_log = log;
BluetoothAdapter = BluetoothAdapter.DefaultAdapter;
_mState = StateNone;
_handler = handler;
_mAddress = address;
}
/// <summary>
/// Set the current state of the connection
/// #param state An integer defining the current connection state
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
private void SetState(int state)
{
_log.Info(Tag + " setState() " + _mState + " -> " + state);
_mState = state;
}
private BluetoothAdapter GetBluetoothAdapter()
{
return BluetoothAdapter.DefaultAdapter;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void Connect()
{
var device = GetBluetoothAdapter().GetRemoteDevice(_mAddress);
Connect(device);
}
///<summary>
/// Start the ConnectThread to initiate a connection to a remote device.
/// #param device The BluetoothDevice to connect
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Connect(BluetoothDevice device)
{
_log.Info(Tag + " connecting to: " + device);
// Cancel any thread attempting to make a connection
if (_mState == StateConnecting)
{
if (_mConnectThread != null)
{
_mConnectThread.Cancel();
_mConnectThread = null;
}
}
// Cancel any thread currently running a connection
if (_mConnectedThread != null)
{
_mConnectedThread.Cancel();
_mConnectedThread = null;
}
// Start the thread to connect with the given device
try
{
_mConnectThread = new ConnectThread(device, this);
_mConnectThread.Start();
SetState(StateConnecting);
_handler.SendConnectingTo(device.Name);
}
catch (SecurityException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (IllegalArgumentException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (NoSuchMethodException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (IllegalAccessException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (InvocationTargetException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (Exception e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
}
///<summary>
/// Start the ConnectedThread to begin managing a Bluetooth connection
/// #param socket The BluetoothSocket on which the connection was made
/// #param device The BluetoothDevice that has been connected
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Connected(BluetoothSocket socket, BluetoothDevice device)
{
_log.Info(Tag + " connected");
// Cancel the thread that completed the connection
if (_mConnectThread != null)
{
_mConnectThread.Cancel();
_mConnectThread = null;
}
// Cancel any thread currently running a connection
if (_mConnectedThread != null)
{
_mConnectedThread.Cancel();
_mConnectedThread = null;
}
// Start the thread to manage the connection and perform transmissions
_mConnectedThread = new ConnectedThread(socket, this);
_mConnectedThread.Start();
SetState(StateConnected);
_handler.SendConnectedTo(device.Name);
}
///<summary>
/// Stop all threads
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Disconnect()
{
_log.Info(Tag + " Disconnect");
if (_mConnectThread != null)
{
_mConnectThread.Cancel();
_mConnectThread = null;
}
if (_mConnectedThread != null)
{
_mConnectedThread.Shutdown();
_mConnectedThread.Cancel();
_mConnectedThread = null;
}
SetState(StateNone);
_handler.SendNotConnected();
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SendAsciiMessage(string chars)
{
//Write((chars + "\n").GetBytes());
}
///<summary>
/// Write to the ConnectedThread in an unsynchronized manner
/// #param out The bytes to write
/// #see ConnectedThread#Write(byte[])
/// </summary>
private void Write(byte[] value)
{
// Create temporary object
// Synchronize a copy of the ConnectedThread
if (_mState != StateConnected) return;
// Perform the write unsynchronized
Task.Run(() =>
{
_mConnectedThread.Write(value);
});
}
///<summary>
/// Indicate that the connection attempt failed and notify the UI Activity.
/// </summary>
private void ConnectionFailed()
{
SetState(StateNone);
_handler.SendConnectionFailed();
_log.Info(Tag + " ConnectionFailed");
}
///<summary>
/// Indicate that the connection was lost and notify the UI Activity.
/// </summary>
private void ConnectionLost()
{
SetState(StateNone);
_handler.SendConnectionLost();
_log.Info(Tag + " ConnectionLost");
}
/// <summary>
/// This thread runs while attempting to make an outgoing connection
/// with a device. It runs straight through; the connection either
/// succeeds or fails.
/// SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
/// </summary>
private class ConnectThread : Thread
{
private readonly BluetoothSocket _mmSocket;
private readonly BluetoothDevice _mmDevice;
private readonly BluetoothDeviceConnector _deviceConnector;
//public ISharedPreferences prefs = Application.Context.GetSharedPreferences("Aglive_SharedPreferences", FileCreationMode.Private);
public ConnectThread(BluetoothDevice device, BluetoothDeviceConnector deviceConnector)
{
_mmDevice = device;
BluetoothSocket tmp = null;
_deviceConnector = deviceConnector;
if (DeviceListActivity.deviceActivity != null)
{
Toast.MakeText(DeviceListActivity.deviceActivity, AgliveResource.Connecting + "...", ToastLength.Long).Show();
}
_deviceConnector._log.Info(Tag + " calling device.createRfcommSocket with channel 1 ...");
try
{
//tmp = device.CreateRfcommSocketToServiceRecord(UUID.FromString("00001101-0000-1000-8000-00805F9B34FB"));
//tmp = device.CreateRfcommSocketToServiceRecord(device.GetUuids()[0].Uuid);
deviceConnector.BluetoothAdapter.CancelDiscovery();
var createRfcommSocket = JNIEnv.GetMethodID(device.Class.Handle, "createInsecureRfcommSocket", "(I)Landroid/bluetooth/BluetoothSocket;");
var socket = JNIEnv.CallObjectMethod(device.Handle, createRfcommSocket, new JValue(1));
tmp = GetObject<BluetoothSocket>(socket, JniHandleOwnership.TransferLocalRef);
_deviceConnector._log.Info(Tag + " calling device.createRfcommSocket with channel 2 ...");
var uuidList = device.GetUuids();
if (uuidList != null)
{
int count = 0;
while(count < 10)//true)//10 attempts
//foreach (var uuid in uuidList)
{
try
{
//_deviceConnector._log.Info(Tag + " connect with uuid: " + uuid);
//tmp = device.CreateInsecureRfcommSocketToServiceRecord(uuid.Uuid);
// tmp = (BluetoothSocket)device.Class.GetMethod("createRfcommSocket", new Class[] { }).Invoke(device,1);
//if (BluetoothDevice.DeviceTypeLe == device.GetType())
//{.
if ((int)Build.VERSION.SdkInt >= 10)
{
try
{
Method m = device.Class.GetMethod("createRfcommSocket", new Class[] { Integer.Type });
tmp = (BluetoothSocket)m.Invoke(device, 1);
}
catch (Exception e)
{
//Log.e(TAG, "Could not create Insecure RFComm Connection",e);
}
}
if (isconnected.isConnected != true)
{
tmp.Connect();
isconnected.isConnected = true;
}
else
{
break;
}
//}
_deviceConnector._log.Info(Tag + " connect with uuid status: " + tmp.IsConnected);
if (tmp.IsConnected)
{
//_deviceConnector._log.Info(Tag + " uuid success " + uuid);
break;
}
//ISharedPreferencesEditor editor = prefs.Edit();
//editor.PutBoolean("isConnected", tmp.IsConnected);
//editor.Apply();
}
catch (Exception e)
{
// ignored
}
count++;
}
}
_deviceConnector._log.Info(Tag + " setting socket to result of createRfcommSocket");
_deviceConnector._log.Info(Tag + " setting socket Status" + tmp.IsConnected);
}
catch (Exception e)
{
_deviceConnector._log.Error(Tag + " ConnectThread", e);
}
_mmSocket = tmp;
}
public override void Run()
{
base.Run();
_deviceConnector._log.Info(Tag + " BEGIN mConnectThread");
//setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
_deviceConnector.BluetoothAdapter.CancelDiscovery();
// Make a connection to the BluetoothSocket
try
{
// This is a blocking call and will only return on a
// successful connection or an exception
_deviceConnector._log.Info(Tag + " Run() => " + _mmSocket.IsConnected);
if (!_deviceConnector.BluetoothAdapter.IsDiscovering && !_mmSocket.IsConnected)
{
_deviceConnector._log.Info(Tag + " BEGIN mConnectThread 1");
_mmSocket.Connect();
_deviceConnector._log.Info(Tag + " BEGIN mConnectThread 2");
}
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " ConnectThread => Run Function", e);
_deviceConnector.ConnectionFailed();
try
{
_mmSocket.Close();
}
catch (IOException e2)
{
_deviceConnector._log.Error(Tag + " unable to close() socket during connection failure", e2);
}
return;
}
// Reset the ConnectThread because we're done
_deviceConnector._mConnectThread = null;
// Start the connected thread
_deviceConnector.Connected(_mmSocket, _mmDevice);
_deviceConnector._log.Info(Tag + " END mConnectThread");
}
[Obsolete("deprecated")]
public override void Destroy()
{
try
{
_deviceConnector._log.Info(Tag + " Destory()");
_mmSocket?.Close();
_deviceConnector._log.Info(Tag + " Destroy");
base.Destroy();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of connect socket failed", e);
}
}
public void Cancel()
{
try
{
_deviceConnector._log.Info(Tag + " Cancel()");
_mmSocket?.Close();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of connect socket failed", e);
}
}
}
///<summary>
/// This thread runs during a connection with a remote device.
/// It handles all incoming and outgoing transmissions.
/// </summary>
private class ConnectedThread : Thread
{
private readonly BluetoothSocket _mmSocket;
private readonly Stream _mmInStream;
private readonly Stream _mmOutStream;
private readonly BluetoothDeviceConnector _deviceConnector;
public ConnectedThread(BluetoothSocket socket, BluetoothDeviceConnector deviceConnector)
{
_deviceConnector = deviceConnector;
_mmSocket = socket;
_deviceConnector._log.Info(Tag + " create ConnectedThread");
// Get the BluetoothSocket input and output streams
try
{
_mmInStream = _mmSocket?.InputStream;
_mmOutStream = _mmSocket?.OutputStream;
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " temp sockets not created", e);
}
}
private bool _stop;
private readonly bool _hasReadAnything = false;
public void Shutdown()
{
_stop = true;
if (!_hasReadAnything) return;
try
{
_deviceConnector._log.Info(Tag + " Shutdown ConnectedThread");
_mmInStream?.Close();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of InputStream failed.", e);
}
}
public override void Run()
{
base.Run();
_deviceConnector._log.Info(Tag + " BEGIN mConnectedThread");
var reader = new Java.IO.BufferedReader(new Java.IO.InputStreamReader(_mmInStream));
while (!_stop)
{
try
{
var rfid = reader.ReadLine();
if (!string.IsNullOrEmpty(rfid?.Trim()))
{
_deviceConnector._handler.SendLineRead(rfid);
}
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " disconnected", e);
_deviceConnector.ConnectionLost();
break;
}
}
}
///<summary>
/// Write to the connected OutStream.
/// #param bytes The bytes to write
/// </summary>
public void Write(byte[] bytes)
{
try
{
_mmOutStream.Write(bytes, 0, bytes.Length);
_deviceConnector._handler.SendBytesWritten(bytes);
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " Exception during write", e);
}
}
public void Cancel()
{
try
{
_deviceConnector._log.Error(Tag + " ConnectedThread() => Cancel()");
_mmInStream.Close();
_mmOutStream.Close();
_mmSocket?.Close();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of connect socket failed", e);
}
}
}
}
public static class isconnected
{
public static bool isConnected { get; set; }
}
Activity from where I am trying to connect to scanner:
public class MenuActivity : BaseActivity
{
Button _dashboard_menuItem, _sync_menuItem, _scan_menuItem, _activity_menuItem, _settings_menuItem, _contact_menuItem, _signout_menuItem;
Switch _connectScannerSwitch;
public IRFIDReader RFIDReader =Dependencies.Container.Get<IRFIDReader>();
private bool isCalled=false;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_menu);
InitializeComponant();
InitializeEvents();
_connectScannerSwitch.Checked = isconnected.isConnected;
_scan_menuItem.Text = isconnected.isConnected ? AgliveResource.DisconnectScanner : AgliveResource.ConnectScanner;
}
private void InitializeEvents()
{
_connectScannerSwitch.CheckedChange += _connectScannerSwitch_Click;
_connectScannerSwitch.Click += _connectScannerSwitch_Click;
}
private void _connectScannerSwitch_Click(object sender, EventArgs e)
{
if (!_connectScannerSwitch.Checked)
{
if (!isconnected.isConnected)
{
_scan_menuItem.Text = "Connecting";
}
}
ConnectDisconnectWand();
}
public void SetWandConnectValue(bool value)
{
_connectScannerSwitch.Checked = value;
ConnectDisconnectWand();
}
private void ConnectDisconnectWand()
{
if (string.IsNullOrEmpty(prefs.GetString("BluetoothDeviceName", null)))
{
if (isCalled == false)
{
_connectScannerSwitch.Checked = false;
var intent = new Intent(this, typeof(DeviceListActivity));
StartActivityForResult(intent, RequestCode.RequestConnectDevice);
isCalled = true;
}
return;
}
TokenExpiredSubscriptionToken = TinyMessenger.Subscribe<RFIDReaderStateChangedEvent>(StateChangedEvent);
if (_connectScannerSwitch.Checked)
{
if (!isconnected.isConnected)
{
_scan_menuItem.Text = AgliveResource.Connecting;
RFIDReader.ConnectDevice();
}
}
else if (RFIDReader.IsConnected)
{
RFIDReader.DisConnectDevice();
}
}
private void InitializeComponant()
{
prefs = Application.Context.GetSharedPreferences("SharedPreferences", FileCreationMode.Private);
_scan_menuItem = FindViewById<Button>(Resource.Id.ScanMenuItem);
_connectScannerSwitch=FindViewById<Switch>(Resource.Id.connectScannerSwitch);
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
// case Android.Resource.Id.Home:
case Resource.Id.back:
OnBackPressed();
return true;
case Resource.Id.menuIcon:
{
StartActivity(typeof(MenuActivity));
return true;
}
default:
return base.OnOptionsItemSelected(item);
}
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
isCalled = false;
_scan_menuItem.Text = _connectScannerSwitch.Checked ? AgliveResource.DisconnectScanner : AgliveResource.ConnectScanner;//"Disconnect RFID Scanner" : "Connect to Scanner";
if (resultCode != Result.Ok)
return;
switch (requestCode)
{
case RequestCode.RequestConnectDevice:
isCalled = false;
//_connectScannerSwitch.Checked = true;
//_scan_menuItem.Text = "connected";
if (!string.IsNullOrEmpty(prefs.GetString("BluetoothDeviceName", null)))
{
Toast.MakeText(this, AgliveResource.Connecting + "...", ToastLength.Long).Show();
SetWandConnectValue(true);
}
break;
}
}
private void StateChangedEvent(RFIDReaderStateChangedEvent rfidReaderStateChangedEvent)
{
if (_connectScannerSwitch.Checked && !RFIDReader.IsConnected)
{
if (!string.IsNullOrEmpty(RFIDReader.ErrorMessage))
{
Toast.MakeText(this, RFIDReader.ErrorMessage, ToastLength.Long).Show();
isCalled = false;
}
TinyMessenger.Unsubscribe<RFIDReaderStateChangedEvent>(TokenExpiredSubscriptionToken);
isconnected.isConnected = false;
}
SetWandConnectionLabel();
}
private void SetWandConnectionLabel()
{
_connectScannerSwitch.Checked = RFIDReader.IsConnected;
_scan_menuItem.Text = _connectScannerSwitch.Checked ? AgliveResource.DisconnectScanner : AgliveResource.ConnectScanner;
}
}
I am facing a issue where in instead of using a thread the UI is blocked and shows blank screen.
I think the reason is that you connect the Bluetooth in the UI thread.
Android is using single thread model.You should never perform long operations in the UI thread. They will block the UI. If the UI thread is blocked for more than 5 seconds, the ANR dialog will be shown. You could refer to this official documentation : Threads.
I found the issue, It was because I was trying to connect to Bluetooth from connectThread. Removing the connecting line did the magic, here is the working code:
public class BluetoothDeviceConnector : IDeviceConnector
{
private const string Tag = nameof(BluetoothDeviceConnector);
private const int StateNone = 0; // we're doing nothing
private const int StateConnecting = 2; // now initiating an outgoing connection
private const int StateConnected = 3; // now connected to a remote device
protected readonly BluetoothAdapter BluetoothAdapter;
private readonly IMessageHandler _handler;
private readonly string _mAddress;
private ConnectThread _mConnectThread;
private ConnectedThread _mConnectedThread;
private int _mState;
private readonly ILog _log;
///<summary>
/// Prepare a new Bluetooth session.
/// #param handler A Handler to send messages back to the UI Activity
///</summary>
public BluetoothDeviceConnector(IMessageHandler handler, string address, ILog log)
{
_log = log;
BluetoothAdapter = BluetoothAdapter.DefaultAdapter;
_mState = StateNone;
_handler = handler;
_mAddress = address;
}
/// <summary>
/// Set the current state of the connection
/// #param state An integer defining the current connection state
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
private void SetState(int state)
{
_log.Info(Tag + " setState() " + _mState + " -> " + state);
_mState = state;
}
private BluetoothAdapter GetBluetoothAdapter()
{
return BluetoothAdapter.DefaultAdapter;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void Connect()
{
var device = GetBluetoothAdapter().GetRemoteDevice(_mAddress);
Connect(device);
}
///<summary>
/// Start the ConnectThread to initiate a connection to a remote device.
/// #param device The BluetoothDevice to connect
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Connect(BluetoothDevice device)
{
_log.Info(Tag + " connecting to: " + device);
// Cancel any thread attempting to make a connection
if (_mState == StateConnecting)
{
if (_mConnectThread != null)
{
_mConnectThread.Cancel();
_mConnectThread = null;
}
}
// Cancel any thread currently running a connection
if (_mConnectedThread != null)
{
_mConnectedThread.Cancel();
_mConnectedThread = null;
}
// Start the thread to connect with the given device
try
{
_mConnectThread = new ConnectThread(device, this);
_mConnectThread.Start();
SetState(StateConnecting);
_handler.SendConnectingTo(device.Name);
}
catch (SecurityException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (IllegalArgumentException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (NoSuchMethodException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (IllegalAccessException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (InvocationTargetException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (Exception e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
}
///<summary>
/// Start the ConnectedThread to begin managing a Bluetooth connection
/// #param socket The BluetoothSocket on which the connection was made
/// #param device The BluetoothDevice that has been connected
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Connected(BluetoothSocket socket, BluetoothDevice device)
{
_log.Info(Tag + " connected");
// Cancel the thread that completed the connection
if (_mConnectThread != null)
{
_mConnectThread.Cancel();
_mConnectThread = null;
}
// Cancel any thread currently running a connection
if (_mConnectedThread != null)
{
_mConnectedThread.Cancel();
_mConnectedThread = null;
}
// Start the thread to manage the connection and perform transmissions
_mConnectedThread = new ConnectedThread(socket, this);
_mConnectedThread.Start();
SetState(StateConnected);
_handler.SendConnectedTo(device.Name);
}
///<summary>
/// Stop all threads
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Disconnect()
{
_log.Info(Tag + " Disconnect");
if (_mConnectThread != null)
{
_mConnectThread.Cancel();
_mConnectThread = null;
}
if (_mConnectedThread != null)
{
_mConnectedThread.Shutdown();
_mConnectedThread.Cancel();
_mConnectedThread = null;
}
SetState(StateNone);
_handler.SendNotConnected();
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SendAsciiMessage(string chars)
{
//Write((chars + "\n").GetBytes());
}
///<summary>
/// Write to the ConnectedThread in an unsynchronized manner
/// #param out The bytes to write
/// #see ConnectedThread#Write(byte[])
/// </summary>
private void Write(byte[] value)
{
// Create temporary object
// Synchronize a copy of the ConnectedThread
if (_mState != StateConnected) return;
// Perform the write unsynchronized
Task.Run(() =>
{
_mConnectedThread.Write(value);
});
}
///<summary>
/// Indicate that the connection attempt failed and notify the UI Activity.
/// </summary>
private void ConnectionFailed()
{
SetState(StateNone);
_handler.SendConnectionFailed();
_log.Info(Tag + " ConnectionFailed");
}
///<summary>
/// Indicate that the connection was lost and notify the UI Activity.
/// </summary>
private void ConnectionLost()
{
SetState(StateNone);
_handler.SendConnectionLost();
_log.Info(Tag + " ConnectionLost");
}
/// <summary>
/// This thread runs while attempting to make an outgoing connection
/// with a device. It runs straight through; the connection either
/// succeeds or fails.
/// SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
/// </summary>
private class ConnectThread : Thread
{
private readonly BluetoothSocket _mmSocket;
private readonly BluetoothDevice _mmDevice;
private readonly BluetoothDeviceConnector _deviceConnector;
//public ISharedPreferences prefs = Application.Context.GetSharedPreferences("Aglive_SharedPreferences", FileCreationMode.Private);
public ConnectThread(BluetoothDevice device, BluetoothDeviceConnector deviceConnector)
{
_mmDevice = device;
BluetoothSocket tmp = null;
_deviceConnector = deviceConnector;
_deviceConnector._log.Info(Tag + " calling device.createRfcommSocket with channel 1 ...");
try
{
//tmp = device.CreateRfcommSocketToServiceRecord(UUID.FromString("00001101-0000-1000-8000-00805F9B34FB"));
//tmp = device.CreateRfcommSocketToServiceRecord(device.GetUuids()[0].Uuid);
deviceConnector.BluetoothAdapter.CancelDiscovery();
var createRfcommSocket = JNIEnv.GetMethodID(device.Class.Handle, "createInsecureRfcommSocket", "(I)Landroid/bluetooth/BluetoothSocket;");
var socket = JNIEnv.CallObjectMethod(device.Handle, createRfcommSocket, new JValue(1));
tmp = GetObject<BluetoothSocket>(socket, JniHandleOwnership.TransferLocalRef);
_deviceConnector._log.Info(Tag + " calling device.createRfcommSocket with channel 2 ...");
var uuidList = device.GetUuids();
if (uuidList != null)
{
int count = 0;
while(count < 10)//true)//10 attempts
//foreach (var uuid in uuidList)
{
try
{
//_deviceConnector._log.Info(Tag + " connect with uuid: " + uuid);
//tmp = device.CreateInsecureRfcommSocketToServiceRecord(uuid.Uuid);
// tmp = (BluetoothSocket)device.Class.GetMethod("createRfcommSocket", new Class[] { }).Invoke(device,1);
//if (BluetoothDevice.DeviceTypeLe == device.GetType())
//{.
if ((int)Build.VERSION.SdkInt >= 10)
{
try
{
Method m = device.Class.GetMethod("createRfcommSocket", new Class[] { Integer.Type });
tmp = (BluetoothSocket)m.Invoke(device, 1);
}
catch (Exception e)
{
//Log.e(TAG, "Could not create Insecure RFComm Connection",e);
}
}
if (isconnected.isConnected != true)
{
tmp.Connect();
isconnected.isConnected = true;
}
else
{
break;
}
//}
_deviceConnector._log.Info(Tag + " connect with uuid status: " + tmp.IsConnected);
if (tmp.IsConnected)
{
//_deviceConnector._log.Info(Tag + " uuid success " + uuid);
break;
}
//ISharedPreferencesEditor editor = prefs.Edit();
//editor.PutBoolean("isConnected", tmp.IsConnected);
//editor.Apply();
}
catch (Exception e)
{
// ignored
}
count++;
}
}
_deviceConnector._log.Info(Tag + " setting socket to result of createRfcommSocket");
_deviceConnector._log.Info(Tag + " setting socket Status" + tmp.IsConnected);
}
catch (Exception e)
{
_deviceConnector._log.Error(Tag + " ConnectThread", e);
}
_mmSocket = tmp;
}
public override void Run()
{
base.Run();
_deviceConnector._log.Info(Tag + " BEGIN mConnectThread");
//setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
_deviceConnector.BluetoothAdapter.CancelDiscovery();
// Make a connection to the BluetoothSocket
try
{
// This is a blocking call and will only return on a
// successful connection or an exception
_deviceConnector._log.Info(Tag + " Run() => " + _mmSocket.IsConnected);
if (!_deviceConnector.BluetoothAdapter.IsDiscovering && !_mmSocket.IsConnected)
{
_deviceConnector._log.Info(Tag + " BEGIN mConnectThread 1");
_mmSocket.Connect();
_deviceConnector._log.Info(Tag + " BEGIN mConnectThread 2");
}
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " ConnectThread => Run Function", e);
_deviceConnector.ConnectionFailed();
try
{
_mmSocket.Close();
}
catch (IOException e2)
{
_deviceConnector._log.Error(Tag + " unable to close() socket during connection failure", e2);
}
return;
}
// Reset the ConnectThread because we're done
_deviceConnector._mConnectThread = null;
// Start the connected thread
_deviceConnector.Connected(_mmSocket, _mmDevice);
_deviceConnector._log.Info(Tag + " END mConnectThread");
}
[Obsolete("deprecated")]
public override void Destroy()
{
try
{
_deviceConnector._log.Info(Tag + " Destory()");
_mmSocket?.Close();
_deviceConnector._log.Info(Tag + " Destroy");
base.Destroy();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of connect socket failed", e);
}
}
public void Cancel()
{
try
{
_deviceConnector._log.Info(Tag + " Cancel()");
_mmSocket?.Close();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of connect socket failed", e);
}
}
}
///<summary>
/// This thread runs during a connection with a remote device.
/// It handles all incoming and outgoing transmissions.
/// </summary>
private class ConnectedThread : Thread
{
private readonly BluetoothSocket _mmSocket;
private readonly Stream _mmInStream;
private readonly Stream _mmOutStream;
private readonly BluetoothDeviceConnector _deviceConnector;
public ConnectedThread(BluetoothSocket socket, BluetoothDeviceConnector deviceConnector)
{
_deviceConnector = deviceConnector;
_mmSocket = socket;
_deviceConnector._log.Info(Tag + " create ConnectedThread");
// Get the BluetoothSocket input and output streams
try
{
_mmInStream = _mmSocket?.InputStream;
_mmOutStream = _mmSocket?.OutputStream;
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " temp sockets not created", e);
}
}
private bool _stop;
private readonly bool _hasReadAnything = false;
public void Shutdown()
{
_stop = true;
if (!_hasReadAnything) return;
try
{
_deviceConnector._log.Info(Tag + " Shutdown ConnectedThread");
_mmInStream?.Close();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of InputStream failed.", e);
}
}
public override void Run()
{
base.Run();
_deviceConnector._log.Info(Tag + " BEGIN mConnectedThread");
var reader = new Java.IO.BufferedReader(new Java.IO.InputStreamReader(_mmInStream));
while (!_stop)
{
try
{
var rfid = reader.ReadLine();
if (!string.IsNullOrEmpty(rfid?.Trim()))
{
_deviceConnector._handler.SendLineRead(rfid);
}
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " disconnected", e);
_deviceConnector.ConnectionLost();
break;
}
}
}
///<summary>
/// Write to the connected OutStream.
/// #param bytes The bytes to write
/// </summary>
public void Write(byte[] bytes)
{
try
{
_mmOutStream.Write(bytes, 0, bytes.Length);
_deviceConnector._handler.SendBytesWritten(bytes);
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " Exception during write", e);
}
}
public void Cancel()
{
try
{
_deviceConnector._log.Error(Tag + " ConnectedThread() => Cancel()");
_mmInStream.Close();
_mmOutStream.Close();
_mmSocket?.Close();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of connect socket failed", e);
}
}
}
}
public static class isconnected
{
public static bool isConnected { get; set; }
}
Related
I have a requirement of connecting to a bluetooth scanner from my android application. After it is connected the scanned RFID's will be added to local database.
The problem here is that the bluetooth scanner does not connect at times not sure when it fails to connect as there is no definite pattern to fail.
And at times it connects but does not read any RFID's. cannot figure out whay it fails. I only get one exception message
"read failed, socket might closed or timeout, read ret: -1"
Here is the code of BluetoothDeviceConnector:
public class BluetoothDeviceConnector : IDeviceConnector
{
private const string Tag = nameof(BluetoothDeviceConnector);
private const int StateNone = 0; // we're doing nothing
private const int StateConnecting = 2; // now initiating an outgoing connection
private const int StateConnected = 3; // now connected to a remote device
protected readonly BluetoothAdapter BluetoothAdapter;
private readonly IMessageHandler _handler;
private readonly string _mAddress;
private ConnectThread _mConnectThread;
private ConnectedThread _mConnectedThread;
private int _mState;
private readonly ILog _log;
///<summary>
/// Prepare a new Bluetooth session.
/// #param handler A Handler to send messages back to the UI Activity
///</summary>
public BluetoothDeviceConnector(IMessageHandler handler, string address, ILog log)
{
_log = log;
BluetoothAdapter = BluetoothAdapter.DefaultAdapter;
_mState = StateNone;
_handler = handler;
_mAddress = address;
}
/// <summary>
/// Set the current state of the connection
/// #param state An integer defining the current connection state
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
private void SetState(int state)
{
_log.Info(Tag + " setState() " + _mState + " -> " + state);
_mState = state;
}
private BluetoothAdapter GetBluetoothAdapter()
{
return BluetoothAdapter.DefaultAdapter;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void Connect()
{
var device = GetBluetoothAdapter().GetRemoteDevice(_mAddress);
Connect(device);
}
///<summary>
/// Start the ConnectThread to initiate a connection to a remote device.
/// #param device The BluetoothDevice to connect
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Connect(BluetoothDevice device)
{
_log.Info(Tag + " connecting to: " + device);
// Cancel any thread attempting to make a connection
if (_mState == StateConnecting)
{
if (_mConnectThread != null)
{
_mConnectThread.Cancel();
_mConnectThread = null;
}
}
// Cancel any thread currently running a connection
if (_mConnectedThread != null)
{
_mConnectedThread.Cancel();
_mConnectedThread = null;
}
// Start the thread to connect with the given device
try
{
_mConnectThread = new ConnectThread(device, this);
_mConnectThread.Start();
SetState(StateConnecting);
_handler.SendConnectingTo(device.Name);
}
catch (SecurityException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (IllegalArgumentException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (NoSuchMethodException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (IllegalAccessException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (InvocationTargetException e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
catch (Exception e)
{
_log.Error(Tag + " Connect(BluetoothDevice device) :", e);
}
}
///<summary>
/// Start the ConnectedThread to begin managing a Bluetooth connection
/// #param socket The BluetoothSocket on which the connection was made
/// #param device The BluetoothDevice that has been connected
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Connected(BluetoothSocket socket, BluetoothDevice device)
{
_log.Info(Tag + " connected");
// Cancel the thread that completed the connection
if (_mConnectThread != null)
{
_mConnectThread.Cancel();
_mConnectThread = null;
}
// Cancel any thread currently running a connection
if (_mConnectedThread != null)
{
_mConnectedThread.Cancel();
_mConnectedThread = null;
}
// Start the thread to manage the connection and perform transmissions
_mConnectedThread = new ConnectedThread(socket, this);
_mConnectedThread.Start();
SetState(StateConnected);
_handler.SendConnectedTo(device.Name);
}
///<summary>
/// Stop all threads
/// </summary>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Disconnect()
{
_log.Info(Tag + " Disconnect");
if (_mConnectThread != null)
{
_mConnectThread.Cancel();
_mConnectThread = null;
}
if (_mConnectedThread != null)
{
_mConnectedThread.Shutdown();
_mConnectedThread.Cancel();
_mConnectedThread = null;
}
SetState(StateNone);
_handler.SendNotConnected();
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SendAsciiMessage(string chars)
{
//Write((chars + "\n").GetBytes());
}
///<summary>
/// Write to the ConnectedThread in an unsynchronized manner
/// #param out The bytes to write
/// #see ConnectedThread#Write(byte[])
/// </summary>
private void Write(byte[] value)
{
// Create temporary object
// Synchronize a copy of the ConnectedThread
if (_mState != StateConnected) return;
// Perform the write unsynchronized
Task.Run(() =>
{
_mConnectedThread.Write(value);
});
}
///<summary>
/// Indicate that the connection attempt failed and notify the UI Activity.
/// </summary>
private void ConnectionFailed()
{
SetState(StateNone);
_handler.SendConnectionFailed();
_log.Info(Tag + " ConnectionFailed");
}
///<summary>
/// Indicate that the connection was lost and notify the UI Activity.
/// </summary>
private void ConnectionLost()
{
SetState(StateNone);
_handler.SendConnectionLost();
_log.Info(Tag + " ConnectionLost");
}
/// <summary>
/// This thread runs while attempting to make an outgoing connection
/// with a device. It runs straight through; the connection either
/// succeeds or fails.
/// SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
/// </summary>
private class ConnectThread : Thread
{
private readonly BluetoothSocket _mmSocket;
private readonly BluetoothDevice _mmDevice;
private readonly BluetoothDeviceConnector _deviceConnector;
public ConnectThread(BluetoothDevice device, BluetoothDeviceConnector deviceConnector)
{
_mmDevice = device;
BluetoothSocket tmp = null;
_deviceConnector = deviceConnector;
_deviceConnector._log.Info(Tag + " calling device.createRfcommSocket with channel 1 ...");
try
{
//tmp = device.CreateRfcommSocketToServiceRecord(UUID.FromString("00001101-0000-1000-8000-00805F9B34FB"));
//tmp = device.CreateRfcommSocketToServiceRecord(device.GetUuids()[0].Uuid);
deviceConnector.BluetoothAdapter.CancelDiscovery();
var createRfcommSocket = JNIEnv.GetMethodID(device.Class.Handle, "createInsecureRfcommSocket", "(I)Landroid/bluetooth/BluetoothSocket;");
var socket = JNIEnv.CallObjectMethod(device.Handle, createRfcommSocket, new JValue(1));
tmp = GetObject<BluetoothSocket>(socket, JniHandleOwnership.TransferLocalRef);
_deviceConnector._log.Info(Tag + " calling device.createRfcommSocket with channel 2 ...");
var uuidList = device.GetUuids();
if (uuidList != null)
{
foreach (var uuid in uuidList)
{
try
{
_deviceConnector._log.Info(Tag + " connect with uuid: " + uuid);
tmp = device.CreateInsecureRfcommSocketToServiceRecord(uuid.Uuid);
tmp.Connect();
_deviceConnector._log.Info(Tag + " connect with uuid status: " + tmp.IsConnected);
if (tmp.IsConnected)
{
_deviceConnector._log.Info(Tag + " uuid success " + uuid);
break;
}
}
catch (Exception ex)
{
// ignored
}
}
}
_deviceConnector._log.Info(Tag + " setting socket to result of createRfcommSocket");
_deviceConnector._log.Info(Tag + " setting socket Status" + tmp.IsConnected);
}
catch (Exception e)
{
_deviceConnector._log.Error(Tag + " ConnectThread", e);
}
_mmSocket = tmp;
}
public override void Run()
{
base.Run();
_deviceConnector._log.Info(Tag + " BEGIN mConnectThread");
//setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
_deviceConnector.BluetoothAdapter.CancelDiscovery();
// Make a connection to the BluetoothSocket
try
{
// This is a blocking call and will only return on a
// successful connection or an exception
_deviceConnector._log.Info(Tag + " Run() => " + _mmSocket.IsConnected);
if (!_deviceConnector.BluetoothAdapter.IsDiscovering && !_mmSocket.IsConnected)
{
_deviceConnector._log.Info(Tag + " BEGIN mConnectThread 1");
_mmSocket.Connect();
_deviceConnector._log.Info(Tag + " BEGIN mConnectThread 2");
}
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " ConnectThread => Run Function", e);
_deviceConnector.ConnectionFailed();
try
{
_mmSocket.Close();
}
catch (IOException e2)
{
_deviceConnector._log.Error(Tag + " unable to close() socket during connection failure", e2);
}
return;
}
// Reset the ConnectThread because we're done
_deviceConnector._mConnectThread = null;
// Start the connected thread
_deviceConnector.Connected(_mmSocket, _mmDevice);
_deviceConnector._log.Info(Tag + " END mConnectThread");
}
[Obsolete("deprecated")]
public override void Destroy()
{
try
{
_deviceConnector._log.Info(Tag + " Destory()");
_mmSocket?.Close();
_deviceConnector._log.Info(Tag + " Destroy");
base.Destroy();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of connect socket failed", e);
}
}
public void Cancel()
{
try
{
_deviceConnector._log.Info(Tag + " Cancel()");
_mmSocket?.Close();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of connect socket failed", e);
}
}
}
///<summary>
/// This thread runs during a connection with a remote device.
/// It handles all incoming and outgoing transmissions.
/// </summary>
private class ConnectedThread : Thread
{
private readonly BluetoothSocket _mmSocket;
private readonly Stream _mmInStream;
private readonly Stream _mmOutStream;
private readonly BluetoothDeviceConnector _deviceConnector;
public ConnectedThread(BluetoothSocket socket, BluetoothDeviceConnector deviceConnector)
{
_deviceConnector = deviceConnector;
_mmSocket = socket;
_deviceConnector._log.Info(Tag + " create ConnectedThread");
// Get the BluetoothSocket input and output streams
try
{
_mmInStream = _mmSocket?.InputStream;
_mmOutStream = _mmSocket?.OutputStream;
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " temp sockets not created", e);
}
}
private bool _stop;
private readonly bool _hasReadAnything = false;
public void Shutdown()
{
_stop = true;
if (!_hasReadAnything) return;
try
{
_deviceConnector._log.Info(Tag + " Shutdown ConnectedThread");
_mmInStream?.Close();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of InputStream failed.", e);
}
}
public override void Run()
{
base.Run();
_deviceConnector._log.Info(Tag + " BEGIN mConnectedThread");
var reader = new Java.IO.BufferedReader(new Java.IO.InputStreamReader(_mmInStream));
while (!_stop)
{
try
{
var rfid = reader.ReadLine();
if (!string.IsNullOrEmpty(rfid?.Trim()))
{
_deviceConnector._handler.SendLineRead(rfid);
}
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " disconnected", e);
_deviceConnector.ConnectionLost();
break;
}
}
}
///<summary>
/// Write to the connected OutStream.
/// #param bytes The bytes to write
/// </summary>
public void Write(byte[] bytes)
{
try
{
_mmOutStream.Write(bytes, 0, bytes.Length);
_deviceConnector._handler.SendBytesWritten(bytes);
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " Exception during write", e);
}
}
public void Cancel()
{
try
{
_deviceConnector._log.Error(Tag + " ConnectedThread() => Cancel()");
_mmSocket?.Close();
}
catch (IOException e)
{
_deviceConnector._log.Error(Tag + " close() of connect socket failed", e);
}
}
}
}
Can anybody please help me in figuring the issue, as the main function of the app I am working on is to connect to scanner and scan the RFID's.
Try changing your tmp = device.CreateInsecureRfcommSocketToServiceRecord(uuid.Uuid); to tmp = device.CreateRfcommSocketToServiceRecord(uuid.Uuid);
I'm trying to connect my device to another one via Bluetooth, but when I select the device I want to connect with, I get an IOException saying
read failed, socket might closed or timeout, read ret: -1
Just to illustrate how my app works, I have a RecyclerView populated with the devices my Bluetooth scan has found, then when I click an item the app is supposed to connect with that device.
Below is my the code for my connection thread:
private val MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")
private lateinit var device: BluetoothDevice
private lateinit var onDeviceActionListener: OnDeviceActionListener
private lateinit var socket: BluetoothSocket
fun init(device: BluetoothDevice,
onDeviceActionListener: OnDeviceActionListener): ConnectionThread {
this.device = device
this.onDeviceActionListener = onDeviceActionListener
try {
socket = device.createRfcommSocketToServiceRecord(MY_UUID)
} catch (e: IOException) {
Log.e(TAG, "Error creating socket", e)
}
return this
}
override fun run() {
try {
socket.connect()
} catch (openException: IOException) {
Log.e(TAG, "Error opening connection. Trying to close...", openException)
try {
socket.close()
} catch (closeException: IOException) {
Log.e(TAG, "Error closing socket", closeException)
}
return
}
onDeviceActionListener.onDeviceConnect(device)
}
My guess is there is something wrong with my UUID. I've tried some other values but still didn't work.
Any help will be much appreciated.
Well, I don't see exactly what you are doing wrong here. However, I have done quite a bit of Bluetooth work. More recently just focused in BLE. You should be able to discover your nearby BT devices and see their UUIDs.
I have written a helper class about 3 years ago so it's a little old, but should be mostly the same code. Happy to share it with you if it helps.
public class BluetoothConnector {
private static final String TAG = Globals.SEARCH_STRING + BluetoothConnector.class.getSimpleName();
private static final String DEFAULT_SERVER_NAME_FOR_APP = "tn_bt_default_server";
private static final int DEFAULT_DISCOVERABLE_DURATION_MS = 30000;
private static final UUID DEFAULT_UUID = UUID.fromString("6534c201-039c-4e4f-89f9-5ca8cfeb9667");
public static final int ENABLE_DISCOVER_INTENT = 1002;
protected boolean mIsToastEnabled = false; //Access from calling class to enable toasting of progress to screen if necessary
private Handler mUIHandler;
private static ServerSocketThread mServerSocketThread;
private static ClientSocketThread mClientSocketThread;
private ManageConnectionThread mManageConnectionThread;
private Context mContext;
private IBluetoothDataListener mBluetoothDataListener;
public final Object ServerSocketLock = new Object();
public final Object ClientSocketLock = new Object();
public final Object ManageConnectionLock = new Object();
public BluetoothConnector(Context context, IBluetoothDataListener listener){
this(context, new Handler(Looper.getMainLooper()), listener);
}
public BluetoothConnector(Context context, Handler UIHandler, IBluetoothDataListener listener){
Log.v(TAG, "BluetoothConnector(context=" + context + ", Handler=" + UIHandler.getClass().getSimpleName() + ", IBluetoothDataListener=" + listener.getClass().getSimpleName());
mContext = context;
mUIHandler = UIHandler;
mBluetoothDataListener = listener;
}
public void makeThisDeviceDiscoverable(Activity callingActivity){
makeThisDeviceDiscoverable(callingActivity, BluetoothAdapter.getDefaultAdapter(), DEFAULT_DISCOVERABLE_DURATION_MS);
}
public void makeThisDeviceDiscoverable(Activity callingActivity, BluetoothAdapter adapter){
makeThisDeviceDiscoverable(callingActivity, adapter, DEFAULT_DISCOVERABLE_DURATION_MS);
}
public void makeThisDeviceDiscoverable(Activity callingActivity, int durationInMs){
makeThisDeviceDiscoverable(callingActivity, BluetoothAdapter.getDefaultAdapter(), durationInMs);
}
public void makeThisDeviceDiscoverable(Activity callingActivity, BluetoothAdapter adapter, int durationInMs) {
Log.v(TAG, "makeThisDeviceDiscoverable(callingActivity=" + callingActivity.getClass().getSimpleName() + ", BluetoothAdapter=" + (adapter == null ? "null" : adapter.getName()) + ", duration=" + String.valueOf(durationInMs));
if(adapter == null){
Log.v(TAG, "adapter is null");
}else if(adapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Log.v(TAG, "Launching Activity to request Discoverable Permission");
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, durationInMs);
callingActivity.startActivityForResult(discoverableIntent, ENABLE_DISCOVER_INTENT);
}else{
Log.v(TAG, "adapter is already in SCAN MODE");
}
}
public void awaitConnectionFromDevice(){
awaitConnectionFromDevice(DEFAULT_UUID, BluetoothAdapter.getDefaultAdapter());
}
public void awaitConnectionFromDevice(UUID commonKey){
awaitConnectionFromDevice(commonKey, BluetoothAdapter.getDefaultAdapter());
}
public void awaitConnectionFromDevice(BluetoothAdapter adapter){
awaitConnectionFromDevice(DEFAULT_UUID, adapter);
}
public void awaitConnectionFromDevice(UUID commonKey, BluetoothAdapter adapter){
Log.v(TAG, "awaitConnectionFromDevice for UUID: " + String.valueOf(commonKey) + ", BluetoothAdapter=" + (adapter == null ? "null" : adapter.getName()));
cancelDiscovery();
synchronized (ServerSocketLock){
if(mServerSocketThread != null){
Log.v(TAG, "Server Socket Thread was not null so canceling current Thread");
mServerSocketThread.cancel();
}
Log.v(TAG, "Attempting to Start new ServerThread");
mServerSocketThread = new ServerSocketThread(commonKey, adapter);
mServerSocketThread.start();
}
}
public void cancelAwaitingConnectionFromDevice(){
Log.v(TAG, "cancelAwaitingConnectionFromDevice");
synchronized (ServerSocketLock){
if(mServerSocketThread != null){
mServerSocketThread.cancel();
mServerSocketThread = null;
Log.v(TAG, "canceling Server Socket Thread");
}else{
Log.v(TAG, "Server Socket null, so not canceling");
}
}
}
public void startDiscovery() {
startDiscovery(BluetoothAdapter.getDefaultAdapter());
}
public void startDiscovery(BluetoothAdapter adapter){
Log.v(TAG, "startDiscovery to find list of devices in range");
adapter.startDiscovery();
}
public void cancelDiscovery() {
cancelDiscovery(BluetoothAdapter.getDefaultAdapter());
}
public void cancelDiscovery(BluetoothAdapter adapter){
Log.v(TAG, "cancelDiscovery");
adapter.cancelDiscovery();
}
public void connectToDevice(BluetoothDevice device){
connectToDevice(device, DEFAULT_UUID);
}
public void connectToDevice(BluetoothDevice device, UUID commonKey){
Log.v(TAG, "connectToDevice(BluetoothDevice=" + (device == null ? "null" : device.getName()) + ", UUID=" + String.valueOf(commonKey));
synchronized (ClientSocketLock){
if(mClientSocketThread != null){
Log.v(TAG, "Client Socket Thread was not null so canceling current Thread");
mClientSocketThread.cancel();
}else{
Log.v(TAG, "Client Socket Thread is NULL so not canceling");
}
Log.v(TAG, "ClientSocketThread Starting");
mClientSocketThread = new ClientSocketThread(device, commonKey);
mClientSocketThread.start();
}
}
public BluetoothDevice getBluetoothDeviceByMac(String mac){
Log.v(TAG, "getBluetoothDeviceByMac(mac=" + mac);
return getBluetoothDeviceByMac(mac, BluetoothAdapter.getDefaultAdapter());
}
public BluetoothDevice getBluetoothDeviceByMac(String mac, BluetoothAdapter adapter) {
Log.v(TAG, "getBluetoothDeviceByMac(mac=" + mac + ", BluetoothAdapter=" + (adapter == null ? "null" : adapter.getName()));
return adapter.getRemoteDevice(mac);
}
public ArrayList<KeyValueModel> getPairedDevices(){
return getPairedDevices(BluetoothAdapter.getDefaultAdapter());
}
public ArrayList<KeyValueModel> getPairedDevices(BluetoothAdapter adapter){
ArrayList<KeyValueModel> bondedDevices = new ArrayList<KeyValueModel>();
Set<BluetoothDevice> pairedDevices = adapter.getBondedDevices();
Log.v(TAG, "getPairedDevices Found " + pairedDevices.size() + " number of paired devices");
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
bondedDevices.add(new KeyValueModel(device.getAddress(), device.getName()));
}
}
return bondedDevices;
}
public static void unpairDevice(BluetoothDevice device){
Log.v(TAG, "unpairDevice");
try{
Method method = device.getClass().getMethod("removeBond", (Class[]) null);
method.invoke(device, (Object[]) null);
}catch (Exception ex){
Log.e(TAG, "Error Unpairing Device: " + ex.getMessage());
}
}
public boolean sendDataToConnectedDevice(byte[] data){
Log.v(TAG, "sendDataToConnectedDevice");
synchronized (ManageConnectionLock){
mManageConnectionThread.write(data);
return true;
}
}
public void setBluetoothDataListener(IBluetoothDataListener listener){
mBluetoothDataListener = listener;
}
public boolean getIsConnected(){
synchronized (ManageConnectionLock) {
return mManageConnectionThread != null && mManageConnectionThread.isAlive();
}
}
private void startManageConnectionThread(BluetoothSocket socket){
Log.v(TAG, "startManageConnectionThread for Socket: " + (socket == null ? "null" : socket.getClass().getSimpleName()));
synchronized (ManageConnectionLock) {
mManageConnectionThread = new ManageConnectionThread(socket);
mManageConnectionThread.start();
}
}
private void handleDataReceivedFromConnectedDevice(final byte[] bytes){
Log.v(TAG, "handleDataReceivedFromConnectedDevice");
Log.v(TAG, "bytes to Listener: " + new String(bytes));
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if (mBluetoothDataListener != null) {
mBluetoothDataListener.onReceivedPayloadFromConnectedDevice(bytes);
}
}
});
}else{
Log.v(TAG, "UIHandler was null so skipped sending payload to listener");
}
}
private void handleConnected(){
Log.e(TAG, "handleConnected");
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onConnectedToTargetDevice();
}
}
});
}else{
Log.v(TAG, "UIHandler was null so skipped sending payload to listener");
}
}
private void handleDisconnected(){
Log.e(TAG, "handleDisconnected");
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onDisconnectedFromTargetDevice();
}
}
});
}else{
Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener");
}
}
private void handleFailedToConnectAsServer(final Exception ex){
Log.e(TAG, "handleFailedToConnectAsServer ex: " + ex.getMessage());
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onFailedToReceiveConnectionFromTargetDevice(ex);
}
}
});
}else{
Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener");
}
}
private void handleFailedToConnectAsClient(final Exception ex){
Log.e(TAG, "handleFailedToConnectAsClient ex: " + ex.getMessage());
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onFailedToConnectToTargetDevice(ex);
}
}
});
}else{
Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener");
}
}
private void handleErrorInRetrievingData(final Exception ex){
Log.e(TAG, "handleErrorInRetrievingData ex: " + ex.getMessage());
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onErrorReceivingPayloadFromConnectedDevice(ex);
}
}
});
}else{
Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener");
}
}
private void handleFailedToSendDataToConnectedDevice(final Exception ex){
Log.e(TAG, "handleFailedToSendDataToConnectedDevice ex: " + ex.getMessage());
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onFailedToSendDataToConnectedDevice(ex);
}
}
});
}else{
Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener");
}
}
private void toastMessage(final String value){
if(!mIsToastEnabled || mUIHandler == null) {
return;
}
mUIHandler.post(new Runnable() {
#Override
public void run() {
try{
Toast.makeText(mContext, value, Toast.LENGTH_SHORT).show();
}catch(Exception ex){
Log.v(TAG, "Error Toasting, possibly bad handler, or context: " + ex.getMessage());
}
}
});
}
private class ServerSocketThread extends Thread{
private final String TAG = Globals.SEARCH_STRING + ServerSocketThread.class.getSimpleName();
private final BluetoothServerSocket mServerSocket;
public ServerSocketThread(UUID commonKey, BluetoothAdapter adapter) {
Log.v(TAG, "ServerSocketThread Constructor");
BluetoothServerSocket tmp = null;
try {
Log.v(TAG, "listening for RFComas Server: " + DEFAULT_SERVER_NAME_FOR_APP + ", and commonKey: " + String.valueOf(commonKey));
// MY_UUID is the app's UUID string, also used by the client code
tmp = adapter.listenUsingRfcommWithServiceRecord(DEFAULT_SERVER_NAME_FOR_APP, commonKey);
toastMessage("Listening for RFComm As Server on UUID: " + String.valueOf(commonKey));
} catch (IOException e) {
Log.e(TAG, "Error creating ServerSocket: " + e.getMessage());
toastMessage("Error Creating ServerSocket: " + e.getMessage());
}
mServerSocket = tmp;
}
public void run() {
Log.v(TAG, "ServerSocket run");
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (mServerSocket != null) {
try {
Log.v(TAG, "ServerSocket.accept()");
toastMessage("ServerSocket.accept()");
//Waits for Client Connection to pass Socket, then we close down
socket = mServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "ServerSocket.accept() Error: " + e.getMessage());
toastMessage("ServerSocket.accept() Error: " + e.getMessage());
handleFailedToConnectAsServer(e);
break;
}
// If a connection was accepted we don't need to keep server listening, so close unless multiple client/server connections is desired
if (socket != null) {
try{
Log.v(TAG, "ServerSocket Accepted Client Socket, Begin Listening Connect Thread");
toastMessage("ServerSocket Accepted Client Socket, Begin Listening Connect Thread");
// Do work to manage the connection (in a separate thread)
startManageConnectionThread(socket);
//mServerSocket.close();
}catch(Exception ex){
Log.e(TAG, "Exception closing Server Socket");
}
//break; //Add in Break if you want to shut down listening for connections
}else{
Log.v(TAG, "Socket wasn't accepted");
toastMessage("Socket wasn't accepted");
handleFailedToConnectAsServer(new Exception("Socket is Null"));
}
}
Log.v(TAG, "Exiting Server Accept Thread");
}
public void cancel() {
try {
Log.v(TAG, "ServerSocketThread Canceled");
mServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "ServerSocketThread Error: " + e.getMessage());
}
}
}
private class ClientSocketThread extends Thread{
private BluetoothSocket mSocket;
private final BluetoothDevice mDevice;
public ClientSocketThread(BluetoothDevice device, UUID commonKey) {
Log.v(TAG, "ClientSocketThread Constructor");
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
Log.v(TAG, "Client creating RFComm Socket to Server with UUID: " + String.valueOf(commonKey));
toastMessage("Client creating RFComm Socket to Server with UUID: " + String.valueOf(commonKey));
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(commonKey);
} catch (IOException e) {
Log.e(TAG, "Error creating Client Socket: " + e.getMessage());
toastMessage("Creating Socket Exception: " + e.getMessage());
handleFailedToConnectAsClient(e);
}
mSocket = tmp;
}
public void run() {
try {
if(mSocket == null){
Log.e(TAG, "Error Client Socket is Null, Canceling Client Thread");
return;
}
Log.v(TAG, "Client Connecting");
// Connect to the server, or timeout eventually
toastMessage("Client Connecting");
mSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and try the fallback method of reflection with port to connect
try {
Log.e("", "trying fallback...");
toastMessage("Client Connection Failed Exception: " + connectException.getMessage());
mSocket = (BluetoothSocket) mDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(mDevice, 1);
toastMessage("Client Connect Again Attempt 2, but with fall back Reflection and port");
Log.v(TAG, "Client Connect Again Attempt 2, but with fall back Reflection and port");
mSocket.connect();
Log.e("", "Connected");
toastMessage("Client Connected");
} catch (Exception ex) {
Log.e("", "Couldn't establish Bluetooth connection!");
toastMessage("Client Couldn't Establish Connection to Server: " + ex.getMessage());
handleFailedToConnectAsClient(ex);
return;
}
}
// Do work to manage the connection (in a separate thread)
startManageConnectionThread(mSocket);
}
public void cancel() {
try {
Log.v(TAG, "Client Socket cancel");
mSocket.close();
} catch (IOException e) {
Log.e(TAG, "Error Closing Socket");
}
}
}
private class ManageConnectionThread extends Thread {
/////////////
// MEMBERS //
/////////////
private final String TAG = Globals.SEARCH_STRING + ManageConnectionThread.class.getSimpleName();
private final BluetoothSocket mSocket;
private final InputStream mInStream;
private final OutputStream mOutStream;
//////////////////
// CONSTRUCTOR //
//////////////////
public ManageConnectionThread(BluetoothSocket socket) {
mSocket = socket;
handleConnected();
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
try {
Log.v(TAG, "ManageConnectionThread Constructor");
Log.v(TAG, "Connected to Socket = " + String.valueOf(socket.isConnected()));
toastMessage("Listening for input or output Stream");
Log.v(TAG, "Get InputStream");
tmpIn = socket.getInputStream();
Log.v(TAG, "Get OutputStream");
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "Error getting Socket Streams: " + e.getMessage());
toastMessage("Connect Thread: Error: " + e.getMessage());
handleErrorInRetrievingData(e);
}
mInStream = tmpIn;
mOutStream = tmpOut;
}
///////////////
// OVERRIDES //
///////////////
public void run() {
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
byte[] data = new byte[16384];
int nRead;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
while ((nRead = mInStream.read(data, 0, data.length)) != -1) {
//Log.v(TAG, "bytes Read: " + String.valueOf(nRead));
buffer.write(data, 0, nRead);
//TODO Find better way to find End Of Message rather than looking for }
String temp = new String(buffer.toByteArray());
//Log.v(TAG, "current Data: " + temp);
if(temp.contains("}")){
Log.v(TAG, "bytes reading complete");
handleDataReceivedFromConnectedDevice(buffer.toByteArray());
buffer.flush();
buffer = new ByteArrayOutputStream();
}else{
Log.v(TAG, "More bytes Available");
}
}
} catch (IOException e) {
Log.e(TAG, "Error reading inputStream");
handleErrorInRetrievingData(e);
break;
}
}
Log.v(TAG, "Exiting Managed Connection Thread");
handleDisconnected();
}
/////////////
// METHODS //
/////////////
public void write(byte[] bytes) {
try {
Log.v(TAG, "ManageConnectionThread write(bytes)");
mOutStream.write(bytes);
} catch (IOException e) {
Log.e(TAG, "Error Writing Stream: " + e.getMessage());
handleFailedToSendDataToConnectedDevice(e);
}
}
public void cancel() {
try {
Log.v(TAG, "ManageConnectionThread cancel");
handleDisconnected();
mSocket.close();
} catch (IOException e) {
Log.e(TAG, "Error Closing BluetoothSocket: " + e.getMessage());
}
}
}
public interface IBluetoothDataListener{
//////////////////////
// OVERRIDE METHODS //
//////////////////////
void onReceivedPayloadFromConnectedDevice(byte[] payload);
void onErrorReceivingPayloadFromConnectedDevice(Exception ex);
void onFailedToConnectToTargetDevice(Exception ex);
void onFailedToReceiveConnectionFromTargetDevice(Exception ex);
void onFailedToSendDataToConnectedDevice(Exception ex);
void onConnectedToTargetDevice();
void onDisconnectedFromTargetDevice();
}
}
Then of course you will want to make sure you have your broadcast receivers setup:
<receiver
android:name=".receivers.BluetoothChangedReceiver"
android:enabled="true" >
<intent-filter>
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
<action android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
<action android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
<action android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
<action android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
<action android:name="android.bluetooth.device.action.FOUND" />
<action android:name="android.bluetooth.device.action.DISAPPEARED" />
</intent-filter>
</receiver>
<receiver
android:name=".receivers.BluetoothDeviceReceiver"
android:enabled="true" >
<intent-filter>
<action android:name="android.bluetooth.device.action.FOUND" />
<action android:name="android.bluetooth.device.action.DISAPPEARED" />
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
<action android:name="android.bluetooth.device.action.ACTION_ACL_DISCONNECT_REQUESTED" />
<action android:name="android.bluetooth.device.action.BOND_STATE_CHANGED" />
<action android:name="android.bluetooth.device.action.UUID" />
</intent-filter>
</receiver>
I'm trying to get two android phones to connect via bluetooth. I'm following the instructions here from the android online howto's, and I'm following pretty closely.
http://developer.android.com/guide/topics/connectivity/bluetooth.html
I can get bluetooth to connect once, but I have to restart the android device or the app itself in order to get it to connect a second time. This is not a problem during development because with each edit of the code the android studio program re-loads the app. It starts it and restarts it, so that during testing I can connect over and over. During actual use I have to restart the android phone or go to the applications manager option under settings and physically stop that app.
From the code below I can connect if I call these lines:
generateDefaultAdapter();
startDiscovery();
startThreadAccept();
startThreadConnect();
How do I get it so that the bluetooth connection can be initiated over and over again? I see the message 'unable to connect' from the inner class 'ConnectThread' and an IO error from a 'printStackTrace()' from that part of the code. The second time I try, I seem to be able to call the method 'stopConnection()' and then the lines above (starting with 'generateDefaultAdapter()') but I find I cannot connect.
package org.test;
//some import statements here...
public class Bluetooth {
public boolean mDebug = true;
public BluetoothAdapter mBluetoothAdapter;
public UUID mUUID = UUID.fromString(BLUETOOTH_UUID);
public Thread mAcceptThread;
public Thread mConnectThread;
public ConnectedThread mManageConnectionAccept;
public ConnectedThread mManageConnectionConnect;
public APDuellingBluetooth() {
}
public void generateDefaultAdapter() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
}
if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled() ) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
(mDialogDuel.getActivity()).startActivityForResult(enableBtIntent, INTENT_ACTIVITY_BLUETOOTH_REQUEST_ENABLE);
}
}
public void cancelDiscovery() { if (mBluetoothAdapter != null) mBluetoothAdapter.cancelDiscovery();}
public void startDiscovery() { mBluetoothAdapter.startDiscovery();}
public BluetoothAdapter getBluetoothAdapter() {return mBluetoothAdapter;}
public void stopConnection () {
try {
if (mAcceptThread != null) {
mAcceptThread.interrupt();
//mAcceptThread.join();
mAcceptThread = null;
}
if (mConnectThread != null) {
mConnectThread.interrupt();
//mConnectThread.join();
mConnectThread = null;
}
if (mManageConnectionConnect != null) {
mManageConnectionConnect.cancel();
mManageConnectionConnect.interrupt();
mManageConnectionConnect = null;
}
if (mManageConnectionAccept != null) {
mManageConnectionAccept.cancel();
mManageConnectionAccept.interrupt();
mManageConnectionAccept = null;
}
}
catch(Exception e) {
e.printStackTrace();
}
}
public void startThreadAccept () {
if (mAcceptThread != null && !mAcceptThread.isInterrupted()) {
if (mDebug) System.out.println("server already open");
//return;
mAcceptThread.interrupt();
mAcceptThread = new AcceptThread();
}
else {
mAcceptThread = new AcceptThread();
}
if (mAcceptThread.getState() == Thread.State.NEW ){
//mAcceptThread.getState() == Thread.State.RUNNABLE) {
mAcceptThread.start();
}
}
public void startThreadConnect () {
BluetoothDevice mDevice = mBluetoothAdapter.getRemoteDevice(mChosen.getAddress());
//if (mDebug) System.out.println(mDevice.getAddress() + " -- " + mChosen.getAddress() );
if (mConnectThread != null && !mConnectThread.isInterrupted()) {
if (mDebug) System.out.println("client already open");
//return;
mConnectThread.interrupt();
mConnectThread = new ConnectThread(mDevice);
}
else {
mConnectThread = new ConnectThread(mDevice);
}
if (mConnectThread.getState() == Thread.State.NEW){// ||
//mConnectThread.getState() == Thread.State.RUNNABLE) {
mConnectThread.start();
}
}
public void manageConnectedSocketAccept(BluetoothSocket socket) {
String mTemp = mBluetoothAdapter.getName();
if (mDebug) {
System.out.println("socket accept from " + mTemp);
System.out.println("info accept " + socket.getRemoteDevice().toString());
}
if (mManageConnectionAccept != null && !mManageConnectionAccept.isInterrupted()) {
//mManageConnectionAccept.cancel();
//mManageConnectionAccept.interrupt();
if (mAcceptThread == null) System.out.println(" bad thread accept");
}
else {
mManageConnectionAccept = new ConnectedThread(socket, "accept");
}
if (mManageConnectionAccept.getState() == Thread.State.NEW ){//||
//mManageConnectionAccept.getState() == Thread.State.RUNNABLE) {
mManageConnectionAccept.start();
}
}
public void manageConnectedSocketConnect(BluetoothSocket socket) {
String mTemp = mBluetoothAdapter.getName();
if (mDebug) {
System.out.println("socket connect from " + mTemp);
System.out.println("info connect " + socket.getRemoteDevice().toString());
}
if (mManageConnectionConnect != null && !mManageConnectionConnect.isInterrupted()) {
//mManageConnectionConnect.cancel();
//mManageConnectionConnect.interrupt();
if (mConnectThread == null) System.out.print(" bad thread connect ");
}
else {
mManageConnectionConnect = new ConnectedThread(socket, "connect");
}
if (mManageConnectionConnect.getState() == Thread.State.NEW){// ||
//mManageConnectionConnect.getState() == Thread.State.RUNNABLE) {
mManageConnectionConnect.start();
}
}
public void decodeInput (String mIn, ConnectedThread mSource) {
// do something with info that is returned to me...
}
public void encodeOutput (String mMac1, String mMac2, int mLR1, int mLR2) {
String mTemp = composeOutputString ( mServer, mMac1,mMac2, mLR1, mLR2);
if (mManageConnectionConnect != null && mManageConnectionConnect.isConnected()) {
mManageConnectionConnect.write(mTemp.getBytes());
mManageConnectionConnect.flush();
}
if (mManageConnectionAccept != null && mManageConnectionAccept.isConnected()) {
mManageConnectionAccept.write(mTemp.getBytes());
mManageConnectionAccept.flush();
}
mTemp = composeOutputString ( mClient, mMac1,mMac2, mLR1, mLR2);
if (mManageConnectionConnect != null && mManageConnectionConnect.isConnected()) {
mManageConnectionConnect.write(mTemp.getBytes());
mManageConnectionConnect.flush();
}
if (mManageConnectionAccept != null && mManageConnectionAccept.isConnected()) {
mManageConnectionAccept.write(mTemp.getBytes());
mManageConnectionAccept.flush();
}
}
public String composeOutputString (SocketConnectData mData, String mMac1, String mMac2, int mLR1, int mLR2) {
// make a string here with the data I want to send...
String mTemp = new String();
return mTemp;
}
/////////////////////////////////////////////
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
private boolean mLoop = true;
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket,
// because mmServerSocket is final
mLoop = true;
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(mServiceNameReceive, mUUID );
} catch (IOException e) {
System.out.println("rfcomm problem ");
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (mLoop) {
try {
if (mmServerSocket != null) {
socket = mmServerSocket.accept();
}
} catch (IOException e) {
if (mDebug) System.out.println("rfcomm accept problem");
e.printStackTrace();
break;
}
// If a connection was accepted
if (socket != null && ! isConnectionOpen() ) {
// Do work to manage the connection (in a separate thread)
manageConnectedSocketAccept(socket);
try {
mmServerSocket.close();
}
catch (IOException e) {}
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
mLoop = false;
mmServerSocket.close();
} catch (IOException e) { }
}
}
/////////////////////////////////////////////
private class ConnectThread extends Thread {
//private final BluetoothSocket mmSocket;
private BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
try {
tmp = device.createRfcommSocketToServiceRecord(mUUID);
if (mDebug) System.out.println("connect -- rf socket to service record " + tmp);
} catch (Exception e) {
System.out.println("exception -- rf socket to service record problem " + tmp);
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
}
//catch (InterruptedException e ) {System.out.println("interrupted exception");}
catch (IOException e) {
// Unable to connect; close the socket and get out
if (mDebug) System.out.println("unable to connect ");
e.printStackTrace(); // <---- I see output from this spot!!
try {
mmSocket.close();
} catch (IOException closeException) {
System.out.println("unable to close connection ");
}
return;
}
// Do work to manage the connection (in a separate thread)
if (mmSocket.isConnected() && ! isConnectionOpen()) {
manageConnectedSocketConnect(mmSocket);
}
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
public boolean isConnected() {
return mmSocket.isConnected();
}
}
/////////////////////////////////////////////
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public String mTypeName = "";
private boolean mLoop = true;
public StringWriter writer;
public ConnectedThread(BluetoothSocket socket, String type) {
mTypeName = type;
mLoop = true;
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
try {
writer = new StringWriter();
}
catch (Exception e) {}
}
public void run() {
byte[] buffer = new byte[1024]; //
int bytes; // bytes returned from read()
String [] mLines ;
// Keep listening to the InputStream until an exception occurs
while (mLoop) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
if (bytes == -1 || bytes == 0) {
if (mDebug) System.out.println("zero read");
return;
}
writer.append(new String(buffer, 0, bytes));
mLines = writer.toString().split("!");
if (mDebug) System.out.println( "lines " +mLines.length);
for (int i = 0; i < mLines.length; i ++ ) {
if (true) {
if (mDebug) System.out.println(" " + mLines[i]);
decodeInput (mLines[i], this);
}
}
} catch (Exception e) {
e.printStackTrace();
if (mDebug) System.out.println("read buffer problem");
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
if (mDebug) System.out.println("bad write");
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mLoop = false;
mmSocket.close();
mmOutStream.close();
mmInStream.close();
} catch (IOException e) { }
}
public boolean isConnected() {
boolean mIsOpen = false;
try {
mIsOpen = mmSocket.isConnected() ;
} catch (Exception e) {}
return mIsOpen;
}
public void flush() {
try {
mmOutStream.flush();
}
catch (IOException e) {e.printStackTrace();}
}
}
///////////////////////////////////////////////
}
Thanks for your time.
EDIT: this is the error msg:
W/System.err﹕ java.io.IOException: read failed, socket might closed or timeout, read ret: -1
W/System.err﹕ at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:553)
W/System.err﹕ at android.bluetooth.BluetoothSocket.waitSocketSignal(BluetoothSocket.java:530)
W/System.err﹕ at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:357)
W/System.err﹕ at org.davidliebman.test.Bluetooth$ConnectThread.run(Bluetooth.java:761)
Try this:
Instead of restarting the app. Turn off the Bluetooth on the Android device and turn it back on after a 5-sec delay. If you could make the connection successfully, it typically a sign that you did not close the connection and socket completely. Log your code. Make sure the closing socket routine is smoothly executed. Check if the IOException you have in your cancel method of your ConnectedThread is not catching any exception:
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
// ADD LOG
mLoop = false;
mmSocket.close();
mmOutStream.close();
mmInStream.close();
// ADD LOG
} catch (IOException e) {
// ADD LOG}
}
I'm trying to connect two mobile phone (galaxy note1, galaxy note2) with bluetooth but socket connection is fail.
this is my LogCat:
I/BluetoothService(24036): BEGIN mConnectThread
D/BluetoothUtils(24036): isSocketAllowedBySecurityPolicy start : device null
D/BluetoothService(24036): setState() 2 -> 1
D/BluetoothService(24036): Connect Fail
D/BluetoothService(24036): start
V/BluetoothSocket.cpp(24036): abortNative
V/BluetoothSocket.cpp(24036): ...asocket_abort(56) complete
V/BluetoothSocket.cpp(24036): destroyNative
V/BluetoothSocket.cpp(24036): ...asocket_destroy(56) complete
D/BluetoothUtils(24036): isSocketAllowedBySecurityPolicy start : device null
D/BluetoothService(24036): setState() 1 -> 1
D/BluetoothService(24036): Connect Fail
D/BluetoothService(24036): start
I don't know why 'connect fail' is occured.
isSocketAllowedBySecurityPolicy start : device null' is problem? OR bluetooth uuid is not correct?
Could you tell me what is the problem and how to solve this?
And I also add my src code about bluetoothservice part
public class BluetoothService {
// Debugging
private static final String TAG = "BluetoothService";
// Intent request code
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
// RFCOMM Protocol
private static final UUID MY_UUID = UUID
.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
private BluetoothAdapter btAdapter;
private Activity mActivity;
private Handler mHandler;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
private static final int STATE_NONE = 0; // we're doing nothing
private static final int STATE_LISTEN = 1; // now listening for incoming
// connections
private static final int STATE_CONNECTING = 2; // now initiating an outgoing
// connection
private static final int STATE_CONNECTED = 3; // now connected to a remote
// device
// Constructors
public BluetoothService(Activity ac, Handler h) {
mActivity = ac;
mHandler = h;
btAdapter = BluetoothAdapter.getDefaultAdapter();
}
/**
* Check the Bluetooth support
*
* #return boolean
*/
public boolean getDeviceState() {
Log.i(TAG, "Check the Bluetooth support");
if (btAdapter == null) {
Log.d(TAG, "Bluetooth is not available");
return false;
} else {
Log.d(TAG, "Bluetooth is available");
return true;
}
}
/**
* Check the enabled Bluetooth
*/
public void enableBluetooth() {
Log.i(TAG, "Check the enabled Bluetooth");
if (btAdapter.isEnabled()) {
Log.d(TAG, "Bluetooth Enable Now");
// Next Step
scanDevice();
} else {
Log.d(TAG, "Bluetooth Enable Request");
Intent i = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
mActivity.startActivityForResult(i, REQUEST_ENABLE_BT);
}
}
/**
* Available device search
*/
public void scanDevice() {
Log.d(TAG, "Scan Device");
Intent serverIntent = new Intent(mActivity, DeviceListActivity.class);
mActivity.startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
}
/**
* after scanning and get device info
*
* #param data
*/
public void getDeviceInfo(Intent data) {
// Get the device MAC address
String address = data.getExtras().getString(
DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BluetoothDevice object
// BluetoothDevice device = btAdapter.getRemoteDevice(address);
BluetoothDevice device = btAdapter.getRemoteDevice(address);
Log.d(TAG, "Get Device Info \n" + "address : " + address);
connect(device);
}
private synchronized void setState(int state) {
Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
}
public synchronized int getState() {
return mState;
}
public synchronized void start() {
Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (mConnectThread == null) {
} else {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread == null) {
} else {
mConnectedThread.cancel();
mConnectedThread = null;
}
}
public synchronized void connect(BluetoothDevice device) {
Log.d(TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (mState == STATE_CONNECTING) {
if (mConnectThread == null) {
} else {
mConnectThread.cancel();
mConnectThread = null;
}
}
// Cancel any thread currently running a connection
if (mConnectedThread == null) {
} else {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
// ConnectedThread
public synchronized void connected(BluetoothSocket socket,
BluetoothDevice device) {
Log.d(TAG, "connected");
// Cancel the thread that completed the connection
if (mConnectThread == null) {
} else {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread == null) {
} else {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
setState(STATE_CONNECTED);
}
// thread stop
public synchronized void stop() {
Log.d(TAG, "stop");
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(STATE_NONE);
}
public void write(byte[] out) { // Create temporary object
ConnectedThread r; // Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED)
return;
r = mConnectedThread;
} // Perform the write unsynchronized r.write(out); }
}
private void connectionFailed() {
setState(STATE_LISTEN);
}
private void connectionLost() {
setState(STATE_LISTEN);
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
}
mmSocket = tmp;
}
public void run() {
Log.i(TAG, "BEGIN mConnectThread");
setName("ConnectThread");
btAdapter.cancelDiscovery();
try {
mmSocket.connect();
Log.d(TAG, "Connect Success");
} catch (IOException e) {
connectionFailed();
Log.d(TAG, "Connect Fail");
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG,
"unable to close() socket during connection failure",
e2);
}
BluetoothService.this.start();
return;
}
synchronized (BluetoothService.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
bytes = mmInStream.read(buffer);
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
/**
* Write to the connected OutStream.
*
* #param buffer
* The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
connect fail occurs at connectThread. I'm sorry that this question is not easy to read.
Try to get correct UUID by:
BluetoothDevice device;
ParcelUuid list[] = device.getUuids();
//use e.g. first list[0]
deviceUUID = UUID.fromString(list[0].toString());
try {
TheSocket = TheDevice.createRfcommSocketToServiceRecord(deviceUUID);
} catch (IOException e) {
e.printStackTrace();
}
Hy , We are working on the android multiplayer game via bluetooth.
It is a multiplayer LUDO game in which 4 player connect to each other and play the game.
We are stuck in connection with the 3rd and 4th player connection.
private OnMaxConnectionsReachedListener maxConnectionsListener = new OnMaxConnectionsReachedListener() {
public void OnMaxConnectionsReached() {
}
};
private OnIncomingConnectionListener connectedListener = new OnIncomingConnectionListener() {
public void OnIncomingConnection(String device) {
//rivalDevice = device;
if(index < 1000)
{
clients[index] = device;
index++;
Log.d("Khawar", "Khawar"+device);
if(index == 1)
{
//blue.setText(clients[0]);
mConnection.sendMessage(clients[0], "ConnectionList--Ludofyp309509--"+server+"--Ludofyp309509--"+clients[0]);
}
else if(index == 2)
{
//blue.setText(clients[0]);
//red.setText(clients[1]);
mConnection.sendMessage(clients[0], "ConnectionList--Ludofyp309509--"+server+"--Ludofyp309509--"+clients[0]+"--Ludofyp309509--"+clients[1]);
mConnection.sendMessage(clients[1], "ConnectionList--Ludofyp309509--"+server+"--Ludofyp309509--"+clients[0]+"--Ludofyp309509--"+clients[1]);
}
else if(index==3)
{
//blue.setText(clients[0]);
//red.setText(clients[1]);
//yellow.setText(clients[2]);
mConnection.sendMessage(clients[0], "ConnectionList--Ludofyp309509--"+server+"--Ludofyp309509--"+clients[0]+"--Ludofyp309509--"+clients[1]+"--Ludofyp309509--"+clients[2]);
mConnection.sendMessage(clients[1], "ConnectionList--Ludofyp309509--"+server+"--Ludofyp309509--"+clients[0]+"--Ludofyp309509--"+clients[1]+"--Ludofyp309509--"+clients[2]);
mConnection.sendMessage(clients[2], "ConnectionList--Ludofyp309509--"+server+"--Ludofyp309509--"+clients[0]+"--Ludofyp309509--"+clients[1]+"--Ludofyp309509--"+clients[2]);
}
}
//Toast.makeText(getBaseContext(), "Client found" + device , Toast.LENGTH_LONG).show();
// WindowManager w = getWindowManager();
// Display d = w.getDefaultDisplay();
// int width = d.getWidth();
//int height = d.getHeight();
}
};
private OnConnectionLostListener disconnectedListener = new OnConnectionLostListener() {
public void OnConnectionLost(String device) {
class displayConnectionLostAlert implements Runnable {
public void run() {
Builder connectionLostAlert = new Builder(self);
connectionLostAlert.setTitle("Connection lost");
connectionLostAlert
.setMessage("Your connection with the other player has been lost.");
connectionLostAlert.setPositiveButton("Ok", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
connectionLostAlert.setCancelable(false);
try {
connectionLostAlert.show();
} catch (BadTokenException e){
Log.v("TAG", "Exception throws here");
}
}
}
self.runOnUiThread(new displayConnectionLostAlert());
}
};
private OnConnectionServiceReadyListener serviceReadyListener = new OnConnectionServiceReadyListener() {
public void OnConnectionServiceReady() {
if (mType == 0) {
mConnection.startServer(1, connectedListener, maxConnectionsListener,
dataReceivedListener, disconnectedListener);
self.setTitle("LudoOverAndroid: " + mConnection.getName() + "-" + mConnection.getAddress());
server = mConnection.getAddress();
green.setText(server);
Log.v("1", server);
// Intent Game = new Intent(self, Board.class);
// .putExtra("TYPE", 1);
// startActivity(Game);
} else {
self.setTitle("LudoOverAndroid: " + mConnection.getName() + "-" + mConnection.getAddress());
Intent serverListIntent = new Intent(self, ServerListActivity.class);
startActivityForResult(serverListIntent, SERVER_LIST_RESULT_CODE);
clients[index] = mConnection.getAddress();
// Intent Game = new Intent(self, Board.class);
// .putExtra("TYPE", 1);
// startActivity(Game);
}
}
};
Above is the sample code where connection are established.
But in the Connection Services class we have the following code
public int connect(String srcApp, String device) throws RemoteException {
if (mApp.length() > 0) {
Log.v("a", "connection service->connect->mApp.length");
return Connection.FAILURE;
}
mApp = srcApp;
BluetoothDevice myBtServer = mBtAdapter.getRemoteDevice(device);
BluetoothSocket myBSock = null;
Log.v("a", "Yaah aya hay aik baar nahe bar bar :");
for (int i = 0; i < Connection.MAX_SUPPORTED && myBSock == null; i++) {
for (int j = 0; j < 3 && myBSock == null; j++) {
myBSock = getConnectedSocket(myBtServer, mUuid.get(i));
if (myBSock == null) {
try {
Log.v("a", "connection service->connect->myBSock==NULL thread sleep");
Thread.sleep(200);
} catch (InterruptedException e) {
Log.e(TAG, "InterruptedException in connect", e);
}
}
}
}
if (myBSock == null) {
Log.v("a", "connection service->connect->myBSock==NULLss");
return Connection.FAILURE;
}
mBtSockets.put(device, myBSock);
mBtDeviceAddresses.add(device);
Thread mBtStreamWatcherThread = new Thread(new BtStreamWatcher(device));
mBtStreamWatcherThread.start();
mBtStreamWatcherThreads.put(device, mBtStreamWatcherThread);
return Connection.SUCCESS;
}
The mobile when connect with the 3rd or 4th device it return myBSock==null.
But if the codes work right it must return the address of the device and
should add mBtDeviceAddresses.add(device); into the server list.
kindly help us to fix the problem.
Thanks in advance
package com.switching.bluetooth;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.switching.ServerMainActivity;
/**
* This class does all the work for setting up and managing Bluetooth
* connections with other devices. It has a thread that listens for incoming
* connections, a thread for connecting with a device, and a thread for
* performing data transmissions when connected.
*/
public class BluetoothService {
// Debugging
private static final String TAG = "BluetoothService iBT";
private static final boolean D = true;
// Name for the SDP record when creating server socket
private static final String NAME = "i BT";
// Unique UUID for this application
private static UUID MY_UUID;
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
private ArrayList<String> mDeviceAddresses;
private ArrayList<String> mDeviceNames;
private ArrayList<ConnectedThread> mConnThreads;
private ArrayList<BluetoothSocket> mSockets;
/**
* A bluetooth piconet can support up to 7 connections. This array holds 7
* unique UUIDs. When attempting to make a connection, the UUID on the
* client must match one that the server is listening for. When accepting
* incoming connections server listens for all 7 UUIDs. When trying to form
* an outgoing connection, the client tries each UUID one at a time.
*/
private ArrayList<UUID> mUuids;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming
// connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing
// connection
public static final int STATE_CONNECTED = 3; // now connected to a remote
// device
/**
* Constructor. Prepares a new BluetoothChat session.
*
* #param context
* The UI Activity Context
* #param handler
* A Handler to send messages back to the UI Activity
*/
public BluetoothService(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
initializeArrayLists();
// 7 randomly-generated UUIDs. These must match on both server and
// client.
// mUuids.add(UUID.fromString("b7746a40-c758-4868-aa19-7ac6b3475dfc"));
// mUuids.add(UUID.fromString("2d64189d-5a2c-4511-a074-77f199fd0834"));
// mUuids.add(UUID.fromString("e442e09a-51f3-4a7b-91cb-f638491d1412"));
// mUuids.add(UUID.fromString("a81d6504-4536-49ee-a475-7d96d09439e4"));
// mUuids.add(UUID.fromString("aa91eab1-d8ad-448e-abdb-95ebba4a9b55"));
// mUuids.add(UUID.fromString("4d34da73-d0a4-4f40-ac38-917e0a9dee97"));
// mUuids.add(UUID.fromString("5e14d4df-9c8a-4db7-81e4-c937564c86e0"));
}
public static UUID getMY_UUID() {
return MY_UUID;
}
public static void setMY_UUID(UUID mY_UUID) {
MY_UUID = mY_UUID;
}
public boolean isDeviceConnectedAtPosition(int position) {
if (mConnThreads.get(position) == null) {
return false;
}
return true;
}
private void initializeArrayLists() {
mDeviceAddresses = new ArrayList<String>(5);
mDeviceNames = new ArrayList<String>(5);
mConnThreads = new ArrayList<ConnectedThread>(5);
mSockets = new ArrayList<BluetoothSocket>(5);
mUuids = new ArrayList<UUID>(5);
for (int i = 0; i < 5; i++) {
mDeviceAddresses.add(null);
mDeviceNames.add(null);
mConnThreads.add(null);
mSockets.add(null);
mUuids.add(null);
}
Log.i(TAG, "mConnThreads.size() in Service Constructor--"
+ mConnThreads.size());
}
public ArrayList<String> getmDeviceNames() {
return this.mDeviceNames;
}
public void setmDeviceNames(ArrayList<String> mDeviceNames) {
this.mDeviceNames = mDeviceNames;
}
public ArrayList<String> getmDeviceAddresses() {
return mDeviceAddresses;
}
public void setmDeviceAddresses(ArrayList<String> mDeviceAddresses) {
this.mDeviceAddresses = mDeviceAddresses;
}
/**
* Set the current state of the chat connection
*
* #param state
* An integer defining the current connection state
*/
private synchronized void setState(int state) {
if (D)
Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
// Give the new state to the Handler so the UI Activity can update
mHandler.obtainMessage(ServerMainActivity.MESSAGE_STATE_CHANGE, state,
-1).sendToTarget();
}
/**
* Return the current connection state.
*/
public synchronized int getState() {
return mState;
}
/**
* Start the chat service. Specifically start AcceptThread to begin a
* session in listening (server) mode. Called by the Activity onResume()
*/
public synchronized void start() {
if (D)
Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to listen on a BluetoothServerSocket
if (mAcceptThread == null) {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
setState(STATE_LISTEN);
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
*
* #param device
* The BluetoothDevice to connect
*/
public synchronized void connect(BluetoothDevice device,
int selectedPosition) {
if (getPositionIndexOfDevice(device) == -1) {
if (D)
Log.d(TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (mState == STATE_CONNECTING) {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
}
// Cancel any thread currently running a connection
if (mConnThreads.get(selectedPosition) != null) {
mConnThreads.get(selectedPosition).cancel();
// mConnectedThread = null;
mConnThreads.set(selectedPosition, null);
}
// Create a new thread and attempt to connect to each UUID
// one-by-one.
try {
// String
// s="00001101-0000-1000-8000"+device.getAddress().split(":");
ConnectThread mConnectThread = new ConnectThread(device,
UUID.fromString("00001101-0000-1000-8000-"
+ device.getAddress().replace(":", "")),
selectedPosition);
Log.i(TAG, "uuid-string at server side"
+ ("00001101-0000-1000-8000" + device.getAddress()
.replace(":", "")));
mConnectThread.start();
setState(STATE_CONNECTING);
} catch (Exception e) {
}
} else {
Message msg = mHandler
.obtainMessage(ServerMainActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(ServerMainActivity.TOAST,
"This device " + device.getName() + " Already Connected");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
*
* #param socket
* The BluetoothSocket on which the connection was made
* #param device
* The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothSocket socket,
BluetoothDevice device, int selectedPosition) {
if (D)
Log.d(TAG, "connected");
/*
* // Cancel the thread that completed the connection if (mConnectThread
* != null) { mConnectThread.cancel(); mConnectThread = null; }
*
* // Cancel any thread currently running a connection if
* (mConnectedThread != null) { mConnectedThread.cancel();
* mConnectedThread = null; }
*
* // Cancel the accept thread because we only want to connect to one //
* device if (mAcceptThread != null) { mAcceptThread.cancel();
* mAcceptThread = null; }
*/
// Start the thread to manage the connection and perform transmissions
ConnectedThread mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
// Add each connected thread to an array
mConnThreads.set(selectedPosition, mConnectedThread);
// Send the name of the connected device back to the UI Activity
Message msg = mHandler
.obtainMessage(ServerMainActivity.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(ServerMainActivity.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
/**
* Stop all threads
*/
public synchronized void stop() {
if (D)
Log.d(TAG, "stop");
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
for (int i = 0; i < 5; i++) {
mDeviceNames.set(i, null);
mDeviceAddresses.set(i, null);
mSockets.set(i, null);
if (mConnThreads.get(i) != null) {
mConnThreads.get(i).cancel();
mConnThreads.set(i, null);
}
}
setState(STATE_NONE);
}
/**
* Write to the ConnectedThread in an unsynchronized manner
*
* #param out
* The bytes to write
* #see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
// When writing, try to write out to all connected threads
for (int i = 0; i < mConnThreads.size(); i++) {
try {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED)
return;
r = mConnThreads.get(i);
}
// Perform the write unsynchronized
r.write(out);
} catch (Exception e) {
}
}
}
/**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
private void connectionFailed() {
setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(ServerMainActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(ServerMainActivity.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost(BluetoothDevice device) {
// setState(STATE_LISTEN);
int positionIndex = getPositionIndexOfDevice(device);
if (positionIndex != -1) {
Log.i(TAG, "getPositionIndexOfDevice(device) ==="
+ mDeviceAddresses.get(getPositionIndexOfDevice(device)));
mDeviceAddresses.set(positionIndex, null);
mDeviceNames.set(positionIndex, null);
mConnThreads.set(positionIndex, null);
Message msg = mHandler
.obtainMessage(ServerMainActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(ServerMainActivity.TOAST,
"Device connection was lost from " + device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
}
// Send a failure message back to the Activity
}
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
if (mAdapter.isEnabled()) {
BluetoothService.setMY_UUID(UUID
.fromString("00001101-0000-1000-8000-"
+ mAdapter.getAddress().replace(":", "")));
}
Log.i(TAG, "MY_UUID.toString()=="
+ BluetoothService.getMY_UUID().toString());
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME,
BluetoothService.getMY_UUID());
} catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
if (D)
Log.d(TAG, "BEGIN mAcceptThread" + this);
setName("AcceptThread");
BluetoothSocket socket = null;
Log.i(TAG, "mState in acceptThread==" + mState);
// Listen to the server socket if we're not connected
while (mState != STATE_CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
// If a connection was accepted
if (socket != null) {
synchronized (BluetoothService.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
connected(socket, socket.getRemoteDevice(),getAvailablePositionIndexForNewConnection(socket.getRemoteDevice()));
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate
// new socket.
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
if (D)
Log.i(TAG, "END mAcceptThread");
}
public void cancel() {
if (D)
Log.d(TAG, "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of server failed", e);
}
}
}
/**
* This thread runs while listening for incoming connections. It behaves
* like a server-side client. It runs until a connection is accepted (or
* until cancelled).
*/
// private class AcceptThread extends Thread {
// BluetoothServerSocket serverSocket = null;
//
// public AcceptThread() {
// }
//
// public void run() {
// if (D)
// Log.d(TAG, "BEGIN mAcceptThread" + this);
// setName("AcceptThread");
// BluetoothSocket socket = null;
// try {
// // Listen for all 7 UUIDs
// serverSocket = mAdapter.listenUsingRfcommWithServiceRecord(
// NAME, MY_UUID);
// socket = serverSocket.accept();
// if (socket != null) {
// String address = socket.getRemoteDevice().getAddress();
// mSockets.add(socket);
// mDeviceAddresses.add(address);
// mDeviceNames.add(socket.getRemoteDevice().getName());
// // connected(socket, socket.getRemoteDevice());
// }
// } catch (IOException e) {
// Log.e(TAG, "accept() failed", e);
// }
// if (D)
// Log.i(TAG, "END mAcceptThread");
// }
//
// public void cancel() {
// if (D)
// Log.d(TAG, "cancel " + this);
// try {
// serverSocket.close();
// } catch (IOException e) {
// Log.e(TAG, "close() of server failed", e);
// }
// }
// }
/**
* This thread runs while attempting to make an outgoing connection with a
* device. It runs straight through; the connection either succeeds or
* fails.
*/
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private UUID tempUuid;
private int selectedPosition;
public ConnectThread(BluetoothDevice device, UUID uuidToTry,
int selectedPosition) {
mmDevice = device;
BluetoothSocket tmp = null;
tempUuid = uuidToTry;
this.selectedPosition = selectedPosition;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(uuidToTry);
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
}
mmSocket = tmp;
}
public void run() {
Log.i(TAG, "BEGIN mConnectThread");
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mAdapter.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 (IOException e) {
// if
// (tempUuid.toString().contentEquals(mUuids.get(6).toString()))
// {
connectionFailed();
// }
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG,
"unable to close() socket during connection failure",
e2);
}
// Start the service over to restart listening mode
BluetoothService.this.start();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothService.this) {
mConnectThread = null;
}
mDeviceAddresses.set(selectedPosition, mmDevice.getAddress());
mDeviceNames.set(selectedPosition, mmDevice.getName());
// Start the connected thread
connected(mmSocket, mmDevice, selectedPosition);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
/**
* This thread runs during a connection with a remote device. It handles all
* incoming and outgoing transmissions.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(
ServerMainActivity.MESSAGE_READ,
bytes,
getPositionIndexOfDevice(mmSocket.getRemoteDevice()),
buffer).sendToTarget();
Log.i("**********read", "read Called........");
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost(mmSocket.getRemoteDevice());
break;
}
}
}
/**
* Write to the connected OutStream.
*
* #param buffer
* The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
mHandler.obtainMessage(ServerMainActivity.MESSAGE_WRITE, -1,
-1, buffer).sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
public int getPositionIndexOfDevice(BluetoothDevice device) {
for (int i = 0; i < mDeviceAddresses.size(); i++) {
if (mDeviceAddresses.get(i) != null
&& mDeviceAddresses.get(i).equalsIgnoreCase(
device.getAddress()))
return i;
}
return -1;
}
public int getAvailablePositionIndexForNewConnection(BluetoothDevice device) {
if (getPositionIndexOfDevice(device) == -1) {
for (int i = 0; i < mDeviceAddresses.size(); i++) {
if (mDeviceAddresses.get(i) == null) {
return i;
}
}
}
return -1;
}
}
I implemented that with sucess after a relevant amount of work, during the path i faced some tricky bugs, for instance I had to implement a Handshake protocol(something like that) to avoid timeout problem during a connection attempt.
Well, I started looking at the BluetoothChat example(Android SDK Sample), that implements communication between 2 devices. So, I modified that, to permit multiple connections. As the code became large, i will just tell you the approach I have used.
Basically, all devices running my app can be a server or client. So each one, has always a BluetoothServerSocket(AcceptThread) running, so in this way, each device is always able to receive a request connection.
A device that wants to connect, starts a ConnectThread, this thread it is started after a discovery process or if it choose BluetoothDevice of PairedDevices Using getBondedDevices.
When a connection is established, I create a new Thread(ConnectedThread) that represents that connection. If you want to has different behavior that depends of you device role(master or slave) you can have a ConnectedThread subclass like MasterThread and SlaveThread
The Android Documentation has a good explanation of how to work with Bluetooth at: http://developer.android.com/guide/topics/connectivity/bluetooth.html