I'm trying to use an Android device to connect to Bluetooth devices to retrieve some information. In particular I'm trying to connect to Bluetooth headphones on this UUID:
"0000111E-0000-1000-8000-00805F9B34FB"
To do this I'm creating a socket and connecting it to the remote device this way:
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket
// because mmSocket is final.
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothSocket tmp = null;
mmDevice = device;
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
tmp = device.createRfcommSocketToServiceRecord(UUID_HF);
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it otherwise slows down the connection.
bluetoothAdapter.cancelDiscovery();
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and return.
try {
mmSocket.close();
} catch (IOException closeException) {
Log.e(TAG, "Could not close the client socket", closeException);
}
return;
}
// The connection attempt succeeded. Perform work associated with
// the connection in a separate thread.
manageMyConnectedSocket(mmSocket);}
It works fine when the headphones are not yet connected with my Android device. But what happens is that the headphones connect automatically with my Android device thanks to the OS itself. And in this case, when I execute the mmSocket.connect() method, it does not return. I thought that maybe Android has connected automatically another socket with the same UUID and so mine doesn't work. Do you think this is the problem? And if it is, is there a way to close all the sockets between my Android device and a remote Bluetooth device? Or maybe just the one that is bothering my process?
Thanks in advance.
what actually happens is the OS is doing the paired device criteria to save some battery as the searching process consume a lot of energy.
since you've done the search you should go for searching in paired devices not normal search and the result of the search should be taken from
Query paired devices
Before performing device discovery, it's worth querying the set of paired devices to see if the desired device is already known. To do so, call getBondedDevices(). This returns a set of BluetoothDevice objects representing paired devices. For example, you can query all paired devices and get the name and MAC address of each device, as the following code snippet demonstrates:
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
// There are paired devices. Get the name and address of each paired device.
for (BluetoothDevice device : pairedDevices) {
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
}
}
To initiate a connection with a Bluetooth device, all that's needed from the associated BluetoothDevice object is the MAC address, which you retrieve by calling getAddress(). You can learn more about creating a connection in the section about Connecting Devices.
this is the official documentation from google covering every detail about Bluetooth:
https://developer.android.com/guide/topics/connectivity/bluetooth
Related
I am able to pair devices with the android studio app but I get the tag
"CouldNotConnectToSocket" even though the device is paired.
I am new to android studio so I am really stuck with where to go next.
I also get
getBluetoothService() called with no BluetoothManagerCallback
The UUID I created is:
private final static UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
Can anyone please help me?
new Thread() {
#Override
public void run() {
device = BA.getRemoteDevice(address);
try {
BTSocket = device.createRfcommSocketToServiceRecord(BTMODULEUUID);
//BTSocket = createBluetoothSocket(device);
Log.d(TAG, "Device Connected");
BA.cancelDiscovery();
BTSocket.connect();
} catch (IOException ex) {
Log.d(TAG, "CouldNotConnectToSocket");
closeSocket(BTSocket);
}
}
}.start();
The issue I found out was that the devices I was trying to connect to send data back and forth require Bluetooth Low Energy support from the app.
So I need device A (client) to connect to device B (server) and I've gotten it to work, but not in all cases. Upon opening the app, I want to allow the device to be discovered
private void enableDiscoverability() {
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
3600);
startActivity(discoverableIntent);
}
, and i set up a receiver to look for one specific device (just for now, I'm still learning how to use Bluetooth)
private final BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
TextView output = findViewById(R.id.output);
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Discovery has found a device. Get the BluetoothDevice
// object and its info from the Intent.
BluetoothDevice temp = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String deviceName = temp.getName();
Log.i("Device ", deviceName + " was found");
String deviceHardwareAddress = temp.getAddress();
if (deviceHardwareAddress.equalsIgnoreCase("DC:F7:56:DD:73:8F")) {
device = temp;
startClient();
}
}
}
};
So here is my problem. When device A is left on, it'll discover new devices for a little while, but it won't discover the new device B after a few minutes. Both devices should have a receiver and should be discoverable.
Is there a timeout when you're discovering devices? Would something happen to the receiver if it tried to connect but failed? I've tried to look it up, but I'm still new with Bluetooth so I wouldn't know where to begin. I'd be more than happy to post more code if need be
Yes. Every device has a discovery timeout. Best place to start is bluetooth.com, with huge amount of videos and documents. There is timeout for every activity in Bluetooth such as discovery, connection, data transmission etc.
I was going through BluetoothGatt.java and found the method boolean connect(Boolean autoConnect, BluetoothGattCallback callback,
Handler handler)
The documentation just above this method specifies that this is used to initiate a connection with BLE devices.
However, the official Android documentation states that to connect with a BLE device boolean connect() should be used.
The documentation for this connect() method states that this is used to reconnect back to a device.
I am confused here because gatt.connect() is sometimes unreliable (the callback for the device connected is not called even though the BLE device is in range but connects when I try to connect in the second or third attempt.)
Would it be better to use the method mentioned earlier to increase connection chances during first connection attempt?
Can anyone share some information regarding this?
However, the official Android documentation states that to connect with a BLE device Boolean connect() should be used.
Above method is the Bluetooth Gatt method that will help you connect with ble device .
after successful connection , BluetoothGatt will call BluetoothGattCallback , that have different override methods .
As per My implementation , I discovered the device using BluetoothAdapter.LeScanCallback that is used for lower version. After that :-
private void addDeviceItem(BluetoothDevice device, int rssi) {
String penAddress = device.getAddress();
mBluetoothLeService.connect(penAddress );
}
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
// refreshDeviceCache(mBluetoothGatt);
Log.d(TAG, "Trying to create a new connection.");
mConnectionState = STATE_CONNECTING;
return true;
}
I will always connect with the device , after finish with Bluetooth , you have to disconnect with device by calling Gatt.disconnect(). then again make connection using above code.
My answer at Which correct flag of autoConnect in connectGatt of BLE? should explain everything.
Basically, a "direct connect" has a higher duty of the scan window / interval than an "auto connect". That's why an auto connect can take very long time if you have a long advertising interval on the peripheral.
I'm new to both java and android and I am currently working on a simple data logging app for information sent via bluetooth. I have recently switched to using an HM-10 (CC41) BLE module from classic bluetooth. Since I don't know anything about using Gatt characteristics to create a connection and receive data, I would like to continue using socket communication. My phone S7 edge is not able to pair to the BLE device though so it's not an option for me to create a bond programatically before starting the RfcommSocket. Is there any way to continue using socket communication without pairing? Finally, I already have the MAC address of my BLE module so I would rather not be scanning. Here is my relevant code:
public class MainActivity extends AppCompatActivity implements Runnable {
private BluetoothAdapter adapter;
private InputStream inputStream;
private OutputStream outputStream;
private Thread thread;
private TextView Status;
private TextView Connection;
private BluetoothSocket socket = null;
public boolean threadStatusInitial; //changed the status global variables to public static
public boolean threadStatus;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
threadStatusInitial=true;
threadStatus=true;
Status=(TextView) findViewById(R.id.StatusID);
Connection=(TextView) findViewById(R.id.ConnectionStatus);
adapter= BluetoothAdapter.getDefaultAdapter();
if(adapter==null){
Toast.makeText(this,"bluetooth is unavailable",Toast.LENGTH_SHORT).show();
finish();
return;
}
thread=new Thread(this);
}
public void connect(View view){
BluetoothDevice device=adapter.getRemoteDevice("3C:A3:08:94:C3:11");
try {
socket=device.createRfcommSocketToServiceRecord(device.getUuids()[0].getUuid());
socket.connect();
Connection.setText("Connected");
inputStream=socket.getInputStream();
outputStream=socket.getOutputStream();
if (threadStatusInitial){
thread.start();
threadStatusInitial=false; //this ensures that the thread.start() method will only be called during the initial connection
}
threadStatus=true;
} catch (IOException e) {
Toast.makeText(this,"Can't Connect",Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
The thread related global variables have to do with maintaining the logging thread during disconnects and reconnects to the BLE module.
Thanks!
First of all Bluetooth low energy is not meant to use Sockets for connection and data transfer. The whole point of BLE is to keep power consumption as low as possible that cannot be achieved by sockets as they maintain the continue data transfer stream regardless we are sending any data or not.
You can get help from this link for android- HM10 communication.
http://android-er.blogspot.in/2015/12/connect-hm-10-ble-module-to-android.html
Bluetooth classic and Bluetooth Low Energy, although related are different standards. For a classic connection you would use something like the code you have illustrated. But a BLE client is much different. Requires completely different client code. I think your device HM-10 (CC41) BLE module likely only supports BLE. I believe your only choice is to migrate to BLE.
I'm writing a bluetooth HID server for a small and very simple bluetooth remote. I'm following the documentation here.
My application's permission include:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
And this is my BluetoothServerSocket reading connection-accepting thread:
private class AcceptThread extends Thread {
public void run() {
BluetoothSocket socket = null;
while(true) {
try {
socket = MyBluetoothServerSocket.accept(); // problematic line
} catch(IOException e) {
Log.i(BLUETOOTH_SERVICE, e.toString());
break;
}
if(socket != null) {
readInput(socket);
try {
MyBluetoothServerSocket.close();
} catch (IOException e) {
Log.i(BLUETOOTH_SERVICE, e.toString());
}
} else {
Log.i(BLUETOOTH_SERVICE, "Could not accept a connection from the socket.\n");
}
break;
}
}
}
MyBluetoothServerSocket is a socket constructed like this:
MyBluetoothAdapter.listenUsingRfcommWithServiceRecord("MyService", UUID.fromString("00001124-0000-1000-8000-00805f9b34fb"));
The UUID I'm using above is the only one my remote control device reports through the following method:
MyBluetoothDevice.getUuids();
And MyBluetoothAdapter is just the default adapter:
BluetoothAdapter.getDefaultAdapter();
The rest of the code involved is minimal (making sure bluetooth is on, selecting the correct device) and working correctly. The remote is bonded to the phone.
The line marked as problematic in the code above (accept()) never returns i.e. it blocks forever. What am I doing wrong?
edit: I've tried MyBluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord without success.
HID is based on the L2CAP bluetooth profile (protocol?), which is not implemented (line 107) in Android as of October 2013.
This makes it currently impossible to connect to a HID device.