[Solved] Bluetooth list paired devices
-
Sorry for asking such a simple question, but I'm really stuck finding the answer in the documentation.
How can get a list of paired devices without starting the long discovery process?
-
It seems that the Bluez libraries don't provide that functionality , which may be the cause why QtBluetooth also does not provide it. Searching the web I found out that there should be a DBUS service which provides the list. However, that service is not available in Ubuntu (and maybe also other Linux distributions).
There is a command-line tool called "bt-device" in the package "bluez-utils" which provides exactly the list that I was searching for. So I use that as long there is no direct support in QtBluetooth.
@
QMap<QString,QString> LinuxRfComm::getKnownDevices() {
QMap<QString,QString> result;// Run the external Bluetooth program. Example of the output: // HC-06 (20:13:11:15:16:08) QProcess command; command.start("bt-device -l"); command.waitForFinished(3000); QByteArray output=command.readAllStandardOutput(); // Split the result QRegExp regexp("(.*) \\((.*)\\)"); foreach(QByteArray line, output.split('\n')) { if (regexp.indexIn(line)>=0) { result.insert(regexp.cap(2),regexp.cap(1)); } } qDebug("Found %i devices",result.size()); return result;
}
@ -
Android does also provide this list, but only in the Java API. We can call it from Qt this way:
@
QMap<QString,QString> AndroidRfComm::getKnownDevices() {
QMap<QString,QString> result;
QAndroidJniObject pairedDevicesSet=adapter.callObjectMethod("getBondedDevices","()Ljava/util/Set;"); // Set<BluetoothDevice>
check("BluetoothAdapter.getBondedDevices()",pairedDevicesSet);
jint size=pairedDevicesSet.callMethod<jint>("size");
check("Set<BluetoothDevice>.size()");
qDebug("Found %i paired devices",size);
if (size>0) {
QAndroidJniObject iterator=pairedDevicesSet.callObjectMethod("iterator","()Ljava/util/Iterator;"); // Iterator<BluetoothDevice>
check("Set<BluetoothDevice>.iterator()",iterator);
for (int i=0; i<size; i++) {
QAndroidJniObject dev=iterator.callObjectMethod("next","()Ljava/lang/Object;"); // BluetoothDevice
check("Iterator<BluetoothDevice>.next()",dev);
QString address=dev.callObjectMethod("getAddress","()Ljava/lang/String;").toString();
QString name=dev.callObjectMethod("getName","()Ljava/lang/String;").toString();
result.insert(address,name);
}
}
return result;
}
@ -
Hi
I'd like to use your JNI method in order to find a paired device address from a tablet. The reason is that I cannot figure out how to RFCOMM connect from a Samsung tablet to a COM/bluetooth board (testing device simulating a BT server). Qt Doc example is straitforward but with a paired Galaxy Tab3 ST110 (and same on NEXUS 4):
_socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
_socket->connectToService(remoteService)
gives socket error 8 (unsupported protocol) !!!Question 1/ Did I miss something in Qt docs ? maybe I had to prepare the remoteService data structure in some way ?
Question 2/ Qt offers a second way to RFCOMM connect that use the Bluetooth remote address and a UUID. Hence I would like to determine the address of paired device from my tablet. I used JNI long ago so could you please tell me about the following details in your code example
2a) is the variable adapter declaration should be
QAndroidJniObject adapter("android/bluetooth/BluetoothAdapter");2b) what is the check() method ? some verification ? could it be removed ?
Thanks
J -
QBluetoothSocket has another method to connect with address and UUID instead of a service object. You will need this because the Java Interface returns only the name and address of the device.
Do it this way:
QBluetoothAddress("20:13:11:15:16:08");
QString uuid("00001101-0000-1000-8000-00805F9B34FB");
QBluetoothSocket* socket=new QBluetoothSocket(); socket->connectToService(QBluetoothAddress(btAddress),QBluetoothUuid(uuid));Here is a complete working program using only JNI that might be helpful http://stefanfrings.de/android_qt/AndroidBluetooth.zip
Or another program that combines JNI with the Qt Bluetooth library: http://stefanfrings.de/avr_io/ioModule.zip
You need to know the correct UUID. I found it with Google. You could also scan for devices and check out what's stored in the service object. It should always contain the device address and either a UUID or a port number. For my cases it turned out that the UUID is more universal because all devices use the same but different port numbers.
Some phones/tablets simply don't support RFCOMM protocol. You may try any RFCOMM application from the Play Store to verify that. I can recommend: https://play.google.com/store/apps/details?id=mobi.dzs.android.BluetoothSPP&hl=de (It recommends to upgrade but that newer version doesn't work on my phone).
I see the example source from my previous post is incomplete, it does not tell how to get the "adapter" object. The check method checks for exceptions as documented in http://qt-project.org/doc/qt-5/qandroidjniobject.html in the chapter Handling Java Exceptions.
Now this is a more complete example:
@
QStringList IoModule::getBluetoothDevices() {
QStringList result;
QString fmt("%1 %2");#ifdef Q_OS_ANDROID // Query via Android Java API. QAndroidJniObject adapter=QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter","getDefaultAdapter","()Landroid/bluetooth/BluetoothAdapter;"); // returns a BluetoothAdapter if (checkException("BluetoothAdapter.getDefaultAdapter()",&adapter)) { return result; } QAndroidJniObject pairedDevicesSet=adapter.callObjectMethod("getBondedDevices","()Ljava/util/Set;"); // returns a Set<BluetoothDevice> if (checkException("BluetoothAdapter.getBondedDevices()",&pairedDevicesSet)) { return result; } jint size=pairedDevicesSet.callMethod<jint>("size"); checkException("Set<BluetoothDevice>.size()"); if (size>0) { QAndroidJniObject iterator=pairedDevicesSet.callObjectMethod("iterator","()Ljava/util/Iterator;"); // returns an Iterator<BluetoothDevice> if (checkException("Set<BluetoothDevice>.iterator()",&iterator)) { return result; } for (int i=0; i<size; i++) { QAndroidJniObject dev=iterator.callObjectMethod("next","()Ljava/lang/Object;"); // returns a BluetoothDevice if (checkException("Iterator<BluetoothDevice>.next()",&dev)) { continue; } QString address=dev.callObjectMethod("getAddress","()Ljava/lang/String;").toString(); // returns a String QString name=dev.callObjectMethod("getName","()Ljava/lang/String;").toString(); // returns a String result.append(fmt.arg(address).arg(name)); } } #elif defined Q_OS_LINUX // Query via the Linux command bt-device. QProcess command; command.start("bt-device -l"); command.waitForFinished(3000); if (command.error()==QProcess::FailedToStart) { qWarning("Cannot execute the command 'bt-device': %s",qPrintable(command.errorString())); } else { // Parse the output, example: HC-06 (20:13:11:15:16:08) QByteArray output=command.readAllStandardOutput(); QRegExp regexp("(.*) \\((.*)\\)"); foreach(QByteArray line, output.split('\n')) { if (regexp.indexIn(line)>=0) { result.append(fmt.arg(regexp.cap(2)).arg(regexp.cap(1))); } } } #endif return result;
}
#ifdef Q_OS_ANDROID
bool IoModule::checkException(const char* method, const QAndroidJniObject* obj) {
static QAndroidJniEnvironment env;
bool result=false;
if (env->ExceptionCheck()) {
qCritical("Exception in %s",method);
env->ExceptionDescribe();
env->ExceptionClear();
result=true;
}
if (!(obj==NULL || obj->isValid())) {
qCritical("Invalid object returned by %s",method);
result=true;
}
return result;
}
#endif
@If there is still something missing, checkout my two example programs (from above).
-
Hi
Thanks you very much: I have used your Qt/JNI/Java method for getting the remote address of my paired device and apply strategy 2. As a result
1/ I (your code) was successfull for retrieving the correct remode address
2/ With the connectToService(address, sppUuid) strategy the tablet seems to connect (see trace below)Not definitly sure that SPP protocol is fully implemented on SAMSUNG Galaxy Tab3 Lite, I have to check in and out data now and I will report to you.
Something more to note: if my tablet (client) tries to connect to early after remote board (server) power up it can be in Qt that the socket Connected Signal fires as well as Socket error signal and that the trace indicates at the same time "Service Not Found". Perhaps the SDP protocol is establihsed after the socket server at the remote side...
AGAIN : Thanks you very much for your help !
J
D/Qt ( 7868): ..\src\bttalker.cpp:83 (BtTalker::BtTalker(QObject*)): client socket prepared
D/Qt ( 7868): ..\src\bttalker.cpp:129 (void BtTalker::startClient(const QBluetoothServiceInfo&)): local adapter host mode: 1
D/Qt ( 7868): ..\src\bttalker.cpp:158 (void BtTalker::startClient(const QBluetoothServiceInfo&)): remote paired device:
D/Qt ( 7868): ..\src\bttalker.cpp:162 (void BtTalker::startClient(const QBluetoothServiceInfo&)): try to connect to "00:06:66:46:86:00" / "{00001101-0000-1000-8000-00805f9b34fb}"
D/Qt ( 7868): ..\src\bttalker.cpp:167 (void BtTalker::startClient(const QBluetoothServiceInfo&)): Socket connected to RFCOMM service