summaryrefslogtreecommitdiff
path: root/src/bluetooth
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@digia.com>2014-02-17 10:38:48 +0100
committerAlex Blasche <alexander.blasche@digia.com>2014-02-17 10:38:48 +0100
commit8fe7fbe6b552b0d196967cfea85fede5e7c211b9 (patch)
treeb90f246cc3b8847cedaf6b5f8dc045cfc563b9be /src/bluetooth
parent9bcb79f0c741f7805dad17c467a5c2041227a18a (diff)
parentb4bde05d8459cc57c25bac3f7be19fcf03908606 (diff)
downloadqtconnectivity-8fe7fbe6b552b0d196967cfea85fede5e7c211b9.tar.gz
Merge branch 'dev' into btle
Conflicts: examples/bluetooth/bluetooth.pro src/bluetooth/doc/src/examples.qdoc src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp src/bluetooth/qbluetoothservicediscoveryagent_p.h src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp Change-Id: Ie1577e4b0f469cd5a6b05a61cbe94f180a64448d
Diffstat (limited to 'src/bluetooth')
-rw-r--r--src/bluetooth/android/android.pri17
-rw-r--r--src/bluetooth/android/androidbroadcastreceiver.cpp109
-rw-r--r--src/bluetooth/android/androidbroadcastreceiver_p.h77
-rw-r--r--src/bluetooth/android/devicediscoverybroadcastreceiver.cpp132
-rw-r--r--src/bluetooth/android/devicediscoverybroadcastreceiver_p.h66
-rw-r--r--src/bluetooth/android/inputstreamthread.cpp150
-rw-r--r--src/bluetooth/android/inputstreamthread_p.h78
-rw-r--r--src/bluetooth/android/jni_android.cpp111
-rw-r--r--src/bluetooth/android/localdevicebroadcastreceiver.cpp211
-rw-r--r--src/bluetooth/android/localdevicebroadcastreceiver_p.h72
-rw-r--r--src/bluetooth/android/serveracceptancethread.cpp235
-rw-r--r--src/bluetooth/android/serveracceptancethread_p.h92
-rw-r--r--src/bluetooth/android/servicediscoverybroadcastreceiver.cpp115
-rw-r--r--src/bluetooth/android/servicediscoverybroadcastreceiver_p.h68
-rw-r--r--src/bluetooth/bluetooth.pro25
-rw-r--r--src/bluetooth/doc/qtbluetooth.qdocconf2
-rw-r--r--src/bluetooth/doc/snippets/doc_src_qtbluetooth.cpp4
-rw-r--r--src/bluetooth/doc/src/bluetooth-index.qdoc1
-rw-r--r--src/bluetooth/doc/src/examples.qdoc5
-rw-r--r--src/bluetooth/qbluetooth.cpp6
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent.cpp29
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent.h1
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp205
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp60
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp4
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_p.h27
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp27
-rw-r--r--src/bluetooth/qbluetoothdeviceinfo.cpp2
-rw-r--r--src/bluetooth/qbluetoothdeviceinfo.h2
-rw-r--r--src/bluetooth/qbluetoothlocaldevice.cpp55
-rw-r--r--src/bluetooth/qbluetoothlocaldevice.h5
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_android.cpp443
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_bluez.cpp162
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.cpp5
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.h66
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_qnx.cpp81
-rw-r--r--src/bluetooth/qbluetoothserver.cpp43
-rw-r--r--src/bluetooth/qbluetoothserver.h2
-rw-r--r--src/bluetooth/qbluetoothserver_android.cpp274
-rw-r--r--src/bluetooth/qbluetoothserver_bluez.cpp48
-rw-r--r--src/bluetooth/qbluetoothserver_p.h17
-rw-r--r--src/bluetooth/qbluetoothserver_qnx.cpp24
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent.cpp125
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent.h7
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_android.cpp513
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp135
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_p.cpp1
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_p.h28
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp77
-rw-r--r--src/bluetooth/qbluetoothserviceinfo.cpp36
-rw-r--r--src/bluetooth/qbluetoothserviceinfo.h8
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_android.cpp140
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_bluez.cpp13
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_qnx.cpp2
-rw-r--r--src/bluetooth/qbluetoothsocket.cpp143
-rw-r--r--src/bluetooth/qbluetoothsocket.h14
-rw-r--r--src/bluetooth/qbluetoothsocket_android.cpp451
-rw-r--r--src/bluetooth/qbluetoothsocket_bluez.cpp55
-rw-r--r--src/bluetooth/qbluetoothsocket_p.h35
-rw-r--r--src/bluetooth/qbluetoothsocket_qnx.cpp54
-rw-r--r--src/bluetooth/qbluetoothtransfermanager.cpp4
-rw-r--r--src/bluetooth/qbluetoothtransfermanager.h2
-rw-r--r--src/bluetooth/qbluetoothtransferreply_bluez.cpp13
-rw-r--r--src/bluetooth/qbluetoothtransferreply_qnx.cpp16
-rw-r--r--src/bluetooth/qbluetoothtransferrequest.h2
-rw-r--r--src/bluetooth/qbluetoothuuid.cpp5
-rw-r--r--src/bluetooth/qnx/ppshelpers.cpp42
-rw-r--r--src/bluetooth/qnx/ppshelpers_p.h13
68 files changed, 4633 insertions, 459 deletions
diff --git a/src/bluetooth/android/android.pri b/src/bluetooth/android/android.pri
new file mode 100644
index 00000000..3c8a0380
--- /dev/null
+++ b/src/bluetooth/android/android.pri
@@ -0,0 +1,17 @@
+PRIVATE_HEADERS += \
+ android/inputstreamthread_p.h \
+ android/devicediscoverybroadcastreceiver_p.h \
+ android/servicediscoverybroadcastreceiver_p.h \
+ android/androidbroadcastreceiver_p.h \
+ android/localdevicebroadcastreceiver_p.h \
+ android/serveracceptancethread_p.h
+
+
+SOURCES += \
+ android/inputstreamthread.cpp \
+ android/devicediscoverybroadcastreceiver.cpp \
+ android/servicediscoverybroadcastreceiver.cpp \
+ android/jni_android.cpp \
+ android/androidbroadcastreceiver.cpp \
+ android/localdevicebroadcastreceiver.cpp \
+ android/serveracceptancethread.cpp
diff --git a/src/bluetooth/android/androidbroadcastreceiver.cpp b/src/bluetooth/android/androidbroadcastreceiver.cpp
new file mode 100644
index 00000000..affa7683
--- /dev/null
+++ b/src/bluetooth/android/androidbroadcastreceiver.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <android/log.h>
+#include "android/androidbroadcastreceiver_p.h"
+#include <QtCore/QLoggingCategory>
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtGui/QGuiApplication>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+
+AndroidBroadcastReceiver::AndroidBroadcastReceiver(QObject* parent)
+ : QObject(parent), valid(false)
+{
+ //get QtActivity
+ activityObject = QAndroidJniObject(QtAndroidPrivate::activity());
+
+ broadcastReceiverObject = QAndroidJniObject("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver");
+ if (!broadcastReceiverObject.isValid())
+ return;
+ broadcastReceiverObject.setField<jlong>("qtObject", reinterpret_cast<long>(this));
+
+ intentFilterObject = QAndroidJniObject("android/content/IntentFilter");
+ if (!intentFilterObject.isValid())
+ return;
+
+ valid = true;
+}
+
+AndroidBroadcastReceiver::~AndroidBroadcastReceiver()
+{
+ unregisterReceiver();
+}
+
+bool AndroidBroadcastReceiver::isValid() const
+{
+ return valid;
+}
+
+void AndroidBroadcastReceiver::unregisterReceiver()
+{
+ if (!valid)
+ return;
+
+ activityObject.callObjectMethod(
+ "unregisterReceiver",
+ "(Landroid/content/BroadcastReceiver;)V",
+ broadcastReceiverObject.object<jobject>());
+}
+
+void AndroidBroadcastReceiver::addAction(const QString &action)
+{
+ if (!valid)
+ return;
+
+ QAndroidJniObject actionString = QAndroidJniObject::fromString(action);
+ intentFilterObject.callMethod<void>("addAction", "(Ljava/lang/String;)V", actionString.object<jstring>());
+
+ activityObject.callObjectMethod(
+ "registerReceiver",
+ "(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;",
+ broadcastReceiverObject.object<jobject>(),
+ intentFilterObject.object<jobject>());
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/android/androidbroadcastreceiver_p.h b/src/bluetooth/android/androidbroadcastreceiver_p.h
new file mode 100644
index 00000000..baae6798
--- /dev/null
+++ b/src/bluetooth/android/androidbroadcastreceiver_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JNIBROADCASTRECEIVER_H
+#define JNIBROADCASTRECEIVER_H
+#include <jni.h>
+#include <QtCore/QObject>
+#include <android/log.h>
+#include <QtAndroidExtras/QAndroidJniObject>
+
+QT_BEGIN_NAMESPACE
+
+void QtBroadcastReceiver_jniOnReceive(JNIEnv *, jobject, jlong, jobject, jobject);
+
+class AndroidBroadcastReceiver: public QObject
+{
+ Q_OBJECT
+public:
+ AndroidBroadcastReceiver(QObject* parent = 0);
+ virtual ~AndroidBroadcastReceiver();
+
+ void addAction(const QString &filter);
+ bool isValid() const;
+
+protected:
+ friend void QtBroadcastReceiver_jniOnReceive(JNIEnv *, jobject, jlong, jobject, jobject);
+ virtual void onReceive(JNIEnv *env, jobject context, jobject intent) = 0;
+
+ void unregisterReceiver();
+
+ QAndroidJniObject activityObject;
+ QAndroidJniObject intentFilterObject;
+ QAndroidJniObject broadcastReceiverObject;
+ bool valid;
+};
+
+QT_END_NAMESPACE
+#endif // JNIBROADCASTRECEIVER_H
diff --git a/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp
new file mode 100644
index 00000000..16a6afe4
--- /dev/null
+++ b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "android/devicediscoverybroadcastreceiver_p.h"
+#include <QtCore/QLoggingCategory>
+#include <QtBluetooth/QBluetoothAddress>
+#include <QtBluetooth/QBluetoothDeviceInfo>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+DeviceDiscoveryBroadcastReceiver::DeviceDiscoveryBroadcastReceiver(QObject* parent): AndroidBroadcastReceiver(parent)
+{
+ addAction(QStringLiteral("android.bluetooth.device.action.FOUND"));
+ addAction(QStringLiteral("android.bluetooth.adapter.action.DISCOVERY_STARTED"));
+ addAction(QStringLiteral("android.bluetooth.adapter.action.DISCOVERY_FINISHED"));
+}
+
+void DeviceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(env);
+
+ QAndroidJniObject intentObject(intent);
+ const QString action = intentObject.callObjectMethod("getAction", "()Ljava/lang/String;").toString();
+
+ qCDebug(QT_BT_ANDROID) << "DeviceDiscoveryBroadcastReceiver::onReceive() - event:" << action;
+
+ if (action == QStringLiteral("android.bluetooth.adapter.action.DISCOVERY_FINISHED") ) {
+ emit finished();
+ } else if (action == QStringLiteral("android.bluetooth.adapter.action.DISCOVERY_STARTED") ) {
+
+ } else if (action == QStringLiteral("android.bluetooth.device.action.FOUND")) {
+ //get BluetoothDevice
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.DEVICE"));
+ QAndroidJniObject bluetoothDevice =
+ intentObject.callObjectMethod("getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+
+ if (!bluetoothDevice.isValid())
+ return;
+
+ const QString deviceName = bluetoothDevice.callObjectMethod<jstring>("getName").toString();
+ const QBluetoothAddress deviceAddress(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.RSSI"));
+ int rssi = intentObject.callMethod<jshort>("getShortExtra",
+ "(Ljava/lang/String;S)S",
+ keyExtra.object<jstring>(),
+ 0);
+ QAndroidJniObject bluetoothClass = bluetoothDevice.callObjectMethod("getBluetoothClass",
+ "()Landroid/bluetooth/BluetoothClass;");
+ if (!bluetoothClass.isValid())
+ return;
+ int classType = bluetoothClass.callMethod<jint>("getDeviceClass");
+
+
+ static QList<qint32> services;
+ if (services.count() == 0)
+ services << QBluetoothDeviceInfo::PositioningService
+ << QBluetoothDeviceInfo::NetworkingService
+ << QBluetoothDeviceInfo::RenderingService
+ << QBluetoothDeviceInfo::CapturingService
+ << QBluetoothDeviceInfo::ObjectTransferService
+ << QBluetoothDeviceInfo::AudioService
+ << QBluetoothDeviceInfo::TelephonyService
+ << QBluetoothDeviceInfo::InformationService;
+
+ //Matching BluetoothClass.Service values
+ qint32 result = 0;
+ qint32 current = 0;
+ for (int i = 0; i < services.count(); i++) {
+ current = services.at(i);
+ int id = (current << 16);
+ if (bluetoothClass.callMethod<jboolean>("hasService", "(I)Z", id))
+ result |= current;
+ }
+
+ result = result << 13;
+ classType |= result;
+
+ QBluetoothDeviceInfo info(deviceAddress, deviceName, classType);
+ info.setRssi(rssi);
+
+ emit deviceDiscovered(info);
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h b/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h
new file mode 100644
index 00000000..6c08b22e
--- /dev/null
+++ b/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEVICEDISCOVERYBROADCASTRECEIVER_H
+#define DEVICEDISCOVERYBROADCASTRECEIVER_H
+
+#include "android/androidbroadcastreceiver_p.h"
+#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
+
+QT_BEGIN_NAMESPACE
+
+class QBluetoothDeviceInfo;
+
+class DeviceDiscoveryBroadcastReceiver : public AndroidBroadcastReceiver
+{
+ Q_OBJECT
+public:
+ DeviceDiscoveryBroadcastReceiver(QObject* parent = 0);
+ virtual void onReceive(JNIEnv *env, jobject context, jobject intent);
+
+signals:
+ void deviceDiscovered(const QBluetoothDeviceInfo &info);
+ void finished();
+};
+
+QT_END_NAMESPACE
+#endif // DEVICEDISCOVERYBROADCASTRECEIVER_H
diff --git a/src/bluetooth/android/inputstreamthread.cpp b/src/bluetooth/android/inputstreamthread.cpp
new file mode 100644
index 00000000..df32ee62
--- /dev/null
+++ b/src/bluetooth/android/inputstreamthread.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+
+#include "android/inputstreamthread_p.h"
+#include "qbluetoothsocket_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+InputStreamThread::InputStreamThread(QBluetoothSocketPrivate *socket)
+ : QThread(), m_stop(false)
+{
+ m_socket_p = socket;
+}
+
+void InputStreamThread::run()
+{
+ qint32 byte;
+ Q_UNUSED(byte)
+ while (1) {
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_stop)
+ break;
+ }
+ readFromInputStream();
+ }
+
+ QAndroidJniEnvironment env;
+ if (m_socket_p->inputStream.isValid())
+ m_socket_p->inputStream.callMethod<void>("close");
+
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+}
+
+bool InputStreamThread::bytesAvailable() const
+{
+ QMutexLocker locker(&m_mutex);
+ return m_socket_p->buffer.size();
+}
+
+//This runs inside the thread.
+void InputStreamThread::readFromInputStream()
+{
+ QAndroidJniEnvironment env;
+
+ int bufLen = 1000; // Seems to magical number that also low-end products can survive.
+ jbyteArray nativeArray = env->NewByteArray(bufLen);
+
+
+ jint ret = m_socket_p->inputStream.callMethod<jint>("read", "([BII)I", nativeArray, 0, bufLen);
+
+ if (env->ExceptionCheck() || ret < 0) {
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ env->DeleteLocalRef(nativeArray);
+ QMutexLocker lock(&m_mutex);
+ m_stop = true;
+
+ /*
+ * We cannot distinguish IOException due to valid closure or due to other error
+ * Therefore we always have to throw an error and a disconnect signal
+ * A genuine disconnect wouldn't need the error signal.
+ * For now we always signal error which implicitly emits disconnect() too.
+ */
+
+ emit error();
+ return;
+ }
+
+ if (ret == 0) {
+ qDebug() << "Nothing to read";
+ env->DeleteLocalRef(nativeArray);
+ return;
+ }
+
+ QMutexLocker lock(&m_mutex);
+ char *writePtr = m_socket_p->buffer.reserve(bufLen);
+ env->GetByteArrayRegion(nativeArray, 0, ret, reinterpret_cast<jbyte*>(writePtr));
+ env->DeleteLocalRef(nativeArray);
+ m_socket_p->buffer.chop(bufLen - ret);
+ emit dataAvailable();
+}
+
+void InputStreamThread::stop()
+{
+ QMutexLocker locker(&m_mutex);
+ m_stop = true;
+}
+
+qint64 InputStreamThread::readData(char *data, qint64 maxSize)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_stop)
+ return -1;
+
+ if (!m_socket_p->buffer.isEmpty())
+ return m_socket_p->buffer.read(data, maxSize);
+
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/android/inputstreamthread_p.h b/src/bluetooth/android/inputstreamthread_p.h
new file mode 100644
index 00000000..85852534
--- /dev/null
+++ b/src/bluetooth/android/inputstreamthread_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INPUTSTREAMTHREAD_H
+#define INPUTSTREAMTHREAD_H
+
+#include <QtCore/QThread>
+#include <QtCore/QMutex>
+
+QT_BEGIN_NAMESPACE
+
+class QBluetoothSocketPrivate;
+
+class InputStreamThread : public QThread
+{
+ Q_OBJECT
+public:
+ explicit InputStreamThread(QBluetoothSocketPrivate *socket_p);
+ virtual void run();
+
+ bool bytesAvailable() const;
+ void stop();
+
+ qint64 readData(char *data, qint64 maxSize);
+signals:
+ void dataAvailable();
+ void error();
+
+private:
+ void readFromInputStream();
+
+ QBluetoothSocketPrivate *m_socket_p;
+ mutable QMutex m_mutex;
+ bool m_stop;
+};
+
+QT_END_NAMESPACE
+
+#endif // INPUTSTREAMTHREAD_H
diff --git a/src/bluetooth/android/jni_android.cpp b/src/bluetooth/android/jni_android.cpp
new file mode 100644
index 00000000..eb1fc2dd
--- /dev/null
+++ b/src/bluetooth/android/jni_android.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <jni.h>
+#include <android/log.h>
+#include <QtCore/QLoggingCategory>
+#include <QtBluetooth/qbluetoothglobal.h>
+#include <QtAndroidExtras/QAndroidJniObject>
+#include "android/androidbroadcastreceiver_p.h"
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+void QtBroadcastReceiver_jniOnReceive(JNIEnv *env, jobject /*javaObject*/,
+ jlong qtObject, jobject context, jobject intent)
+{
+ reinterpret_cast<AndroidBroadcastReceiver*>(qtObject)->onReceive(env, context, intent);
+}
+
+static JNINativeMethod methods[] = {
+ {"jniOnReceive", "(JLandroid/content/Context;Landroid/content/Intent;)V",
+ (void *) QtBroadcastReceiver_jniOnReceive},
+};
+
+static const char logTag[] = "QtBluetooth";
+static const char classErrorMsg[] = "Can't find class \"%s\"";
+
+#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
+clazz = env->FindClass(CLASS_NAME); \
+if (!clazz) { \
+ __android_log_print(ANDROID_LOG_FATAL, logTag, classErrorMsg, CLASS_NAME); \
+ return JNI_FALSE; \
+}
+
+static bool registerNatives(JNIEnv *env)
+{
+ jclass clazz;
+ FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver");
+
+ if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives failed");
+ return false;
+ }
+
+ return true;
+}
+
+Q_BLUETOOTH_EXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
+{
+ typedef union {
+ JNIEnv *nativeEnvironment;
+ void *venv;
+ } UnionJNIEnvToVoid;
+
+ UnionJNIEnvToVoid uenv;
+ uenv.venv = 0;
+
+ if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "GetEnv failed");
+ return -1;
+ }
+
+ JNIEnv *env = uenv.nativeEnvironment;
+ if (!registerNatives(env)) {
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "registerNatives failed");
+ return -1;
+ }
+
+ if (QT_BT_ANDROID().isDebugEnabled())
+ __android_log_print(ANDROID_LOG_INFO, logTag, "Bluetooth start");
+
+ return JNI_VERSION_1_4;
+}
diff --git a/src/bluetooth/android/localdevicebroadcastreceiver.cpp b/src/bluetooth/android/localdevicebroadcastreceiver.cpp
new file mode 100644
index 00000000..0e81ef22
--- /dev/null
+++ b/src/bluetooth/android/localdevicebroadcastreceiver.cpp
@@ -0,0 +1,211 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QLoggingCategory>
+#include "localdevicebroadcastreceiver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+LocalDeviceBroadcastReceiver::LocalDeviceBroadcastReceiver(QObject *parent) :
+ AndroidBroadcastReceiver(parent), previousScanMode(0)
+{
+ addAction(QStringLiteral("android.bluetooth.device.action.BOND_STATE_CHANGED"));
+ addAction(QStringLiteral("android.bluetooth.adapter.action.SCAN_MODE_CHANGED"));
+ addAction(QStringLiteral("android.bluetooth.device.action.ACL_CONNECTED"));
+ addAction(QStringLiteral("android.bluetooth.device.action.ACL_DISCONNECTED"));
+ addAction(QStringLiteral("android.bluetooth.device.action.PAIRING_REQUEST")); //API 19
+
+}
+
+void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(env);
+
+ QAndroidJniObject intentObject(intent);
+ const QString action = intentObject.callObjectMethod("getAction", "()Ljava/lang/String;").toString();
+ qCDebug(QT_BT_ANDROID) << QStringLiteral("LocalDeviceBroadcastReceiver::onReceive() - event: %1").arg(action);
+
+ if (action == QStringLiteral("android.bluetooth.adapter.action.SCAN_MODE_CHANGED")) {
+ QAndroidJniObject extrasBundle =
+ intentObject.callObjectMethod("getExtras","()Landroid/os/Bundle;");
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.adapter.extra.SCAN_MODE"));
+
+ int extra = extrasBundle.callMethod<jint>("getInt",
+ "(Ljava/lang/String;)I",
+ keyExtra.object<jstring>());
+
+ if (previousScanMode != extra) {
+ previousScanMode = extra;
+
+ switch (extra) {
+ case 20: //BluetoothAdapter.SCAN_MODE_NONE
+ emit hostModeStateChanged(QBluetoothLocalDevice::HostPoweredOff);
+ break;
+ case 21: //BluetoothAdapter.SCAN_MODE_CONNECTABLE
+ emit hostModeStateChanged(QBluetoothLocalDevice::HostConnectable);
+ break;
+ case 23: //BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
+ emit hostModeStateChanged(QBluetoothLocalDevice::HostDiscoverable);
+ break;
+ default:
+ qCWarning(QT_BT_ANDROID) << "Unknown Host State";
+ break;
+ }
+ }
+ } else if (action == QStringLiteral("android.bluetooth.device.action.BOND_STATE_CHANGED")) {
+ //get BluetoothDevice
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.DEVICE"));
+ QAndroidJniObject bluetoothDevice =
+ intentObject.callObjectMethod("getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+
+ //get new bond state
+ keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.BOND_STATE"));
+ QAndroidJniObject extrasBundle =
+ intentObject.callObjectMethod("getExtras","()Landroid/os/Bundle;");
+ int bondState = extrasBundle.callMethod<jint>("getInt",
+ "(Ljava/lang/String;)I",
+ keyExtra.object<jstring>());
+
+ QBluetoothAddress address(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ if (address.isNull())
+ return;
+
+ switch (bondState) {
+ case 10: //BluetoothDevice.BOND_NONE
+ emit pairingStateChanged(address, QBluetoothLocalDevice::Unpaired);
+ break;
+ case 11: //BluetoothDevice.BOND_BONDING
+ //we ignore this as Qt doesn't have equivalent API.
+ break;
+ case 12: //BluetoothDevice.BOND_BONDED
+ emit pairingStateChanged(address, QBluetoothLocalDevice::Paired);
+ break;
+ default:
+ qCWarning(QT_BT_ANDROID) << "Unknown BOND_STATE_CHANGED value:" << bondState;
+ break;
+ }
+ } else if (action == QStringLiteral("android.bluetooth.device.action.ACL_DISCONNECTED") ||
+ action == QStringLiteral("android.bluetooth.device.action.ACL_CONNECTED")) {
+
+ const bool isConnectEvent =
+ action == QStringLiteral("android.bluetooth.device.action.ACL_CONNECTED") ? true : false;
+
+ //get BluetoothDevice
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.DEVICE"));
+ QAndroidJniObject bluetoothDevice =
+ intentObject.callObjectMethod("getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+
+ QBluetoothAddress address(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ if (address.isNull())
+ return;
+
+ emit connectDeviceChanges(address, isConnectEvent);
+ } else if (action == QStringLiteral("android.bluetooth.device.action.PAIRING_REQUEST")) {
+
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.PAIRING_VARIANT"));
+ int variant = intentObject.callMethod<jint>("getIntExtra",
+ "(Ljava/lang/String;I)I",
+ keyExtra.object<jstring>(),
+ -1);
+
+ int key = -1;
+ switch (variant) {
+ case -1: //ignore -> no pairing variant set
+ return;
+ case 2: //BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION
+ {
+ keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.PAIRING_KEY"));
+ key = intentObject.callMethod<jint>("getIntExtra",
+ "(Ljava/lang/String;I)I",
+ keyExtra.object<jstring>(),
+ -1);
+ if (key == -1)
+ return;
+
+ keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.DEVICE"));
+ QAndroidJniObject bluetoothDevice =
+ intentObject.callObjectMethod("getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+
+ //we need to keep a reference around in case the user confirms later on
+ pairingDevice = bluetoothDevice;
+
+ QBluetoothAddress address(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+
+ //User has choice to confirm or not. If no confirmation is happening
+ //the OS default pairing dialog can be used or timeout occurs.
+ emit pairingDisplayConfirmation(address, QString::number(key));
+ break;
+ }
+ default:
+ qCWarning(QT_BT_ANDROID) << "Unknown pairing variant: " << variant;
+ return;
+ }
+ }
+}
+
+bool LocalDeviceBroadcastReceiver::pairingConfirmation(bool accept)
+{
+ if (!pairingDevice.isValid())
+ return false;
+
+ bool success = pairingDevice.callMethod<jboolean>("setPairingConfirmation",
+ "(Z)Z", accept);
+ pairingDevice = QAndroidJniObject();
+ return success;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/android/localdevicebroadcastreceiver_p.h b/src/bluetooth/android/localdevicebroadcastreceiver_p.h
new file mode 100644
index 00000000..ddd65d92
--- /dev/null
+++ b/src/bluetooth/android/localdevicebroadcastreceiver_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "android/androidbroadcastreceiver_p.h"
+#include <QtBluetooth/QBluetoothAddress>
+#include <QtBluetooth/QBluetoothLocalDevice>
+
+#ifndef LOCALDEVICEBROADCASTRECEIVER_H
+#define LOCALDEVICEBROADCASTRECEIVER_H
+
+QT_BEGIN_NAMESPACE
+
+class LocalDeviceBroadcastReceiver : public AndroidBroadcastReceiver
+{
+ Q_OBJECT
+public:
+ explicit LocalDeviceBroadcastReceiver(QObject *parent = 0);
+ virtual ~LocalDeviceBroadcastReceiver() {}
+ virtual void onReceive(JNIEnv *env, jobject context, jobject intent);
+ bool pairingConfirmation(bool accept);
+
+signals:
+ void hostModeStateChanged(QBluetoothLocalDevice::HostMode state);
+ void pairingStateChanged(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
+ void connectDeviceChanges(const QBluetoothAddress &address, bool isConnectEvent);
+ void pairingDisplayConfirmation(const QBluetoothAddress &address, const QString& pin);
+private:
+ int previousScanMode;
+ QAndroidJniObject pairingDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif // LOCALDEVICEBROADCASTRECEIVER_H
diff --git a/src/bluetooth/android/serveracceptancethread.cpp b/src/bluetooth/android/serveracceptancethread.cpp
new file mode 100644
index 00000000..88a92478
--- /dev/null
+++ b/src/bluetooth/android/serveracceptancethread.cpp
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QLoggingCategory>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+
+#include "android/serveracceptancethread_p.h"
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+ServerAcceptanceThread::ServerAcceptanceThread(QObject *parent) :
+ QThread(parent), m_stop(false), maxPendingConnections(1)
+{
+ btAdapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
+ "getDefaultAdapter",
+ "()Landroid/bluetooth/BluetoothAdapter;");
+}
+
+ServerAcceptanceThread::~ServerAcceptanceThread()
+{
+ Q_ASSERT(!isRunning());
+ QMutexLocker lock(&m_mutex);
+ shutdownPendingConnections();
+}
+
+void ServerAcceptanceThread::setServiceDetails(const QBluetoothUuid &uuid,
+ const QString &serviceName,
+ QBluetooth::SecurityFlags securityFlags)
+{
+ QMutexLocker lock(&m_mutex);
+ m_uuid = uuid;
+ m_serviceName = serviceName;
+ secFlags = securityFlags;
+}
+
+void ServerAcceptanceThread::run()
+{
+ m_mutex.lock();
+
+ qCDebug(QT_BT_ANDROID) << "Starting ServerSocketAccept thread";
+ if (!validSetup()) {
+ qCWarning(QT_BT_ANDROID) << "Invalid Server Socket setup";
+ m_mutex.unlock();
+ return;
+ }
+
+ shutdownPendingConnections();
+
+ m_stop = false;
+
+ QString tempUuid = m_uuid.toString();
+ tempUuid.chop(1); //remove trailing '}'
+ tempUuid.remove(0,1); //remove first '{'
+
+ QAndroidJniEnvironment env;
+ QAndroidJniObject inputString = QAndroidJniObject::fromString(tempUuid);
+ QAndroidJniObject uuidObject = QAndroidJniObject::callStaticObjectMethod(
+ "java/util/UUID", "fromString",
+ "(Ljava/lang/String;)Ljava/util/UUID;",
+ inputString.object<jstring>());
+ inputString = QAndroidJniObject::fromString(m_serviceName);
+ if (((int)secFlags) == 0) { //no form of security flag set
+ qCDebug(QT_BT_ANDROID) << "InSecure listening";
+ btServerSocket = btAdapter.callObjectMethod("listenUsingInsecureRfcommWithServiceRecord",
+ "(Ljava/lang/String;Ljava/util/UUID;)Landroid/bluetooth/BluetoothServerSocket;",
+ inputString.object<jstring>(),
+ uuidObject.object<jobject>());
+ } else {
+ qCDebug(QT_BT_ANDROID) << "Secure listening";
+ btServerSocket = btAdapter.callObjectMethod("listenUsingRfcommWithServiceRecord",
+ "(Ljava/lang/String;Ljava/util/UUID;)Landroid/bluetooth/BluetoothServerSocket;",
+ inputString.object<jstring>(),
+ uuidObject.object<jobject>());
+ }
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ qCWarning(QT_BT_ANDROID) << "Cannot setup rfcomm socket listener";
+ m_mutex.unlock();
+ return;
+ }
+
+ if (!btServerSocket.isValid()) {
+ qCWarning(QT_BT_ANDROID) << "Invalid BluetoothServerSocket";
+ m_mutex.unlock();
+ return;
+ }
+
+ while (!m_stop) {
+ m_mutex.unlock();
+
+ qCDebug(QT_BT_ANDROID) << "Waiting for new incoming socket";
+ QAndroidJniEnvironment env;
+
+ //this call blocks until we see an incoming connection
+ QAndroidJniObject socket = btServerSocket.callObjectMethod("accept",
+ "()Landroid/bluetooth/BluetoothSocket;");
+
+ qCDebug(QT_BT_ANDROID) << "New socket accepted: ->" << socket.isValid();
+ bool exceptionOccurred = false;
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ exceptionOccurred = true;
+ }
+
+ m_mutex.lock();
+
+ if (exceptionOccurred || m_stop) {
+ //if m_stop is true there is nothing really to be done but exit
+ m_stop = true;
+ } else if (socket.isValid()){
+ if (pendingSockets.count() < maxPendingConnections) {
+ pendingSockets.append(socket);
+ emit newConnection();
+ } else {
+ qCWarning(QT_BT_ANDROID) << "Refusing connection due to limited pending socket queue";
+ socket.callMethod<void>("close");
+ if (env->ExceptionCheck()) {
+ qCWarning(QT_BT_ANDROID) << "Error during refusal of new socket";
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+
+ }
+ } else {
+ //should never happen as invalid socket should cause exception
+ qCWarning(QT_BT_ANDROID) << "Invalid state during server socket accept";
+ }
+ }
+
+ m_uuid = QBluetoothUuid();
+ m_serviceName = QString();
+ btServerSocket = QAndroidJniObject();
+ m_mutex.unlock();
+}
+
+void ServerAcceptanceThread::stop()
+{
+ QMutexLocker lock(&m_mutex);
+ m_stop = true;
+
+ QAndroidJniEnvironment env;
+ if (btServerSocket.isValid()) {
+ qCDebug(QT_BT_ANDROID) << "Closing server socket";
+ btServerSocket.callMethod<void>("close");
+ if (env->ExceptionCheck()) {
+ qCWarning(QT_BT_ANDROID) << "Exception during closure of server socket";
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ qCDebug(QT_BT_ANDROID) << "Closing server socket111";
+ }
+}
+
+bool ServerAcceptanceThread::hasPendingConnections() const
+{
+ QMutexLocker lock(&m_mutex);
+ return (pendingSockets.count() > 0);
+}
+
+/*
+ * Returns the next pending connection or an invalid JNI object.
+ * Note that even a stopped thread may still have pending
+ * connections. Pending connections are only terminated upon
+ * thread restart or destruction.
+ */
+QAndroidJniObject ServerAcceptanceThread::nextPendingConnection()
+{
+ QMutexLocker lock(&m_mutex);
+ if (pendingSockets.isEmpty())
+ return QAndroidJniObject();
+ else
+ return pendingSockets.takeFirst();
+}
+
+void ServerAcceptanceThread::setMaxPendingConnections(int maximumCount)
+{
+ QMutexLocker lock(&m_mutex);
+ maxPendingConnections = maximumCount;
+}
+
+//must be run inside the lock but doesn't lock by itself
+bool ServerAcceptanceThread::validSetup() const
+{
+ return (!m_uuid.isNull() && !m_serviceName.isEmpty());
+}
+
+//must be run inside the lock but doesn't lock by itself
+void ServerAcceptanceThread::shutdownPendingConnections()
+{
+ while (!pendingSockets.isEmpty()) {
+ QAndroidJniObject socket = pendingSockets.takeFirst();
+ socket.callMethod<void>("close");
+ }
+}
diff --git a/src/bluetooth/android/serveracceptancethread_p.h b/src/bluetooth/android/serveracceptancethread_p.h
new file mode 100644
index 00000000..1297e48f
--- /dev/null
+++ b/src/bluetooth/android/serveracceptancethread_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERVERACCEPTANCETHREAD_H
+#define SERVERACCEPTANCETHREAD_H
+
+#include <QtCore/QMutex>
+#include <QtCore/QThread>
+#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtBluetooth/QBluetoothUuid>
+#include "qbluetooth.h"
+
+
+class ServerAcceptanceThread : public QThread
+{
+ Q_OBJECT
+public:
+ enum AndroidError {
+ AndroidNoError
+ };
+
+ explicit ServerAcceptanceThread(QObject *parent = 0);
+ ~ServerAcceptanceThread();
+ void setServiceDetails(const QBluetoothUuid &uuid, const QString &serviceName,
+ QBluetooth::SecurityFlags securityFlags);
+ virtual void run();
+
+ void stop();
+ bool hasPendingConnections() const;
+ QAndroidJniObject nextPendingConnection();
+ void setMaxPendingConnections(int maximumCount);
+
+signals:
+ void newConnection();
+ void error(ServerAcceptanceThread::AndroidError);
+
+private:
+ bool validSetup() const;
+ void shutdownPendingConnections();
+
+ QList<QAndroidJniObject> pendingSockets;
+ QAndroidJniObject btAdapter;
+ QAndroidJniObject btServerSocket;
+ mutable QMutex m_mutex;
+ QString m_serviceName;
+ QBluetoothUuid m_uuid;
+ bool m_stop;
+ AndroidError lastError;
+ int maxPendingConnections;
+ QBluetooth::SecurityFlags secFlags;
+
+};
+
+#endif // SERVERACCEPTANCETHREAD_H
diff --git a/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp b/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp
new file mode 100644
index 00000000..341617bc
--- /dev/null
+++ b/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "android/servicediscoverybroadcastreceiver_p.h"
+#include <QtCore/QLoggingCategory>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtBluetooth/QBluetoothAddress>
+#include <QtBluetooth/QBluetoothDeviceInfo>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+ServiceDiscoveryBroadcastReceiver::ServiceDiscoveryBroadcastReceiver(QObject* parent): AndroidBroadcastReceiver(parent)
+{
+ addAction(QStringLiteral("android.bluetooth.device.action.UUID"));
+}
+
+void ServiceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(env);
+
+ QAndroidJniObject intentObject(intent);
+ const QString action = intentObject.callObjectMethod("getAction", "()Ljava/lang/String;").toString();
+
+ qCDebug(QT_BT_ANDROID) << "ServiceDiscoveryBroadcastReceiver::onReceive() - event:" << action;
+
+ if (action == QStringLiteral("android.bluetooth.device.action.UUID")) {
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.UUID"));
+ QAndroidJniObject parcelableUuids = intentObject.callObjectMethod(
+ "getParcelableArrayExtra",
+ "(Ljava/lang/String;)[Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+ if (!parcelableUuids.isValid())
+ return;
+ QList<QBluetoothUuid> result = ServiceDiscoveryBroadcastReceiver::convertParcelableArray(parcelableUuids);
+
+ keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.DEVICE"));
+ QAndroidJniObject bluetoothDevice =
+ intentObject.callObjectMethod("getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+ QBluetoothAddress address;
+ if (bluetoothDevice.isValid()) {
+ address = QBluetoothAddress(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ emit uuidFetchFinished(address, result);
+ }
+ }
+}
+
+QList<QBluetoothUuid> ServiceDiscoveryBroadcastReceiver::convertParcelableArray(const QAndroidJniObject &parcelUuidArray)
+{
+ QList<QBluetoothUuid> result;
+ QAndroidJniEnvironment env;
+ QAndroidJniObject p;
+
+ jobjectArray parcels = parcelUuidArray.object<jobjectArray>();
+ if (!parcels)
+ return result;
+
+ jint size = env->GetArrayLength(parcels);
+ for (int i = 0; i < size; i++) {
+ p = env->GetObjectArrayElement(parcels, i);
+
+ QBluetoothUuid uuid(p.callObjectMethod<jstring>("toString").toString());
+ //qCDebug(QT_BT_ANDROID) << uuid.toString();
+ result.append(uuid);
+ }
+
+ return result;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h b/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h
new file mode 100644
index 00000000..e75095e8
--- /dev/null
+++ b/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERVICEDISCOVERYBROADCASTRECEIVER_H
+#define SERVICEDISCOVERYBROADCASTRECEIVER_H
+
+#include "android/androidbroadcastreceiver_p.h"
+#include <QtCore/QList>
+#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
+#include <QtBluetooth/QBluetoothUuid>
+
+QT_BEGIN_NAMESPACE
+
+class QBluetoothDeviceInfo;
+
+class ServiceDiscoveryBroadcastReceiver : public AndroidBroadcastReceiver
+{
+ Q_OBJECT
+public:
+ ServiceDiscoveryBroadcastReceiver(QObject* parent = 0);
+ virtual void onReceive(JNIEnv *env, jobject context, jobject intent);
+
+ static QList<QBluetoothUuid> convertParcelableArray(const QAndroidJniObject &obj);
+
+signals:
+ void uuidFetchFinished(const QBluetoothAddress &addr, const QList<QBluetoothUuid> &serviceUuid);
+};
+
+QT_END_NAMESPACE
+#endif // SERVICEDISCOVERYBROADCASTRECEIVER_H
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro
index 69f4b6f8..e5f03db0 100644
--- a/src/bluetooth/bluetooth.pro
+++ b/src/bluetooth/bluetooth.pro
@@ -89,8 +89,8 @@ config_bluez:qtHaveModule(dbus) {
qlowenergyserviceinfo_bluez.cpp \
qlowenergycharacteristicinfo_bluez.cpp
-} else:qnx{
- DEFINES += QT_QNX_BLUETOOTH #BT_BBPPSDEBUG
+} else:CONFIG(blackberry) {
+ DEFINES += QT_QNX_BLUETOOTH
include(qnx/qnx.pri)
@@ -114,6 +114,27 @@ config_bluez:qtHaveModule(dbus) {
qlowenergyserviceinfo_qnx.cpp \
qlowenergyprocess_qnx.cpp
+} else:android:!android-no-sdk {
+ include(android/android.pri)
+ DEFINES += QT_ANDROID_BLUETOOTH
+ QT += core-private androidextras
+
+ ANDROID_PERMISSIONS = \
+ android.permission.BLUETOOTH \
+ android.permission.BLUETOOTH_ADMIN
+ ANDROID_BUNDLED_JAR_DEPENDENCIES = \
+ jar/QtAndroidBluetooth-bundled.jar:org.qtproject.qt5.android.bluetooth.QtBluetoothBroadcastReceiver
+ ANDROID_JAR_DEPENDENCIES = \
+ jar/QtAndroidBluetooth.jar:org.qtproject.qt5.android.bluetooth.QtBluetoothBroadcastReceiver
+
+ SOURCES += \
+ qbluetoothdevicediscoveryagent_android.cpp \
+ qbluetoothlocaldevice_android.cpp \
+ qbluetoothserviceinfo_android.cpp \
+ qbluetoothservicediscoveryagent_android.cpp \
+ qbluetoothsocket_android.cpp \
+ qbluetoothserver_android.cpp
+
} else {
message("Unsupported bluetooth platform, will not build a working QBluetooth library")
message("Either no Qt dBus found or no Bluez headers")
diff --git a/src/bluetooth/doc/qtbluetooth.qdocconf b/src/bluetooth/doc/qtbluetooth.qdocconf
index 45c0d3b4..36e8cb6f 100644
--- a/src/bluetooth/doc/qtbluetooth.qdocconf
+++ b/src/bluetooth/doc/qtbluetooth.qdocconf
@@ -2,7 +2,7 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
project = QtBluetooth
description = Qt Bluetooth Reference Documentation
-url = http://qt-project.org/doc/qt-$QT_VER/qtbluetooth
+url = http://qt-project.org/doc/qt-$QT_VER
version = $QT_VERSION
examplesinstallpath = bluetooth
diff --git a/src/bluetooth/doc/snippets/doc_src_qtbluetooth.cpp b/src/bluetooth/doc/snippets/doc_src_qtbluetooth.cpp
index 6d160f52..56459e72 100644
--- a/src/bluetooth/doc/snippets/doc_src_qtbluetooth.cpp
+++ b/src/bluetooth/doc/snippets/doc_src_qtbluetooth.cpp
@@ -67,8 +67,8 @@ if (localDevice.isValid()) {
//! [discovery]
// Create a discovery agent and connect to its signals
QBluetoothDiscoveryAgent *discoveryAgent = new QBluetoothDiscoveryAgent(this);
-connect(discoveryAgent, SIGNAL(deviceDiscovered(const QBluetoothDeviceInfo&)),
- this, SLOT(deviceDiscovered(const QBluetoothDeviceInfo&)));
+connect(discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
+ this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
// Start a discovery
discoveryAgent->start();
diff --git a/src/bluetooth/doc/src/bluetooth-index.qdoc b/src/bluetooth/doc/src/bluetooth-index.qdoc
index ff1651d0..77575994 100644
--- a/src/bluetooth/doc/src/bluetooth-index.qdoc
+++ b/src/bluetooth/doc/src/bluetooth-index.qdoc
@@ -68,6 +68,7 @@ import statement in your \c .qml file:
\li QML
\list
\li \l {scanner}{QML Bluetooth Scanner}
+ \li \l {picturetransfer}{QML Bluetooth Picture Push}
\endlist
\li C++
\list
diff --git a/src/bluetooth/doc/src/examples.qdoc b/src/bluetooth/doc/src/examples.qdoc
index b7ad5df3..11e38d36 100644
--- a/src/bluetooth/doc/src/examples.qdoc
+++ b/src/bluetooth/doc/src/examples.qdoc
@@ -66,9 +66,12 @@
\li The tennis game using a QML interface to the Bluetooth API. It
must connect to an instance of the C++ \l{bttennis}{Bluetooth Tennis} game to play.
\row
- \li \l{btscanner}{QML Bluetooth Scanner}
+ \li \l{scanner}{QML Bluetooth Scanner}
\li A QML implementation of the Bluetooth device scanner.
\row
+ \li \l{picturetransfer}{QML Picture Push Example}
+ \li A QML application that transfers pictures between Bluetooth devices.
+ \row
\li \l{lowenergyscanner}{QML Bluetooth Low Energy Scanner}
\li Scan for Bluetooth Low Energy devices, services and characteristics.
\endtable
diff --git a/src/bluetooth/qbluetooth.cpp b/src/bluetooth/qbluetooth.cpp
index 02ca7636..4ba14dba 100644
--- a/src/bluetooth/qbluetooth.cpp
+++ b/src/bluetooth/qbluetooth.cpp
@@ -39,6 +39,7 @@
**
****************************************************************************/
+#include <QtCore/QLoggingCategory>
#include <QtBluetooth/qbluetooth.h>
QT_BEGIN_NAMESPACE
@@ -76,4 +77,9 @@ namespace QBluetooth {
*/
}
+Q_LOGGING_CATEGORY(QT_BT, "qt.bluetooth")
+Q_LOGGING_CATEGORY(QT_BT_ANDROID, "qt.bluetooth.android")
+Q_LOGGING_CATEGORY(QT_BT_BLUEZ, "qt.bluetooth.bluez")
+Q_LOGGING_CATEGORY(QT_BT_QNX, "qt.bluetooth.qnx")
+
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
index 57136a65..eeac8f11 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
@@ -38,6 +38,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+#include "qbluetoothhostinfo.h"
#include "qbluetoothdevicediscoveryagent.h"
#include "qbluetoothdevicediscoveryagent_p.h"
@@ -71,6 +72,8 @@ QT_BEGIN_NAMESPACE
\value NoError No error has occurred.
\value PoweredOffError The Bluetooth adaptor is powered off, power it on before doing discovery.
\value InputOutputError Writing or reading from the device resulted in an error.
+ \value InvalidBluetoothAdapterError The passed local adapter address does not match the physical
+ adapter address of any local Bluetooth device.
\value UnknownError An unknown error has occurred.
*/
@@ -102,12 +105,14 @@ QT_BEGIN_NAMESPACE
\fn void QBluetoothDeviceDiscoveryAgent::finished()
This signal is emitted when Bluetooth device discovery completes.
+ The signal is not going to be emitted if the device discovery finishes with an error.
*/
/*!
\fn void QBluetoothDeviceDiscoveryAgent::error(QBluetoothDeviceDiscoveryAgent::Error error)
This signal is emitted when an \a error occurs during Bluetooth device discovery.
+ The \a error parameter describes the error that occurred.
\sa error(), errorString()
*/
@@ -134,14 +139,30 @@ QBluetoothDeviceDiscoveryAgent::QBluetoothDeviceDiscoveryAgent(QObject *parent)
}
/*!
- Constructs a new Bluetooth device discovery agent with parent \a parent and uses the adapter \a deviceAdapter
- for the device search. If \a deviceAdapter is default constructed the resulting
+ Constructs a new Bluetooth device discovery agent with \a parent.
+
+ It uses \a deviceAdapter for the device search. If \a deviceAdapter is default constructed the resulting
QBluetoothDeviceDiscoveryAgent object will use the local default Bluetooth adapter.
+
+ If a \a deviceAdapter is specified that is not a local adapter \l error() will be set to
+ \l InvalidBluetoothAdapterError. Therefore it is recommended to test the error flag immediately after
+ using this constructor.
+
+ \sa error()
*/
QBluetoothDeviceDiscoveryAgent::QBluetoothDeviceDiscoveryAgent(const QBluetoothAddress &deviceAdapter, QObject *parent)
: QObject(parent), d_ptr(new QBluetoothDeviceDiscoveryAgentPrivate(deviceAdapter))
{
d_ptr->q_ptr = this;
+ if (!deviceAdapter.isNull()) {
+ const QList<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices();
+ foreach (const QBluetoothHostInfo &hostInfo, localDevices) {
+ if (hostInfo.address() == deviceAdapter)
+ return;
+ }
+ d_ptr->lastError = InvalidBluetoothAdapterError;
+ d_ptr->errorString = tr("Invalid Bluetooth adapter address");
+ }
}
/*!
@@ -194,7 +215,7 @@ QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices()
void QBluetoothDeviceDiscoveryAgent::start()
{
Q_D(QBluetoothDeviceDiscoveryAgent);
- if (!isActive())
+ if (!isActive() && d->lastError != InvalidBluetoothAdapterError)
d->start();
}
@@ -207,7 +228,7 @@ void QBluetoothDeviceDiscoveryAgent::start()
void QBluetoothDeviceDiscoveryAgent::stop()
{
Q_D(QBluetoothDeviceDiscoveryAgent);
- if (isActive())
+ if (isActive() && d->lastError != InvalidBluetoothAdapterError)
d->stop();
}
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent.h b/src/bluetooth/qbluetoothdevicediscoveryagent.h
index a311d14f..4ac1685e 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent.h
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent.h
@@ -66,6 +66,7 @@ public:
NoError,
InputOutputError,
PoweredOffError,
+ InvalidBluetoothAdapterError,
UnknownError = 100 //New errors must be added before Unknown error
};
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
new file mode 100644
index 00000000..c2e1792d
--- /dev/null
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothdevicediscoveryagent_p.h"
+#include <QtCore/QLoggingCategory>
+#include <QtBluetooth/QBluetoothAddress>
+#include <QtBluetooth/QBluetoothDeviceInfo>
+#include "android/devicediscoverybroadcastreceiver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
+ const QBluetoothAddress &deviceAdapter)
+ : inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry),
+ lastError(QBluetoothDeviceDiscoveryAgent::NoError), errorString(QStringLiteral()),
+ receiver(0),
+ m_adapterAddress(deviceAdapter),
+ m_active(false),
+ pendingCancel(false),
+ pendingStart(false)
+{
+ adapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
+ "getDefaultAdapter",
+ "()Landroid/bluetooth/BluetoothAdapter;");
+}
+
+QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
+{
+ if (m_active)
+ stop();
+
+ delete receiver;
+}
+
+bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
+{
+ if (pendingStart)
+ return true;
+ if (pendingCancel)
+ return false;
+ return m_active;
+}
+
+void QBluetoothDeviceDiscoveryAgentPrivate::start()
+{
+ if (pendingCancel) {
+ pendingStart = true;
+ return;
+ }
+
+ Q_Q(QBluetoothDeviceDiscoveryAgent);
+
+ if (!adapter.isValid()) {
+ qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
+ lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Device does not support Bluetooth");
+ emit q->error(lastError);
+ return;
+ }
+
+ if (!m_adapterAddress.isNull() &&
+ adapter.callObjectMethod<jstring>("getAddress").toString() != m_adapterAddress.toString()) {
+ qCWarning(QT_BT_ANDROID) << "Incorrect local adapter passed.";
+ lastError = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Passed address is not a local device.");
+ emit q->error(lastError);
+ return;
+ }
+
+ const int state = adapter.callMethod<jint>("getState");
+ if (state != 12 ) { //BluetoothAdapter.STATE_ON
+ lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Device is powered off");
+ emit q->error(lastError);
+ return;
+ }
+
+ //install Java BroadcastReceiver
+ if (!receiver) {
+ receiver = new DeviceDiscoveryBroadcastReceiver();
+ qRegisterMetaType<QBluetoothDeviceInfo>("QBluetoothDeviceInfo");
+ QObject::connect(receiver, SIGNAL(deviceDiscovered(const QBluetoothDeviceInfo&)),
+ this, SLOT(processDiscoveredDevices(const QBluetoothDeviceInfo&)));
+ QObject::connect(receiver, SIGNAL(finished()), this, SLOT(processDiscoveryFinished()));
+ }
+
+ discoveredDevices.clear();
+
+ const bool success = adapter.callMethod<jboolean>("startDiscovery");
+ if (!success) {
+ lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Discovery cannot be started");
+ emit q->error(lastError);
+ return;
+ }
+
+ m_active = true;
+
+ qCDebug(QT_BT_ANDROID) << "QBluetoothDeviceDiscoveryAgentPrivate::start() - successfully executed.";
+}
+
+void QBluetoothDeviceDiscoveryAgentPrivate::stop()
+{
+ Q_Q(QBluetoothDeviceDiscoveryAgent);
+
+ if (!m_active)
+ return;
+
+ pendingCancel = true;
+ pendingStart = false;
+ bool success = adapter.callMethod<jboolean>("cancelDiscovery");
+ if (!success) {
+ lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Discovery cannot be stopped");
+ emit q->error(lastError);
+ return;
+ }
+}
+
+void QBluetoothDeviceDiscoveryAgentPrivate::processDiscoveryFinished()
+{
+ //We need to guard because Android sends two DISCOVERY_FINISHED when cancelling
+ //Also if we have two active agents both receive the same signal.
+ //If this one is not active ignore the device information
+ if (!m_active)
+ return;
+
+ m_active = false;
+
+ Q_Q(QBluetoothDeviceDiscoveryAgent);
+
+ if (pendingCancel && !pendingStart) {
+ emit q->canceled();
+ pendingCancel = false;
+ } else if (pendingStart) {
+ pendingStart = pendingCancel = false;
+ start();
+ } else {
+ //check that it didn't finish due to turned off Bluetooth Device
+ const int state = adapter.callMethod<jint>("getState");
+ if (state != 12 ) { //BluetoothAdapter.STATE_ON
+ lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Device is powered off");
+ emit q->error(lastError);
+ return;
+ }
+ emit q->finished();
+ }
+}
+
+void QBluetoothDeviceDiscoveryAgentPrivate::processDiscoveredDevices(const QBluetoothDeviceInfo &info)
+{
+ //If we have two active agents both receive the same signal.
+ // If this one is not active ignore the device information
+ if (!m_active)
+ return;
+
+ Q_Q(QBluetoothDeviceDiscoveryAgent);
+
+ discoveredDevices.append(info);
+ qCDebug(QT_BT_ANDROID) << "Device found: " << info.name() << info.address().toString();
+ emit q->deviceDiscovered(info);
+}
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
index 017f8410..f866b477 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
@@ -39,6 +39,7 @@
**
****************************************************************************/
+#include <QtCore/QLoggingCategory>
#include "qbluetoothdevicediscoveryagent.h"
#include "qbluetoothdevicediscoveryagent_p.h"
#include "qbluetoothaddress.h"
@@ -48,10 +49,10 @@
#include "bluez/adapter_p.h"
#include "bluez/device_p.h"
-//#define QT_DEVICEDISCOVERY_DEBUG
-
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter)
: lastError(QBluetoothDeviceDiscoveryAgent::NoError), m_adapterAddress(deviceAdapter), pendingCancel(false), pendingStart(false),
adapter(0)
@@ -64,6 +65,7 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(con
QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
{
delete manager;
+ delete adapter;
}
bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
@@ -94,9 +96,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start()
if (reply.isError()) {
errorString = reply.error().message();
-#ifdef QT_DEVICEDISCOVERY_DEBUG
- qDebug() << Q_FUNC_INFO << "ERROR: " << errorString;
-#endif
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "ERROR: " << errorString;
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
Q_Q(QBluetoothDeviceDiscoveryAgent);
emit q->error(lastError);
@@ -116,11 +116,23 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start()
propertiesReply.waitForFinished();
if(propertiesReply.isError()) {
errorString = propertiesReply.error().message();
-#ifdef QT_DEVICEDISCOVERY_DEBUG
- qDebug() << Q_FUNC_INFO << "ERROR: " << errorString;
-#endif
+ delete adapter;
+ adapter = 0;
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "ERROR: " << errorString;
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
Q_Q(QBluetoothDeviceDiscoveryAgent);
+ delete adapter;
+ adapter = 0;
+ emit q->error(lastError);
+ return;
+ }
+
+ if (!propertiesReply.value().value(QStringLiteral("Powered")).toBool()) {
+ qCDebug(QT_BT_BLUEZ) << "Aborting device discovery due to offline Bluetooth Adapter";
+ lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Device is powered off");
+ delete adapter;
+ adapter = 0;
emit q->error(lastError);
return;
}
@@ -133,9 +145,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start()
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
Q_Q(QBluetoothDeviceDiscoveryAgent);
emit q->error(lastError);
-#ifdef QT_DEVICEDISCOVERY_DEBUG
- qDebug() << Q_FUNC_INFO << "ERROR: " << errorString;
-#endif
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "ERROR: " << errorString;
return;
}
}
@@ -143,9 +153,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start()
void QBluetoothDeviceDiscoveryAgentPrivate::stop()
{
if (adapter) {
-#ifdef QT_DEVICEDISCOVERY_DEBUG
- qDebug() << Q_FUNC_INFO;
-#endif
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO;
pendingCancel = true;
pendingStart = false;
QDBusPendingReply<> reply = adapter->StopDiscovery();
@@ -158,15 +166,13 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_deviceFound(const QString &addres
{
const QBluetoothAddress btAddress(address);
const QString btName = dict.value(QLatin1String("Name")).toString();
- quint32 btClass = dict.value(QLatin1String("Class")).toUInt();
+ quint32 btClass = dict.value(QLatin1String("Class")).toUInt();
-#ifdef QT_DEVICEDISCOVERY_DEBUG
- qDebug() << "Discovered: " << address << btName
+ qCDebug(QT_BT_BLUEZ) << "Discovered: " << address << btName
<< "Num UUIDs" << dict.value(QLatin1String("UUIDs")).toStringList().count()
<< "total device" << discoveredDevices.count() << "cached"
<< dict.value(QLatin1String("Cached")).toBool()
<< "RSSI" << dict.value(QLatin1String("RSSI")).toInt();
-#endif
QBluetoothDeviceInfo device(btAddress, btName, btClass);
if(dict.value(QLatin1String("RSSI")).isValid())
@@ -190,24 +196,18 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_deviceFound(const QString &addres
for(int i = 0; i < discoveredDevices.size(); i++){
if(discoveredDevices[i].address() == device.address()) {
if(discoveredDevices[i] == device) {
-#ifdef QT_DEVICEDISCOVERY_DEBUG
- qDebug() << "Duplicate: " << address;
-#endif
+ qCDebug(QT_BT_BLUEZ) << "Duplicate: " << address;
return;
}
discoveredDevices.replace(i, device);
Q_Q(QBluetoothDeviceDiscoveryAgent);
-#ifdef QT_DEVICEDISCOVERY_DEBUG
- qDebug() << "Updated: " << address;
-#endif
+ qCDebug(QT_BT_BLUEZ) << "Updated: " << address;
emit q->deviceDiscovered(device);
return; // this works if the list doesn't contain duplicates. Don't let it.
}
}
-#ifdef QT_DEVICEDISCOVERY_DEBUG
- qDebug() << "Emit: " << address;
-#endif
+ qCDebug(QT_BT_BLUEZ) << "Emit: " << address;
discoveredDevices.append(device);
Q_Q(QBluetoothDeviceDiscoveryAgent);
emit q->deviceDiscovered(device);
@@ -215,10 +215,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_deviceFound(const QString &addres
void QBluetoothDeviceDiscoveryAgentPrivate::_q_propertyChanged(const QString &name,
const QDBusVariant &value)
-{
-#ifdef QT_DEVICEDISCOVERY_DEBUG
- qDebug() << Q_FUNC_INFO << name << value.variant();
-#endif
+{
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << name << value.variant();
if (name == QLatin1String("Discovering") && !value.variant().toBool()) {
Q_Q(QBluetoothDeviceDiscoveryAgent);
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp
index 41920dbe..72a3e853 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp
@@ -68,7 +68,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start()
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
- errorString = QStringLiteral("No Bluetooth device available");
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("No Bluetooth device available");
emit q->error(QBluetoothDeviceDiscoveryAgent::InputOutputError);
}
@@ -85,7 +85,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_deviceFound(const QString &addres
void QBluetoothDeviceDiscoveryAgentPrivate::_q_propertyChanged(const QString &name,
const QDBusVariant &value)
-{
+{
Q_UNUSED(name);
Q_UNUSED(value);
}
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
index 56a0c275..71dec409 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
@@ -43,12 +43,15 @@
#define QBLUETOOTHDEVICEDISCOVERYAGENT_P_H
#include "qbluetoothdevicediscoveryagent.h"
+#ifdef QT_ANDROID_BLUETOOTH
+#include <QtAndroidExtras/QAndroidJniObject>
+#include "android/devicediscoverybroadcastreceiver_p.h"
+#endif
-#include <QVariantMap>
-
-#include <qbluetoothaddress.h>
+#include <QtCore/QVariantMap>
-#include <qbluetoothlocaldevice.h>
+#include <QtBluetooth/QBluetoothAddress>
+#include <QtBluetooth/QBluetoothLocalDevice>
#ifdef QT_BLUEZ_BLUETOOTH
class OrgBluezManagerInterface;
@@ -65,7 +68,7 @@ QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
class QBluetoothDeviceDiscoveryAgentPrivate
-#if defined(QT_QNX_BLUETOOTH)
+#if defined(QT_QNX_BLUETOOTH) || defined(QT_ANDROID_BLUETOOTH)
: public QObject {
Q_OBJECT
#else
@@ -92,7 +95,19 @@ private:
QBluetoothDeviceDiscoveryAgent::Error lastError;
QString errorString;
-#ifdef QT_BLUEZ_BLUETOOTH
+#ifdef QT_ANDROID_BLUETOOTH
+private Q_SLOTS:
+ void processDiscoveryFinished();
+ void processDiscoveredDevices(const QBluetoothDeviceInfo& info);
+
+private:
+ DeviceDiscoveryBroadcastReceiver* receiver;
+ QBluetoothAddress m_adapterAddress;
+ bool m_active;
+ QAndroidJniObject adapter;
+
+ bool pendingCancel, pendingStart;
+#elif defined(QT_BLUEZ_BLUETOOTH)
QBluetoothAddress m_adapterAddress;
bool pendingCancel;
bool pendingStart;
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp
index 7cc8ea93..a20ab90b 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp
@@ -92,19 +92,21 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start()
m_currentOp = Start;
if (m_rdfd != -1) {
- qBBBluetoothDebug() << "RDev FD still open";
+ qCDebug(QT_BT_QNX) << "RDev FD still open";
} else if ((m_rdfd = qt_safe_open("/pps/services/bluetooth/remote_devices/.all", O_RDONLY)) == -1) {
- qWarning() << Q_FUNC_INFO << "rdfd - failed to open /pps/services/bluetooth/remote_devices/.all"
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "rdfd - failed to open /pps/services/bluetooth/remote_devices/.all"
<< m_rdfd;
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Cannot open remote device socket");
emit q->error(lastError);
stop();
return;
} else {
m_rdNotifier = new QSocketNotifier(m_rdfd, QSocketNotifier::Read, this);
if (!m_rdNotifier) {
- qWarning() << Q_FUNC_INFO << "failed to connect to m_rdNotifier";
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "failed to connect to m_rdNotifier";
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Cannot connect to Bluetooth socket notifier");
emit q->error(lastError);
stop();
return;
@@ -116,8 +118,10 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start()
m_finishedTimer.start(10000);
connect(m_rdNotifier, SIGNAL(activated(int)), this, SLOT(remoteDevicesChanged(int)));
} else {
- qWarning() << "Could not write to control FD";
+ qCWarning(QT_BT_QNX) << "Could not write to control FD";
m_active = false;
+ lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Cannot start device inquiry");
q->error(QBluetoothDeviceDiscoveryAgent::InputOutputError);
return;
}
@@ -125,7 +129,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start()
void QBluetoothDeviceDiscoveryAgentPrivate::stop()
{
- Q_Q(QBluetoothDeviceDiscoveryAgent);
m_active = false;
m_finishedTimer.stop();
if (m_currentOp == Start) {
@@ -134,7 +137,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
}
m_currentOp = Cancel;
- qBBBluetoothDebug() << "Stopping device search";
+ qCDebug(QT_BT_QNX) << "Stopping device search";
ppsSendControlMessage("cancel_device_search",this);
if (m_rdNotifier) {
@@ -198,7 +201,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::remoteDevicesChanged(int fd)
//Starts the timer again
m_finishedTimer.start(7000);
if (!deviceAddr.isNull()) {
- //qDebug() << "Device discovered: " << deviceName << deviceAddr.toString();
+ qCDebug(QT_BT_QNX) << "Device discovered: " << deviceName << deviceAddr.toString();
/* Looking for device type. Only Low energy devices will be added
* BT_DEVICE_TYPE_LE_PUBLIC is 0 --->LE device
* BT_DEVICE_TYPE_LE_PRIVATE is 1 ---> LE device
@@ -226,7 +229,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::controlReply(ppsResult result)
if (result.dat.size() > 0 && result.dat.first() == QStringLiteral("EOK")) {
//Do nothing. We can not be certain, that the device search is over yet
} else if (result.error == 16) {
- qBBBluetoothDebug() << "Could not start device inquire bc resource is busy";
+ qCDebug(QT_BT_QNX) << "Could not start device inquire bc resource is busy";
if (m_nextOp == None) { //We try again
ppsSendControlMessage("cancel_device_search",this);
QTimer::singleShot(5000, this, SLOT(startDeviceSearch()));
@@ -234,7 +237,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::controlReply(ppsResult result)
}
return;
} else {
- qWarning("A PPS Bluetooth error occurred:");
+ qCWarning(QT_BT_QNX) << "A PPS Bluetooth error occurred:";
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
errorString = result.errorMsg;
Q_EMIT q_ptr->error(QBluetoothDeviceDiscoveryAgent::InputOutputError);
@@ -242,7 +245,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::controlReply(ppsResult result)
}
processNextOp();
} else if (result.msg == QStringLiteral("cancel_device_search") && m_currentOp == Cancel && !isFinished) {
- qBBBluetoothDebug() << "Cancel device search";
+ qCDebug(QT_BT_QNX) << "Cancel device search";
// if (!result.errorMsg.isEmpty()) {
// lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
// errorString = result.errorMsg;
@@ -256,14 +259,14 @@ void QBluetoothDeviceDiscoveryAgentPrivate::controlReply(ppsResult result)
void QBluetoothDeviceDiscoveryAgentPrivate::controlEvent(ppsResult result)
{
if (result.msg == QStringLiteral("device_added")) {
- qBBBluetoothDebug() << "Device was added" << result.dat.first();
+ qCDebug(QT_BT_QNX) << "Device was added" << result.dat.first();
}
}
void QBluetoothDeviceDiscoveryAgentPrivate::finished()
{
if (m_active) {
- qBBBluetoothDebug() << "Device discovery finished";
+ qCDebug(QT_BT_QNX) << "Device discovery finished";
isFinished = true;
stop();
q_ptr->finished();
diff --git a/src/bluetooth/qbluetoothdeviceinfo.cpp b/src/bluetooth/qbluetoothdeviceinfo.cpp
index d451bc49..58d45e3b 100644
--- a/src/bluetooth/qbluetoothdeviceinfo.cpp
+++ b/src/bluetooth/qbluetoothdeviceinfo.cpp
@@ -42,8 +42,6 @@
#include "qbluetoothdeviceinfo.h"
#include "qbluetoothdeviceinfo_p.h"
-#include <QDebug>
-
QT_BEGIN_NAMESPACE
/*!
diff --git a/src/bluetooth/qbluetoothdeviceinfo.h b/src/bluetooth/qbluetoothdeviceinfo.h
index 3e403954..b6b29ca9 100644
--- a/src/bluetooth/qbluetoothdeviceinfo.h
+++ b/src/bluetooth/qbluetoothdeviceinfo.h
@@ -142,7 +142,7 @@ public:
enum MinorImagingClass {
UncategorizedImagingDevice = 0,
ImageDisplay = 0x04,
- ImageCamera = 0x08,
+ ImageCamera = 0x08,
ImageScanner = 0x10,
ImagePrinter = 0x20
};
diff --git a/src/bluetooth/qbluetoothlocaldevice.cpp b/src/bluetooth/qbluetoothlocaldevice.cpp
index 9661adcb..e299ab71 100644
--- a/src/bluetooth/qbluetoothlocaldevice.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice.cpp
@@ -44,7 +44,6 @@
#include "qbluetoothaddress.h"
#include <QtCore/QString>
-#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -93,12 +92,13 @@ QT_BEGIN_NAMESPACE
if they have previously been paired with it or otherwise know its address. This powers up the
device if it was powered off.
\value HostDiscoverable Remote Bluetooth devices can discover the presence of the local
- Bluetooth device. The device will also be connectable, and powered on.
+ Bluetooth device. The device will also be connectable, and powered on. On Android, this mode can only be active
+ for a maximum of 5 minutes.
\value HostDiscoverableLimitedInquiry Remote Bluetooth devices can discover the presence of the local
Bluetooth device when performing a limited inquiry. This should be used for locating services that are
only made discoverable for a limited period of time. This can speed up discovery between gaming devices,
as service discovery can be skipped on devices not in LimitedInquiry mode. In this mode, the device will
- be connectable and powered on, if required.
+ be connectable and powered on, if required. This mode is is not supported on Android.
*/
@@ -188,6 +188,42 @@ bool QBluetoothLocalDevice::isValid() const
*/
/*!
+ \fn QBluetoothLocalDevice::deviceConnected(const QBluetoothAddress &address)
+ \since 5.3
+
+ This signal is emitted when the local device establishes a connection to a remote device
+ with \a address.
+
+ \sa deviceDisconnected(), connectedDevices()
+*/
+
+/*!
+ \fn QBluetoothLocalDevice::deviceDisconnected(const QBluetoothAddress &address)
+ \since 5.3
+
+ This signal is emitted when the local device disconnects from a remote Bluetooth device
+ with \a address.
+
+ \sa deviceConnected(), connectedDevices()
+*/
+
+/*!
+ \fn QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
+ \since 5.3
+
+ Returns the list of connected devices. This list is different from the list of currently
+ paired devices.
+
+ On Android it is not possible to retrieve a list of connected devices. It is only possible to
+ listen to (dis)connect changes. For convenience, this class monitors all connect
+ and disconnect events since its instanciation and returns the current list when calling this function.
+ Therefore it is possible that this function returns an empty list shortly after creating an
+ instance.
+
+ \sa deviceConnected(), deviceDisconnected()
+*/
+
+/*!
\fn QBluetoothLocalDevice::pairingStatus(const QBluetoothAddress &address) const
Returns the current bluetooth pairing status of \a address, if it's unpaired, paired, or paired and authorized.
@@ -198,8 +234,12 @@ bool QBluetoothLocalDevice::isValid() const
\fn QBluetoothLocalDevice::pairingDisplayConfirmation(const QBluetoothAddress &address, QString pin)
Signal by some platforms to display a pairing confirmation dialog for \a address. The user
- is asked to confirm the \a pin is the same on both devices. QBluetoothLocalDevice::pairingConfirmation(bool)
+ is asked to confirm the \a pin is the same on both devices. The \l pairingConfirmation() function
must be called to indicate if the user accepts or rejects the displayed pin.
+
+ This signal is only emitted for pairing requests issues by calling \l requestPairing().
+
+ \sa pairingConfirmation()
*/
/*!
@@ -207,6 +247,8 @@ bool QBluetoothLocalDevice::isValid() const
To be called after getting a pairingDisplayConfirmation(). The \a accept parameter either
accepts the pairing or rejects it.
+
+ Accepting a pairing always refers to the last pairing request issued via \l requestPairing().
*/
/*!
@@ -214,6 +256,8 @@ bool QBluetoothLocalDevice::isValid() const
Signal by some platforms to display the \a pin to the user for \a address. The pin is automatically
generated, and does not need to be confirmed.
+
+ This signal is only emitted for pairing requests issues by calling \l requestPairing().
*/
/*!
@@ -229,7 +273,8 @@ bool QBluetoothLocalDevice::isValid() const
Pairing or unpairing has completed with \a address. Current pairing status is in \a pairing.
If the pairing request was not successful, this signal will not be emitted. The error() signal
- is emitted if the pairing request failed.
+ is emitted if the pairing request failed. The signal is only ever emitted for pairing requests
+ which have previously requested by calling \l requestPairing() of the current object instance.
*/
/*!
diff --git a/src/bluetooth/qbluetoothlocaldevice.h b/src/bluetooth/qbluetoothlocaldevice.h
index 713b5037..597496b7 100644
--- a/src/bluetooth/qbluetoothlocaldevice.h
+++ b/src/bluetooth/qbluetoothlocaldevice.h
@@ -68,7 +68,7 @@ public:
AuthorizedPaired
};
- enum HostMode {
+ enum HostMode {
HostPoweredOff,
HostConnectable,
HostDiscoverable,
@@ -91,6 +91,7 @@ public:
void setHostMode(QBluetoothLocalDevice::HostMode mode);
HostMode hostMode() const;
+ QList<QBluetoothAddress> connectedDevices() const;
void powerOn();
@@ -104,6 +105,8 @@ public Q_SLOTS:
Q_SIGNALS:
void hostModeStateChanged(QBluetoothLocalDevice::HostMode state);
+ void deviceConnected(const QBluetoothAddress &address);
+ void deviceDisconnected(const QBluetoothAddress &address);
void pairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
void pairingDisplayPinCode(const QBluetoothAddress &address, QString pin);
diff --git a/src/bluetooth/qbluetoothlocaldevice_android.cpp b/src/bluetooth/qbluetoothlocaldevice_android.cpp
new file mode 100644
index 00000000..4e441bc2
--- /dev/null
+++ b/src/bluetooth/qbluetoothlocaldevice_android.cpp
@@ -0,0 +1,443 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtBluetooth/QBluetoothLocalDevice>
+#include <QtBluetooth/QBluetoothAddress>
+
+#include "qbluetoothlocaldevice_p.h"
+#include "android/localdevicebroadcastreceiver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(
+ QBluetoothLocalDevice *q, const QBluetoothAddress &address)
+ : q_ptr(q), obj(0), pendingHostModeTransition(false)
+{
+ initialize(address);
+
+ receiver = new LocalDeviceBroadcastReceiver(q_ptr);
+ QObject::connect(receiver, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)),
+ this, SLOT(processHostModeChange(QBluetoothLocalDevice::HostMode)));
+ QObject::connect(receiver, SIGNAL(pairingStateChanged(QBluetoothAddress,QBluetoothLocalDevice::Pairing)),
+ this, SLOT(processPairingStateChanged(QBluetoothAddress,QBluetoothLocalDevice::Pairing)));
+ QObject::connect(receiver, SIGNAL(connectDeviceChanges(QBluetoothAddress,bool)),
+ this, SLOT(processConnectDeviceChanges(QBluetoothAddress,bool)));
+ QObject::connect(receiver, SIGNAL(pairingDisplayConfirmation(QBluetoothAddress,QString)),
+ this, SLOT(processDisplayConfirmation(QBluetoothAddress,QString)));
+}
+
+
+QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
+{
+ delete receiver;
+ delete obj;
+}
+
+QAndroidJniObject *QBluetoothLocalDevicePrivate::adapter()
+{
+ return obj;
+}
+
+void QBluetoothLocalDevicePrivate::initialize(const QBluetoothAddress &address)
+{
+ QAndroidJniEnvironment env;
+
+ jclass btAdapterClass = env->FindClass("android/bluetooth/BluetoothAdapter");
+ if (btAdapterClass == NULL) {
+ qCWarning(QT_BT_ANDROID) << "Native registration unable to find class android/bluetooth/BluetoothAdapter";
+ return;
+ }
+
+ jmethodID getDefaultAdapterID = env->GetStaticMethodID(btAdapterClass, "getDefaultAdapter", "()Landroid/bluetooth/BluetoothAdapter;");
+ if (getDefaultAdapterID == NULL) {
+ qCWarning(QT_BT_ANDROID) << "Native registration unable to get method ID: getDefaultAdapter of android/bluetooth/BluetoothAdapter";
+ return;
+ }
+
+
+ jobject btAdapterObject = env->CallStaticObjectMethod(btAdapterClass, getDefaultAdapterID);
+ if (btAdapterObject == NULL) {
+ qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
+ env->DeleteLocalRef(btAdapterClass);
+ return;
+ }
+
+ obj = new QAndroidJniObject(btAdapterObject);
+ if (!obj->isValid()) {
+ delete obj;
+ obj = 0;
+ } else {
+ if (!address.isNull()) {
+ const QString localAddress = obj->callObjectMethod("getAddress", "()Ljava/lang/String;").toString();
+ if (localAddress != address.toString()) {
+ //passed address not local one -> invalid
+ delete obj;
+ obj = 0;
+ }
+ }
+ }
+
+ env->DeleteLocalRef(btAdapterObject);
+ env->DeleteLocalRef(btAdapterClass);
+}
+
+bool QBluetoothLocalDevicePrivate::isValid() const
+{
+ return obj ? true : false;
+}
+
+
+void QBluetoothLocalDevicePrivate::processHostModeChange(QBluetoothLocalDevice::HostMode newMode)
+{
+ if (!pendingHostModeTransition) {
+ //if not in transition -> pass data on
+ emit q_ptr->hostModeStateChanged(newMode);
+ return;
+ }
+
+ if (isValid() && newMode == QBluetoothLocalDevice::HostPoweredOff) {
+ bool success = (bool) obj->callMethod<jboolean>("enable", "()Z");
+ if (!success)
+ emit q_ptr->error(QBluetoothLocalDevice::UnknownError);
+ }
+
+ pendingHostModeTransition = false;
+}
+
+// Return -1 if address is not part of a pending pairing request
+// Otherwise it returns the index of address in pendingPairings
+int QBluetoothLocalDevicePrivate::pendingPairing(const QBluetoothAddress &address)
+{
+ for (int i = 0; i < pendingPairings.count(); i++) {
+ if (pendingPairings.at(i).first == address)
+ return i;
+ }
+
+ return -1;
+}
+
+
+void QBluetoothLocalDevicePrivate::processPairingStateChanged(
+ const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing)
+{
+ int index = pendingPairing(address);
+
+ if (index < 0)
+ return; //ignore unrelated pairing signals
+
+ QPair<QBluetoothAddress, bool> entry = pendingPairings.takeAt(index);
+ if ((entry.second && pairing == QBluetoothLocalDevice::Paired) ||
+ (!entry.second && pairing == QBluetoothLocalDevice::Unpaired)) {
+ emit q_ptr->pairingFinished(address, pairing);
+ } else {
+ emit q_ptr->error(QBluetoothLocalDevice::PairingError);
+ }
+
+}
+
+void QBluetoothLocalDevicePrivate::processConnectDeviceChanges(const QBluetoothAddress& address, bool isConnectEvent)
+{
+ int index = -1;
+ for (int i = 0; i < connectedDevices.count(); i++) {
+ if (connectedDevices.at(i) == address) {
+ index = i;
+ break;
+ }
+ }
+
+ if (isConnectEvent) { //connect event
+ if (index >= 0)
+ return;
+ connectedDevices.append(address);
+ emit q_ptr->deviceConnected(address);
+ } else { //disconnect event
+ connectedDevices.removeAll(address);
+ emit q_ptr->deviceDisconnected(address);
+ }
+}
+
+void QBluetoothLocalDevicePrivate::processDisplayConfirmation(const QBluetoothAddress &address, const QString &pin)
+{
+ //only send pairing notification for pairing requests issued by
+ //this QBluetoothLocalDevice instance
+ if (pendingPairing(address) == -1)
+ return;
+
+ emit q_ptr->pairingDisplayConfirmation(address, pin);
+ emit q_ptr->pairingDisplayPinCode(address, pin);
+}
+
+QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent)
+: QObject(parent),
+ d_ptr(new QBluetoothLocalDevicePrivate(this, QBluetoothAddress()))
+{
+}
+
+QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, QObject *parent)
+: QObject(parent),
+ d_ptr(new QBluetoothLocalDevicePrivate(this, address))
+{
+}
+
+QString QBluetoothLocalDevice::name() const
+{
+ if (d_ptr->adapter())
+ return d_ptr->adapter()->callObjectMethod("getName", "()Ljava/lang/String;").toString();
+
+ return QString();
+}
+
+QBluetoothAddress QBluetoothLocalDevice::address() const
+{
+ QString result;
+ if (d_ptr->adapter())
+ result = d_ptr->adapter()->callObjectMethod("getAddress", "()Ljava/lang/String;").toString();
+
+ QBluetoothAddress address(result);
+ return address;
+}
+
+void QBluetoothLocalDevice::powerOn()
+{
+ if (hostMode() != HostPoweredOff)
+ return;
+
+ if (d_ptr->adapter()) {
+ bool ret = (bool) d_ptr->adapter()->callMethod<jboolean>("enable", "()Z");
+ if (!ret)
+ emit error(QBluetoothLocalDevice::UnknownError);
+ }
+}
+
+void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode requestedMode)
+{
+ QBluetoothLocalDevice::HostMode mode = requestedMode;
+ if (requestedMode == HostDiscoverableLimitedInquiry)
+ mode = HostDiscoverable;
+
+ if (mode == hostMode())
+ return;
+
+ if (mode == QBluetoothLocalDevice::HostPoweredOff) {
+ bool success = false;
+ if (d_ptr->adapter())
+ success = (bool) d_ptr->adapter()->callMethod<jboolean>("disable", "()Z");
+
+ if (!success)
+ emit error(QBluetoothLocalDevice::UnknownError);
+ } else if (mode == QBluetoothLocalDevice::HostConnectable) {
+ if (hostMode() == QBluetoothLocalDevice::HostDiscoverable) {
+ //cannot directly go from Discoverable to Connectable
+ //we need to go to disabled mode and enable once disabling came through
+
+ setHostMode(QBluetoothLocalDevice::HostPoweredOff);
+ d_ptr->pendingHostModeTransition = true;
+ } else {
+ QAndroidJniObject::callStaticMethod<void>("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver", "setConnectable");
+ }
+ } else if (mode == QBluetoothLocalDevice::HostDiscoverable ||
+ mode == QBluetoothLocalDevice::HostDiscoverableLimitedInquiry) {
+ QAndroidJniObject::callStaticMethod<void>("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver", "setDiscoverable");
+ }
+}
+
+QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
+{
+ if (d_ptr->adapter()) {
+ jint scanMode = d_ptr->adapter()->callMethod<jint>("getScanMode");
+
+ switch (scanMode) {
+ case 20: //BluetoothAdapter.SCAN_MODE_NONE
+ return HostPoweredOff;
+ case 21: //BluetoothAdapter.SCAN_MODE_CONNECTABLE
+ return HostConnectable;
+ case 23: //BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
+ return HostDiscoverable;
+ default:
+ break;
+ }
+ }
+
+ return HostPoweredOff;
+}
+
+QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
+{
+ //Android only supports max of one device (so far)
+ QList<QBluetoothHostInfo> localDevices;
+
+ QAndroidJniEnvironment env;
+ jclass btAdapterClass = env->FindClass("android/bluetooth/BluetoothAdapter");
+ if (btAdapterClass == NULL) {
+ qCWarning(QT_BT_ANDROID) << "Native registration unable to find class android/bluetooth/BluetoothAdapter";
+ return localDevices;
+ }
+
+ jmethodID getDefaultAdapterID = env->GetStaticMethodID(btAdapterClass, "getDefaultAdapter", "()Landroid/bluetooth/BluetoothAdapter;");
+ if (getDefaultAdapterID == NULL) {
+ qCWarning(QT_BT_ANDROID) << "Native registration unable to get method ID: getDefaultAdapter of android/bluetooth/BluetoothAdapter";
+ env->DeleteLocalRef(btAdapterClass);
+ return localDevices;
+ }
+
+
+ jobject btAdapterObject = env->CallStaticObjectMethod(btAdapterClass, getDefaultAdapterID);
+ if (btAdapterObject == NULL) {
+ qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
+ env->DeleteLocalRef(btAdapterClass);
+ return localDevices;
+ }
+
+ QAndroidJniObject o(btAdapterObject);
+ if (o.isValid()) {
+ QBluetoothHostInfo info;
+ info.setName(o.callObjectMethod("getName", "()Ljava/lang/String;").toString());
+ info.setAddress(QBluetoothAddress(o.callObjectMethod("getAddress", "()Ljava/lang/String;").toString()));
+ localDevices.append(info);
+ }
+
+ env->DeleteLocalRef(btAdapterObject);
+ env->DeleteLocalRef(btAdapterClass);
+
+ return localDevices;
+}
+
+void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
+{
+ if (address.isNull()) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QBluetoothLocalDevice::Error,
+ QBluetoothLocalDevice::PairingError));
+ return;
+ }
+
+ const Pairing previousPairing = pairingStatus(address);
+ Pairing newPairing = pairing;
+ if (pairing == AuthorizedPaired) //AuthorizedPaired same as Paired on Android
+ newPairing = Paired;
+
+ if (previousPairing == newPairing) {
+ QMetaObject::invokeMethod(this, "pairingFinished", Qt::QueuedConnection,
+ Q_ARG(QBluetoothAddress, address),
+ Q_ARG(QBluetoothLocalDevice::Pairing, pairing));
+ return;
+ }
+
+ //BluetoothDevice::createBond() requires Android API 19
+ if (QtAndroidPrivate::androidSdkVersion() < 19 || !d_ptr->adapter()) {
+ qCWarning(QT_BT_ANDROID) << "Unable to pair: requires Android API 19+";
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QBluetoothLocalDevice::Error,
+ QBluetoothLocalDevice::PairingError));
+ return;
+ }
+
+ QAndroidJniObject inputString = QAndroidJniObject::fromString(address.toString());
+ jboolean success = QAndroidJniObject::callStaticMethod<jboolean>(
+ "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver",
+ "setPairingMode",
+ "(Ljava/lang/String;Z)Z",
+ inputString.object<jstring>(),
+ newPairing == Paired ? JNI_TRUE : JNI_FALSE);
+
+ if (!success) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QBluetoothLocalDevice::Error,
+ QBluetoothLocalDevice::PairingError));
+ } else {
+ d_ptr->pendingPairings.append(qMakePair(address,
+ newPairing == Paired ? true : false));
+ }
+
+}
+
+QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(const QBluetoothAddress &address) const
+{
+ if (address.isNull() || !d_ptr->adapter())
+ return Unpaired;
+
+ QAndroidJniObject inputString = QAndroidJniObject::fromString(address.toString());
+ QAndroidJniObject remoteDevice =
+ d_ptr->adapter()->callObjectMethod("getRemoteDevice",
+ "(Ljava/lang/String;)Landroid/bluetooth/BluetoothDevice;",
+ inputString.object<jstring>());
+ QAndroidJniEnvironment env;
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ return Unpaired;
+ }
+
+ jint bondState = remoteDevice.callMethod<jint>("getBondState");
+ switch (bondState) {
+ case 12: //BluetoothDevice.BOND_BONDED
+ return Paired;
+ default:
+ break;
+ }
+
+ return Unpaired;
+}
+
+void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
+{
+ if (!d_ptr->adapter())
+ return;
+
+ bool success = d_ptr->receiver->pairingConfirmation(confirmation);
+ if (!success)
+ emit error(PairingError);
+
+}
+
+QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
+{
+ //TODO Support BLuetoothManager::getConnectedDevices(int) from API 18 onwards
+ return d_ptr->connectedDevices;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothlocaldevice_bluez.cpp b/src/bluetooth/qbluetoothlocaldevice_bluez.cpp
index 62df930a..310be91b 100644
--- a/src/bluetooth/qbluetoothlocaldevice_bluez.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_bluez.cpp
@@ -39,8 +39,8 @@
**
****************************************************************************/
-
-#include <QDBusContext>
+#include <QtCore/QLoggingCategory>
+#include <QtDBus/QDBusContext>
#include "qbluetoothlocaldevice.h"
#include "qbluetoothaddress.h"
@@ -53,8 +53,15 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
static const QLatin1String agentPath("/qt/agent");
+inline uint qHash(const QBluetoothAddress &address)
+{
+ return ::qHash(address.toUInt64());
+}
+
QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
QObject(parent), d_ptr(new QBluetoothLocalDevicePrivate(this))
{
@@ -66,7 +73,7 @@ QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, Q
}
QString QBluetoothLocalDevice::name() const
-{
+{
if (!d_ptr || !d_ptr->adapter)
return QString();
@@ -155,6 +162,11 @@ QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
return HostPoweredOff;
}
+QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
+{
+ return d_ptr->connectedDevices();
+}
+
QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
{
QList<QBluetoothHostInfo> localDevices;
@@ -194,7 +206,7 @@ static inline OrgBluezDeviceInterface *getDevice(const QBluetoothAddress &addres
QDBusPendingReply<QDBusObjectPath> reply = d_ptr->adapter->FindDevice(address.toString());
reply.waitForFinished();
if(reply.isError()){
- qWarning() << Q_FUNC_INFO << "reply failed" << reply.error();
+ qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "reply failed" << reply.error();
return 0;
}
@@ -230,7 +242,7 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai
if(!res){
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error, QBluetoothLocalDevice::PairingError));
- qWarning() << "Failed to register agent";
+ qCWarning(QT_BT_BLUEZ) << "Failed to register agent";
return;
}
}
@@ -245,7 +257,7 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai
QDBusPendingReply<> deviceReply = device->SetProperty(QLatin1String("Trusted"), QDBusVariant(true));
deviceReply.waitForFinished();
if(deviceReply.isError()){
- qWarning() << Q_FUNC_INFO << "reply failed" << deviceReply.error();
+ qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "reply failed" << deviceReply.error();
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error, QBluetoothLocalDevice::PairingError));
return;
@@ -264,7 +276,7 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai
QDBusPendingReply<> deviceReply = device->SetProperty(QLatin1String("Trusted"), QDBusVariant(false));
deviceReply.waitForFinished();
if(deviceReply.isError()){
- qWarning() << Q_FUNC_INFO << "reply failed" << deviceReply.error();
+ qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "reply failed" << deviceReply.error();
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error, QBluetoothLocalDevice::PairingError));
return;
@@ -283,14 +295,14 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai
connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), d_ptr, SLOT(pairingCompleted(QDBusPendingCallWatcher*)));
if(reply.isError())
- qWarning() << Q_FUNC_INFO << reply.error() << d_ptr->agent_path;
+ qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << reply.error() << d_ptr->agent_path;
}
}
else if(pairing == Unpaired) {
QDBusPendingReply<QDBusObjectPath> reply = this->d_ptr->adapter->FindDevice(address.toString());
reply.waitForFinished();
if(reply.isError()) {
- qWarning() << Q_FUNC_INFO << "failed to find device" << reply.error();
+ qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "failed to find device" << reply.error();
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error, QBluetoothLocalDevice::PairingError));
return;
@@ -298,7 +310,7 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai
QDBusPendingReply<> removeReply = this->d_ptr->adapter->RemoveDevice(reply.value());
removeReply.waitForFinished();
if(removeReply.isError()){
- qWarning() << Q_FUNC_INFO << "failed to remove device" << removeReply.error();
+ qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "failed to remove device" << removeReply.error();
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error, QBluetoothLocalDevice::PairingError));
} else {
@@ -335,9 +347,19 @@ QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(const QBluet
}
QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q, QBluetoothAddress address)
- : adapter(0), agent(0), localAddress(address), pendingHostModeChange(-1), msgConnection(0), q_ptr(q)
+ : adapter(0), agent(0), localAddress(address), pendingHostModeChange(-1), msgConnection(0), q_ptr(q), connectedCached(false)
{
initializeAdapter();
+ connectDeviceChanges();
+}
+
+void QBluetoothLocalDevicePrivate::connectDeviceChanges()
+{
+ if (adapter) { //invalid QBluetoothLocalDevice due to wrong local adapter address
+ connect(adapter, SIGNAL(PropertyChanged(QString,QDBusVariant)), SLOT(PropertyChanged(QString,QDBusVariant)));
+ connect(adapter, SIGNAL(DeviceCreated(QDBusObjectPath)), SLOT(_q_deviceCreated(QDBusObjectPath)));
+ connect(adapter, SIGNAL(DeviceRemoved(QDBusObjectPath)), SLOT(_q_deviceRemoved(QDBusObjectPath)));
+ }
}
QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
@@ -345,6 +367,7 @@ QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
delete msgConnection;
delete adapter;
delete agent;
+ qDeleteAll(devices);
}
void QBluetoothLocalDevicePrivate::initializeAdapter()
@@ -412,6 +435,103 @@ void QBluetoothLocalDevicePrivate::RequestConfirmation(const QDBusObjectPath &in
return;
}
+void QBluetoothLocalDevicePrivate::_q_deviceCreated(const QDBusObjectPath &device)
+{
+ OrgBluezDeviceInterface *deviceInterface =
+ new OrgBluezDeviceInterface(QLatin1String("org.bluez"), device.path(), QDBusConnection::systemBus());
+ connect(deviceInterface, SIGNAL(PropertyChanged(QString,QDBusVariant)), SLOT(_q_devicePropertyChanged(QString,QDBusVariant)));
+ devices << deviceInterface;
+ QDBusPendingReply<QVariantMap> properties = deviceInterface->asyncCall(QLatin1String("GetProperties"));
+
+ properties.waitForFinished();
+ if (!properties.isValid()) {
+ qCritical() << "Unable to get device properties from: " << device.path();
+ return;
+ }
+ const QBluetoothAddress address = QBluetoothAddress(properties.value().value(QLatin1String("Address")).toString());
+ const bool connected = properties.value().value(QLatin1String("Connected")).toBool();
+
+ if (connectedCached) {
+ if (connected)
+ connectedDevicesSet.insert(address);
+ else
+ connectedDevicesSet.remove(address);
+ }
+ if (connected)
+ emit q_ptr->deviceConnected(address);
+ else
+ emit q_ptr->deviceDisconnected(address);
+}
+
+void QBluetoothLocalDevicePrivate::_q_deviceRemoved(const QDBusObjectPath &device)
+{
+ foreach (OrgBluezDeviceInterface *deviceInterface, devices) {
+ if (deviceInterface->path() == device.path()) {
+ devices.remove(deviceInterface);
+ delete deviceInterface; //deviceDisconnected is already emitted by _q_devicePropertyChanged
+ break;
+ }
+ }
+}
+
+void QBluetoothLocalDevicePrivate::_q_devicePropertyChanged(const QString &property, const QDBusVariant &value)
+{
+ OrgBluezDeviceInterface *deviceInterface = qobject_cast<OrgBluezDeviceInterface*>(sender());
+ if (deviceInterface && property == QLatin1String("Connected")) {
+ QDBusPendingReply<QVariantMap> propertiesReply = deviceInterface->GetProperties();
+ propertiesReply.waitForFinished();
+ if (propertiesReply.isError()) {
+ qCWarning(QT_BT_BLUEZ) << propertiesReply.error().message();
+ return;
+ }
+ const QVariantMap properties = propertiesReply.value();
+ const QBluetoothAddress address = QBluetoothAddress(properties.value(QLatin1String("Address")).toString());
+ const bool connected = value.variant().toBool();
+
+ if (connectedCached) {
+ if (connected)
+ connectedDevicesSet.insert(address);
+ else
+ connectedDevicesSet.remove(address);
+ }
+ if (connected)
+ emit q_ptr->deviceConnected(address);
+ else
+ emit q_ptr->deviceDisconnected(address);
+ }
+}
+
+void QBluetoothLocalDevicePrivate::createCache()
+{
+ QDBusPendingReply<QList<QDBusObjectPath> > reply = adapter->ListDevices();
+ reply.waitForFinished();
+ if (reply.isError()) {
+ qCWarning(QT_BT_BLUEZ) << reply.error().message();
+ return;
+ }
+ foreach (const QDBusObjectPath &device, reply.value()) {
+ OrgBluezDeviceInterface deviceInterface(QLatin1String("org.bluez"), device.path(), QDBusConnection::systemBus());
+
+ QDBusPendingReply<QVariantMap> properties = deviceInterface.asyncCall(QLatin1String("GetProperties"));
+ properties.waitForFinished();
+ if (!properties.isValid()) {
+ qCWarning(QT_BT_BLUEZ) << "Unable to get properties for device " << device.path();
+ return;
+ }
+
+ if (properties.value().value(QLatin1String("Connected")).toBool())
+ connectedDevicesSet.insert(QBluetoothAddress(properties.value().value(QLatin1String("Address")).toString()));
+ }
+ connectedCached = true;
+}
+
+QList<QBluetoothAddress> QBluetoothLocalDevicePrivate::connectedDevices() const
+{
+ if (!connectedCached)
+ const_cast<QBluetoothLocalDevicePrivate *>(this)->createCache();
+ return connectedDevicesSet.toList();
+}
+
void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
{
if(!d_ptr ||
@@ -437,7 +557,7 @@ QString QBluetoothLocalDevicePrivate::RequestPinCode(const QDBusObjectPath &in0)
{
Q_UNUSED(in0)
Q_Q(QBluetoothLocalDevice);
- //qDebug() << Q_FUNC_INFO << in0.path();
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << in0.path();
// seeded in constructor, 6 digit pin
QString pin = QString::fromLatin1("%1").arg(qrand()&1000000);
pin = QString::fromLatin1("%1").arg(pin, 6, QLatin1Char('0'));
@@ -452,7 +572,7 @@ void QBluetoothLocalDevicePrivate::pairingCompleted(QDBusPendingCallWatcher *wat
QDBusPendingReply<> reply = *watcher;
if(reply.isError()) {
- qWarning() << Q_FUNC_INFO << "failed to create pairing" << reply.error();
+ qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "failed to create pairing" << reply.error();
emit q->error(QBluetoothLocalDevice::PairingError);
delete watcher;
return;
@@ -461,7 +581,7 @@ void QBluetoothLocalDevicePrivate::pairingCompleted(QDBusPendingCallWatcher *wat
QDBusPendingReply<QDBusObjectPath> findReply = adapter->FindDevice(address.toString());
findReply.waitForFinished();
if(findReply.isError()) {
- qWarning() << Q_FUNC_INFO << "failed to find device" << findReply.error();
+ qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "failed to find device" << findReply.error();
emit q->error(QBluetoothLocalDevice::PairingError);
delete watcher;
return;
@@ -487,19 +607,19 @@ void QBluetoothLocalDevicePrivate::Authorize(const QDBusObjectPath &in0, const Q
Q_UNUSED(in0)
Q_UNUSED(in1)
//TODO implement this
- //qDebug() << "Got authorize for" << in0.path() << in1;
+ qCDebug(QT_BT_BLUEZ) << "Got authorize for" << in0.path() << in1;
}
void QBluetoothLocalDevicePrivate::Cancel()
{
//TODO implement this
- //qDebug() << Q_FUNC_INFO;
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO;
}
void QBluetoothLocalDevicePrivate::Release()
{
//TODO implement this
- //qDebug() << Q_FUNC_INFO;
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO;
}
@@ -507,7 +627,7 @@ void QBluetoothLocalDevicePrivate::ConfirmModeChange(const QString &in0)
{
Q_UNUSED(in0)
//TODO implement this
- //qDebug() << Q_FUNC_INFO << in0;
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << in0;
}
void QBluetoothLocalDevicePrivate::DisplayPasskey(const QDBusObjectPath &in0, uint in1, uchar in2)
@@ -516,13 +636,13 @@ void QBluetoothLocalDevicePrivate::DisplayPasskey(const QDBusObjectPath &in0, ui
Q_UNUSED(in1)
Q_UNUSED(in2)
//TODO implement this
- //qDebug() << Q_FUNC_INFO << in0.path() << in1 << in2;
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << in0.path() << in1 << in2;
}
uint QBluetoothLocalDevicePrivate::RequestPasskey(const QDBusObjectPath &in0)
{
Q_UNUSED(in0);
- //qDebug() << Q_FUNC_INFO;
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO;
return qrand()&0x1000000;
}
@@ -541,7 +661,7 @@ void QBluetoothLocalDevicePrivate::PropertyChanged(QString property, QDBusVarian
QDBusPendingReply<QVariantMap> reply = adapter->GetProperties();
reply.waitForFinished();
if (reply.isError()){
- qWarning() << "Failed to get bluetooth properties for mode change";
+ qCWarning(QT_BT_BLUEZ) << "Failed to get bluetooth properties for mode change";
return;
}
diff --git a/src/bluetooth/qbluetoothlocaldevice_p.cpp b/src/bluetooth/qbluetoothlocaldevice_p.cpp
index 411863cb..d40e6473 100644
--- a/src/bluetooth/qbluetoothlocaldevice_p.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_p.cpp
@@ -79,6 +79,11 @@ QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
return HostPoweredOff;
}
+QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
+{
+ return QList<QBluetoothAddress>();
+}
+
QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
{
QList<QBluetoothHostInfo> localDevices;
diff --git a/src/bluetooth/qbluetoothlocaldevice_p.h b/src/bluetooth/qbluetoothlocaldevice_p.h
index 0f2aaca8..61527d31 100644
--- a/src/bluetooth/qbluetoothlocaldevice_p.h
+++ b/src/bluetooth/qbluetoothlocaldevice_p.h
@@ -51,9 +51,11 @@
#include <QDBusContext>
#include <QDBusObjectPath>
#include <QDBusMessage>
+#include <QSet>
class OrgBluezAdapterInterface;
class OrgBluezAgentAdaptor;
+class OrgBluezDeviceInterface;
QT_BEGIN_NAMESPACE
class QDBusPendingCallWatcher;
@@ -63,12 +65,58 @@ QT_END_NAMESPACE
#include <QSocketNotifier>
#include "qnx/ppshelpers_p.h"
#endif
+#ifdef QT_ANDROID_BLUETOOTH
+#include <jni.h>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QPair>
+#endif
QT_BEGIN_NAMESPACE
class QBluetoothAddress;
-#if defined(QT_BLUEZ_BLUETOOTH)
+#ifdef QT_ANDROID_BLUETOOTH
+class LocalDeviceBroadcastReceiver;
+class QBluetoothLocalDevicePrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QBluetoothLocalDevicePrivate(
+ QBluetoothLocalDevice *q,
+ const QBluetoothAddress &address = QBluetoothAddress());
+ ~QBluetoothLocalDevicePrivate();
+
+ QAndroidJniObject *adapter();
+ void initialize(const QBluetoothAddress& address);
+ static bool startDiscovery();
+ static bool cancelDiscovery();
+ static bool isDiscovering();
+ bool isValid() const;
+
+
+private slots:
+ void processHostModeChange(QBluetoothLocalDevice::HostMode newMode);
+ void processPairingStateChanged(const QBluetoothAddress &address,
+ QBluetoothLocalDevice::Pairing pairing);
+ void processConnectDeviceChanges(const QBluetoothAddress &address, bool isConnectEvent);
+ void processDisplayConfirmation(const QBluetoothAddress &address, const QString &pin);
+
+private:
+ QBluetoothLocalDevice *q_ptr;
+ QAndroidJniObject *obj;
+
+ int pendingPairing(const QBluetoothAddress &address);
+
+public:
+ LocalDeviceBroadcastReceiver *receiver;
+ bool pendingHostModeTransition;
+ QList<QPair<QBluetoothAddress, bool> > pendingPairings;
+
+ QList<QBluetoothAddress> connectedDevices;
+};
+
+#elif defined(QT_BLUEZ_BLUETOOTH)
class QBluetoothLocalDevicePrivate : public QObject,
protected QDBusContext
{
@@ -78,8 +126,13 @@ public:
QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q, QBluetoothAddress localAddress = QBluetoothAddress());
~QBluetoothLocalDevicePrivate();
+ QSet<OrgBluezDeviceInterface *> devices;
+ QSet<QBluetoothAddress> connectedDevicesSet;
OrgBluezAdapterInterface *adapter;
OrgBluezAgentAdaptor *agent;
+
+ QList<QBluetoothAddress> connectedDevices() const;
+
QString agent_path;
QBluetoothAddress localAddress;
QBluetoothAddress address;
@@ -101,14 +154,22 @@ public Q_SLOTS: // METHODS
void pairingCompleted(QDBusPendingCallWatcher*);
void PropertyChanged(QString,QDBusVariant);
+ void _q_deviceCreated(const QDBusObjectPath &device);
+ void _q_deviceRemoved(const QDBusObjectPath &device);
+ void _q_devicePropertyChanged(const QString &property, const QDBusVariant &value);
bool isValid() const;
private:
+ void createCache();
+ void connectDeviceChanges();
+
QDBusMessage msgConfirmation;
QDBusConnection *msgConnection;
QBluetoothLocalDevice *q_ptr;
+ bool connectedCached;
+
void initializeAdapter();
};
@@ -134,6 +195,8 @@ public:
void requestPairing(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
void setAccess(int);
+ // This method will be used for emitting signals.
+ void connectedDevices();
Q_INVOKABLE void controlReply(ppsResult res);
Q_INVOKABLE void controlEvent(ppsResult res);
@@ -143,6 +206,7 @@ public:
private:
QBluetoothLocalDevice *q_ptr;
bool isValidDevice;
+ QList<QBluetoothAddress> connectedDevicesSet;
};
#else
class QBluetoothLocalDevicePrivate : public QObject
diff --git a/src/bluetooth/qbluetoothlocaldevice_qnx.cpp b/src/bluetooth/qbluetoothlocaldevice_qnx.cpp
index 780639f6..d0236b6a 100644
--- a/src/bluetooth/qbluetoothlocaldevice_qnx.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_qnx.cpp
@@ -42,7 +42,10 @@
#include "qbluetoothlocaldevice.h"
#include "qbluetoothaddress.h"
#include "qbluetoothlocaldevice_p.h"
+#include <sys/pps.h>
#include "qnx/ppshelpers_p.h"
+#include <QDir>
+#include <QtCore/private/qcore_unix_p.h>
QT_BEGIN_NAMESPACE
@@ -93,6 +96,46 @@ QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
return this->d_ptr->hostMode();
}
+QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
+{
+ QList<QBluetoothAddress> devices;
+ QDir bluetoothDevices(QStringLiteral("/pps/services/bluetooth/remote_devices/"));
+ QStringList allFiles = bluetoothDevices.entryList(QDir::NoDotAndDotDot| QDir::Files);
+ for (int i = 0; i < allFiles.size(); i++) {
+ qCDebug(QT_BT_QNX) << allFiles.at(i);
+ int fileId;
+ const char *filePath = QByteArray("/pps/services/bluetooth/remote_devices/").append(allFiles.at(i).toUtf8().constData()).constData();
+ if ((fileId = qt_safe_open(filePath, O_RDONLY)) == -1)
+ qCWarning(QT_BT_QNX) << "Failed to open remote device file";
+ else {
+ pps_decoder_t ppsDecoder;
+ pps_decoder_initialize(&ppsDecoder, 0);
+
+ QBluetoothAddress deviceAddr;
+ QString deviceName;
+
+ if (!ppsReadRemoteDevice(fileId, &ppsDecoder, &deviceAddr, &deviceName)) {
+ pps_decoder_cleanup(&ppsDecoder);
+ qDebug() << "Failed to open remote device file";
+ }
+
+ bool connectedDevice = false;
+ int a = pps_decoder_get_bool(&ppsDecoder, "acl_connected", &connectedDevice);
+ if (a == PPS_DECODER_OK) {
+ if (connectedDevice)
+ devices.append(deviceAddr);
+ }
+ else if ( a == PPS_DECODER_BAD_TYPE)
+ qCDebug(QT_BT_QNX) << "Type missmatch";
+ else
+ qCDebug(QT_BT_QNX) << "An unknown error occurred while checking connected status.";
+ pps_decoder_cleanup(&ppsDecoder);
+ }
+ }
+
+ return devices;
+}
+
QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
{
//We only have one device
@@ -194,7 +237,7 @@ void QBluetoothLocalDevicePrivate::setHostMode(QBluetoothLocalDevice::HostMode m
}
//If the device is in PowerOff state and the profile is changed then the power has to be turned on
if (currentHostMode == QBluetoothLocalDevice::HostPoweredOff) {
- qBBBluetoothDebug() << "Powering on";
+ qCDebug(QT_BT_QNX) << "Powering on";
powerOn();
}
@@ -256,11 +299,30 @@ void QBluetoothLocalDevicePrivate::setAccess(int access)
}
}
+void QBluetoothLocalDevicePrivate::connectedDevices()
+{
+ QList<QBluetoothAddress> devices = q_ptr->connectedDevices();
+ for (int i = 0; i < devices.size(); i ++) {
+ if (!connectedDevicesSet.contains(devices.at(i))) {
+ QBluetoothAddress addr = devices.at(i);
+ connectedDevicesSet.append(addr);
+ emit q_ptr->deviceConnected(devices.at(i));
+ }
+ }
+ for (int i = 0; i < connectedDevicesSet.size(); i ++) {
+ if (!devices.contains(connectedDevicesSet.at(i))) {
+ QBluetoothAddress addr = connectedDevicesSet.at(i);
+ emit q_ptr->deviceDisconnected(addr);
+ connectedDevicesSet.removeOne(addr);
+ }
+ }
+}
+
void QBluetoothLocalDevicePrivate::controlReply(ppsResult result)
{
- qBBBluetoothDebug() << Q_FUNC_INFO << result.msg << result.dat;
+ qCDebug(QT_BT_QNX) << Q_FUNC_INFO << result.msg << result.dat;
if (!result.errorMsg.isEmpty()) {
- qWarning() << Q_FUNC_INFO << result.errorMsg;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << result.errorMsg;
if (result.msg == QStringLiteral("initiate_pairing"))
q_ptr->error(QBluetoothLocalDevice::PairingError);
else
@@ -270,16 +332,17 @@ void QBluetoothLocalDevicePrivate::controlReply(ppsResult result)
void QBluetoothLocalDevicePrivate::controlEvent(ppsResult result)
{
- qBBBluetoothDebug() << Q_FUNC_INFO << "Control Event" << result.msg;
+ qCDebug(QT_BT_QNX) << Q_FUNC_INFO << "Control Event" << result.msg;
if (result.msg == QStringLiteral("access_changed")) {
if (__newHostMode == -1 && result.dat.size() > 1 &&
result.dat.first() == QStringLiteral("level")) {
QBluetoothLocalDevice::HostMode newHostMode = hostMode();
- qBBBluetoothDebug() << "New Host mode" << newHostMode;
+ qCDebug(QT_BT_QNX) << "New Host mode" << newHostMode;
+ connectedDevices();
Q_EMIT q_ptr->hostModeStateChanged(newHostMode);
}
} else if (result.msg == QStringLiteral("pairing_complete")) {
- qBBBluetoothDebug() << "pairing completed";
+ qCDebug(QT_BT_QNX) << "pairing completed";
if (result.dat.contains(QStringLiteral("addr"))) {
const QBluetoothAddress address = QBluetoothAddress(
result.dat.at(result.dat.indexOf(QStringLiteral("addr")) + 1));
@@ -290,18 +353,18 @@ void QBluetoothLocalDevicePrivate::controlEvent(ppsResult result)
result.dat.at(result.dat.indexOf(QStringLiteral("trusted")) + 1) == QStringLiteral("true")) {
pairingStatus = QBluetoothLocalDevice::AuthorizedPaired;
}
- qBBBluetoothDebug() << "pairing completed" << address.toString();
+ qCDebug(QT_BT_QNX) << "pairing completed" << address.toString();
Q_EMIT q_ptr->pairingFinished(address, pairingStatus);
}
} else if (result.msg == QStringLiteral("device_deleted")) {
- qBBBluetoothDebug() << "device deleted";
+ qCDebug(QT_BT_QNX) << "device deleted";
if (result.dat.contains(QStringLiteral("addr"))) {
const QBluetoothAddress address = QBluetoothAddress(
result.dat.at(result.dat.indexOf(QStringLiteral("addr")) + 1));
Q_EMIT q_ptr->pairingFinished(address, QBluetoothLocalDevice::Unpaired);
}
} else if (result.msg == QStringLiteral("radio_shutdown")) {
- qBBBluetoothDebug() << "radio shutdown";
+ qCDebug(QT_BT_QNX) << "radio shutdown";
Q_EMIT q_ptr->hostModeStateChanged(QBluetoothLocalDevice::HostPoweredOff);
}
}
diff --git a/src/bluetooth/qbluetoothserver.cpp b/src/bluetooth/qbluetoothserver.cpp
index 967d4e71..3a7e495f 100644
--- a/src/bluetooth/qbluetoothserver.cpp
+++ b/src/bluetooth/qbluetoothserver.cpp
@@ -90,7 +90,8 @@ QT_BEGIN_NAMESPACE
/*!
\fn void QBluetoothServer::close()
- Closes and resets the listening socket.
+ Closes and resets the listening socket. Any already established \l QBluetoothSocket
+ continues to operate and must be separately \l {QBluetoothSocket::close()}{closed}.
*/
/*!
@@ -110,10 +111,17 @@ QT_BEGIN_NAMESPACE
/*!
\fn bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
- Start listening for incoming connections to \a address on \a port.
+ Start listening for incoming connections to \a address on \a port. \a address
+ must be a local Bluetooth adapter address and \a port must be larger than zero
+ and not be taken already by another Bluetooth server object. It is recommended
+ to avoid setting a port number to enable the system to automatically choose
+ a port.
- Returns true if the operation succeeded and the server is listening for
- incoming connections, otherwise returns false.
+ Returns \c true if the operation succeeded and the server is listening for
+ incoming connections, otherwise returns \c false.
+
+ If the server object is already listening for incoming connections this function
+ always returns \c false. \l close() should be called before calling this function.
\sa isListening(), newConnection()
*/
@@ -121,7 +129,8 @@ QT_BEGIN_NAMESPACE
/*!
\fn void QBluetoothServer::setMaxPendingConnections(int numConnections)
- Sets the maximum number of pending connections to \a numConnections.
+ Sets the maximum number of pending connections to \a numConnections. If
+ the number of pending sockets exceeds this limit new sockets will be rejected.
\sa maxPendingConnections()
*/
@@ -172,12 +181,17 @@ QBluetoothServer::~QBluetoothServer()
Convenience function for registering an SPP service with \a uuid and \a serviceName.
Because this function already registers the service, the QBluetoothServiceInfo object
- which is returned can not be changed any more.
+ which is returned can not be changed any more. To shutdown the server later on it is
+ required to call \l QBluetoothServiceInfo::unregisterService() and \l close() on this
+ server object.
Returns a registered QBluetoothServiceInfo instance if sucessful otherwise an
invalid QBluetoothServiceInfo. This function always assumes that the default Bluetooth adapter
should be used.
+ If the server object is already listening for incoming connections this function
+ returns an invalid \l QBluetoothServiceInfo.
+
For an RFCOMM server this function is equivalent to following code snippet.
\snippet qbluetoothserver.cpp listen
@@ -199,10 +213,12 @@ QBluetoothServiceInfo QBluetoothServer::listen(const QBluetoothUuid &uuid, const
QBluetoothServiceInfo::Sequence classId;
classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
- serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,
classId);
+ //Android requires custom uuid to be set as service class
+ classId.prepend(QVariant::fromValue(uuid));
+ serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
serviceInfo.setServiceUuid(uuid);
QBluetoothServiceInfo::Sequence protocolDescriptorList;
@@ -223,8 +239,10 @@ QBluetoothServiceInfo QBluetoothServer::listen(const QBluetoothUuid &uuid, const
protocolDescriptorList);
bool result = serviceInfo.registerService();
//! [listen3]
- if (!result)
+ if (!result) {
+ close(); //close the still listening socket
return QBluetoothServiceInfo();
+ }
return serviceInfo;
}
@@ -238,6 +256,8 @@ bool QBluetoothServer::isListening() const
#ifdef QT_QNX_BLUETOOTH
if (!d->socket)
return false;
+#elif defined(QT_ANDROID_BLUETOOTH)
+ return d->isListening();
#endif
return d->socket->state() == QBluetoothSocket::ListeningState;
@@ -258,6 +278,13 @@ int QBluetoothServer::maxPendingConnections() const
/*!
\fn QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
Sets the Bluetooth security flags to \a security. This function must be called before calling listen().
+ The Bluetooth link will always be encrypted when using Bluetooth 2.1 devices as encryption is
+ mandatory.
+
+ Android only supports two levels of security (secure and non-secure). If this flag is set to
+ \l QBluetooth::NoSecurity the server object will not employ any authentication or encryption.
+ Any other security flag combination will trigger a secure Bluetooth connection.
+
On BlackBerry, security flags are not supported and will be ignored.
*/
diff --git a/src/bluetooth/qbluetoothserver.h b/src/bluetooth/qbluetoothserver.h
index d4468cb6..61573843 100644
--- a/src/bluetooth/qbluetoothserver.h
+++ b/src/bluetooth/qbluetoothserver.h
@@ -97,7 +97,7 @@ public:
Q_SIGNALS:
void newConnection();
- void error(Error);
+ void error(QBluetoothServer::Error error);
protected:
QBluetoothServerPrivate *d_ptr;
diff --git a/src/bluetooth/qbluetoothserver_android.cpp b/src/bluetooth/qbluetoothserver_android.cpp
new file mode 100644
index 00000000..a2d08757
--- /dev/null
+++ b/src/bluetooth/qbluetoothserver_android.cpp
@@ -0,0 +1,274 @@
+/***************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QLoggingCategory>
+#include "qbluetoothserver.h"
+#include "qbluetoothserver_p.h"
+#include "qbluetoothsocket.h"
+#include "qbluetoothsocket_p.h"
+#include "qbluetoothlocaldevice.h"
+#include "android/serveracceptancethread_p.h"
+
+#include <QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+QHash<QBluetoothServerPrivate*, int> __fakeServerPorts;
+
+QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType)
+ : socket(0),maxPendingConnections(1), securityFlags(QBluetooth::NoSecurity), serverType(sType),
+ m_lastError(QBluetoothServer::NoError)
+{
+ thread = new ServerAcceptanceThread();
+ thread->setMaxPendingConnections(maxPendingConnections);
+}
+
+QBluetoothServerPrivate::~QBluetoothServerPrivate()
+{
+ Q_Q(QBluetoothServer);
+ if (isListening())
+ q->close();
+
+ __fakeServerPorts.remove(this);
+
+ if (thread->isRunning()) {
+ thread->stop();
+ thread->wait();
+ }
+ thread->deleteLater();
+ thread = 0;
+}
+
+bool QBluetoothServerPrivate::initiateActiveListening(
+ const QBluetoothUuid& uuid, const QString &serviceName)
+{
+ Q_UNUSED(uuid);
+ Q_UNUSED(serviceName);
+ qCDebug(QT_BT_ANDROID) << "Initiate active listening" << uuid.toString() << serviceName;
+
+ if (uuid.isNull() || serviceName.isEmpty())
+ return false;
+
+ //no change of SP profile details -> do nothing
+ if (uuid == m_uuid && serviceName == m_serviceName)
+ return true;
+
+ m_uuid = uuid;
+ m_serviceName = serviceName;
+ thread->setServiceDetails(m_uuid, m_serviceName, securityFlags);
+
+ Q_ASSERT(!thread->isRunning());
+ thread->start();
+ Q_ASSERT(thread->isRunning());
+
+ return true;
+}
+
+bool QBluetoothServerPrivate::deactivateActiveListening()
+{
+ thread->stop();
+ thread->wait();
+
+ return true;
+}
+
+bool QBluetoothServerPrivate::isListening() const
+{
+ return thread->isRunning();
+}
+
+void QBluetoothServer::close()
+{
+ Q_D(QBluetoothServer);
+
+ d->thread->stop();
+ d->thread->wait();
+
+ if (d->thread)
+ d->thread->disconnect();
+ __fakeServerPorts.remove(d);
+}
+
+bool QBluetoothServer::listen(const QBluetoothAddress &localAdapter, quint16 port)
+{
+ const QList<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices();
+ if (!localDevices.count())
+ return false; //no Bluetooth device
+
+ if (!localAdapter.isNull()) {
+ bool found = false;
+ foreach (const QBluetoothHostInfo &hostInfo, localDevices) {
+ if (hostInfo.address() == localAdapter) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ qCWarning(QT_BT_ANDROID) << localAdapter.toString() << "is not a valid local Bt adapter";
+ return false;
+ }
+ }
+
+ Q_D(QBluetoothServer);
+ if (serverType() != QBluetoothServiceInfo::RfcommProtocol) {
+ d->m_lastError = UnsupportedProtocolError;
+ emit error(d->m_lastError);
+ return false;
+ }
+
+ if (d->isListening())
+ return false;
+
+ //check Bluetooth is available and online
+ QAndroidJniObject btAdapter = QAndroidJniObject::callStaticObjectMethod(
+ "android/bluetooth/BluetoothAdapter",
+ "getDefaultAdapter",
+ "()Landroid/bluetooth/BluetoothAdapter;");
+ if (!btAdapter.isValid()) {
+ qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
+ d->m_lastError = QBluetoothServer::UnknownError;
+ emit error(d->m_lastError);
+ return false;
+ }
+
+ const int state = btAdapter.callMethod<jint>("getState");
+ if (state != 12 ) { //BluetoothAdapter.STATE_ON
+ d->m_lastError = QBluetoothServer::PoweredOffError;
+ emit error(d->m_lastError);
+ qCWarning(QT_BT_ANDROID) << "Bluetooth device is powered off";
+ return false;
+ }
+
+ //We can not register an actual Rfcomm port, because the platform does not allow it
+ //but we need a way to associate a server with a service
+ if (port == 0) { //Try to assign a non taken port id
+ for (int i=1; ; i++){
+ if (__fakeServerPorts.key(i) == 0) {
+ port = i;
+ break;
+ }
+ }
+ }
+
+ if (__fakeServerPorts.key(port) == 0) {
+ __fakeServerPorts[d] = port;
+
+ qCDebug(QT_BT_ANDROID) << "Port" << port << "registered";
+ } else {
+ qCWarning(QT_BT_ANDROID) << "server with port" << port << "already registered or port invalid";
+ d->m_lastError = ServiceAlreadyRegisteredError;
+ emit error(d->m_lastError);
+ return false;
+ }
+
+ connect(d->thread, SIGNAL(newConnection()), this, SIGNAL(newConnection()));
+ return true;
+}
+
+void QBluetoothServer::setMaxPendingConnections(int numConnections)
+{
+ Q_D(QBluetoothServer);
+ d->maxPendingConnections = numConnections;
+ d->thread->setMaxPendingConnections(numConnections);
+}
+
+QBluetoothAddress QBluetoothServer::serverAddress() const
+{
+ //Android only supports one local adapter
+ QList<QBluetoothHostInfo> hosts = QBluetoothLocalDevice::allDevices();
+ Q_ASSERT(hosts.count() <= 1);
+
+ if (hosts.isEmpty())
+ return QBluetoothAddress();
+ else
+ return hosts.at(0).address();
+}
+
+quint16 QBluetoothServer::serverPort() const
+{
+ //We return the fake port
+ Q_D(const QBluetoothServer);
+ return __fakeServerPorts.value((QBluetoothServerPrivate*)d, 0);
+}
+
+bool QBluetoothServer::hasPendingConnections() const
+{
+ Q_D(const QBluetoothServer);
+
+ return d->thread->hasPendingConnections();
+}
+
+QBluetoothSocket *QBluetoothServer::nextPendingConnection()
+{
+ Q_D(const QBluetoothServer);
+
+ QAndroidJniObject socket = d->thread->nextPendingConnection();
+ if (!socket.isValid())
+ return 0;
+
+
+ QBluetoothSocket *newSocket = new QBluetoothSocket();
+ bool success = newSocket->d_ptr->setSocketDescriptor(socket, d->serverType);
+ if (!success) {
+ delete newSocket;
+ newSocket = 0;
+ }
+
+ return newSocket;
+}
+
+void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
+{
+ Q_D(QBluetoothServer);
+ d->securityFlags = security;
+}
+
+QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
+{
+ Q_D(const QBluetoothServer);
+ return d->securityFlags;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/bluetooth/qbluetoothserver_bluez.cpp b/src/bluetooth/qbluetoothserver_bluez.cpp
index e8457183..b78fb526 100644
--- a/src/bluetooth/qbluetoothserver_bluez.cpp
+++ b/src/bluetooth/qbluetoothserver_bluez.cpp
@@ -43,10 +43,9 @@
#include "qbluetoothserver_p.h"
#include "qbluetoothsocket.h"
+#include <QtCore/QLoggingCategory>
#include <QtCore/QSocketNotifier>
-#include <QtCore/QDebug>
-
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/l2cap.h>
@@ -55,6 +54,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
static inline void convertAddress(quint64 from, quint8 (&to)[6])
{
to[0] = (from >> 0) & 0xff;
@@ -104,11 +105,32 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
{
Q_D(QBluetoothServer);
+ if (d->socket->state() == QBluetoothSocket::ListeningState) {
+ qCWarning(QT_BT_BLUEZ) << "Socket already in listen mode, close server first";
+ return false; //already listening, nothing to do
+ }
+
int sock = d->socket->socketDescriptor();
if (sock < 0) {
- d->m_lastError = InputOutputError;
- emit error(d->m_lastError);
- return false;
+ /* Negative socket descriptor is not always an error case
+ * Another cause could be a call to close()/abort()
+ * Check whether we can recover by re-creating the socket
+ * we should really call Bluez::QBluetoothSocketPrivate::ensureNativeSocket
+ * but a re-creation of the socket will do as well.
+ */
+
+ delete d->socket;
+ if (serverType() == QBluetoothServiceInfo::RfcommProtocol)
+ d->socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
+ else
+ d->socket = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol);
+
+ sock = d->socket->socketDescriptor();
+ if (sock < 0) {
+ d->m_lastError = InputOutputError;
+ emit error(d->m_lastError);
+ return false;
+ }
}
if (d->serverType == QBluetoothServiceInfo::RfcommProtocol) {
@@ -179,7 +201,7 @@ bool QBluetoothServer::hasPendingConnections() const
if (!d || !d->socketNotifier)
return false;
- // if the socket notifier is disable there is a pending connection waiting for us to accept.
+ // if the socket notifier is disabled there is a pending connection waiting for us to accept.
return !d->socketNotifier->isEnabled();
}
@@ -252,11 +274,11 @@ void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
if (security.testFlag(QBluetooth::Secure))
lm |= RFCOMM_LM_SECURE;
- //qDebug() << hex << "Setting lm to" << lm << security;
+ qCDebug(QT_BT_BLUEZ) << hex << "Setting lm to" << lm << security;
if (setsockopt(d->socket->socketDescriptor(), SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0){
- qWarning() << "Failed to set socket option, closing socket for safety" << errno;
- qWarning() << "Error: " << strerror(errno);
+ qCWarning(QT_BT_BLUEZ) << "Failed to set socket option, closing socket for safety" << errno;
+ qCWarning(QT_BT_BLUEZ) << "Error: " << qt_error_string(errno);
d->m_lastError = InputOutputError;
emit error(d->m_lastError);
d->socket->close();
@@ -272,8 +294,8 @@ void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
lm |= L2CAP_LM_SECURE;
if (setsockopt(d->socket->socketDescriptor(), SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)) < 0){
- qWarning() << "Failed to set socket option, closing socket for safety" << errno;
- qWarning() << "Error: " << strerror(errno);
+ qCWarning(QT_BT_BLUEZ) << "Failed to set socket option, closing socket for safety" << errno;
+ qCWarning(QT_BT_BLUEZ) << "Error: " << qt_error_string(errno);
d->m_lastError = InputOutputError;
emit error(d->m_lastError);
d->socket->close();
@@ -292,7 +314,7 @@ QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
if (d->serverType == QBluetoothServiceInfo::RfcommProtocol) {
if (getsockopt(d->socket->socketDescriptor(), SOL_RFCOMM, RFCOMM_LM, &lm, (socklen_t *)&len) < 0) {
- qWarning() << "Failed to get security flags" << strerror(errno);
+ qCWarning(QT_BT_BLUEZ) << "Failed to get security flags" << qt_error_string(errno);
return QBluetooth::NoSecurity;
}
@@ -309,7 +331,7 @@ QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
security |= QBluetooth::Authorization;
} else {
if (getsockopt(d->socket->socketDescriptor(), SOL_L2CAP, L2CAP_LM, &lm, (socklen_t *)&len) < 0) {
- qWarning() << "Failed to get security flags" << strerror(errno);
+ qCWarning(QT_BT_BLUEZ) << "Failed to get security flags" << qt_error_string(errno);
return QBluetooth::NoSecurity;
}
diff --git a/src/bluetooth/qbluetoothserver_p.h b/src/bluetooth/qbluetoothserver_p.h
index 29055fbd..4137986a 100644
--- a/src/bluetooth/qbluetoothserver_p.h
+++ b/src/bluetooth/qbluetoothserver_p.h
@@ -56,6 +56,14 @@
QT_FORWARD_DECLARE_CLASS(QSocketNotifier)
#endif
+#ifdef QT_ANDROID_BLUETOOTH
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtBluetooth/QBluetoothUuid>
+
+class ServerAcceptanceThread;
+#endif
+
QT_BEGIN_NAMESPACE
class QBluetoothAddress;
@@ -108,6 +116,15 @@ private Q_SLOTS:
void controlEvent(ppsResult result);
#elif defined(QT_BLUEZ_BLUETOOTH)
QSocketNotifier *socketNotifier;
+#elif defined(QT_ANDROID_BLUETOOTH)
+ ServerAcceptanceThread *thread;
+ QString m_serviceName;
+ QBluetoothUuid m_uuid;
+public:
+ bool isListening() const;
+ bool initiateActiveListening(const QBluetoothUuid& uuid, const QString &serviceName);
+ bool deactivateActiveListening();
+
#endif
};
diff --git a/src/bluetooth/qbluetoothserver_qnx.cpp b/src/bluetooth/qbluetoothserver_qnx.cpp
index d937a275..d4289368 100644
--- a/src/bluetooth/qbluetoothserver_qnx.cpp
+++ b/src/bluetooth/qbluetoothserver_qnx.cpp
@@ -73,19 +73,19 @@ void QBluetoothServerPrivate::controlReply(ppsResult result)
Q_Q(QBluetoothServer);
if (result.msg == QStringLiteral("register_server")) {
- qBBBluetoothDebug() << "SPP: Server registration succesfull";
+ qCDebug(QT_BT_QNX) << "SPP: Server registration succesfull";
} else if (result.msg == QStringLiteral("get_mount_point_path")) {
- qBBBluetoothDebug() << "SPP: Mount point for server" << result.dat.first();
+ qCDebug(QT_BT_QNX) << "SPP: Mount point for server" << result.dat.first();
int socketFD = ::open(result.dat.first().toStdString().c_str(), O_RDWR | O_NONBLOCK);
if (socketFD == -1) {
m_lastError = QBluetoothServer::InputOutputError;
emit q->error(m_lastError);
- qWarning() << Q_FUNC_INFO << "RFCOMM Server: Could not open socket FD" << errno;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "RFCOMM Server: Could not open socket FD" << errno;
} else {
if (!socket) { // Should never happen
- qWarning() << "Socket not valid";
+ qCWarning(QT_BT_QNX) << "Socket not valid";
m_lastError = QBluetoothServer::UnknownError;
emit q->error(m_lastError);
return;
@@ -106,10 +106,10 @@ void QBluetoothServerPrivate::controlEvent(ppsResult result)
{
Q_Q(QBluetoothServer);
if (result.msg == QStringLiteral("service_connected")) {
- qBBBluetoothDebug() << "SPP: Server: Sending request for mount point path";
- qBBBluetoothDebug() << result.dat;
+ qCDebug(QT_BT_QNX) << "SPP: Server: Sending request for mount point path";
+ qCDebug(QT_BT_QNX) << result.dat;
for (int i=0; i<result.dat.size(); i++) {
- qBBBluetoothDebug() << result.dat.at(i);
+ qCDebug(QT_BT_QNX) << result.dat.at(i);
}
if (result.dat.contains(QStringLiteral("addr")) && result.dat.contains(QStringLiteral("uuid"))
@@ -117,13 +117,13 @@ void QBluetoothServerPrivate::controlEvent(ppsResult result)
nextClientAddress = result.dat.at(result.dat.indexOf(QStringLiteral("addr")) + 1);
m_uuid = QBluetoothUuid(result.dat.at(result.dat.indexOf(QStringLiteral("uuid")) + 1));
int subtype = result.dat.at(result.dat.indexOf(QStringLiteral("subtype")) + 1).toInt();
- qBBBluetoothDebug() << "Getting mount point path" << m_uuid << nextClientAddress<< subtype;
+ qCDebug(QT_BT_QNX) << "Getting mount point path" << m_uuid << nextClientAddress<< subtype;
ppsSendControlMessage("get_mount_point_path", 0x1101, m_uuid, nextClientAddress,
m_serviceName, this, BT_SPP_SERVER_SUBTYPE);
} else {
m_lastError = QBluetoothServer::InputOutputError;
emit q->error(m_lastError);
- qWarning() << Q_FUNC_INFO << "address not specified in service connect reply";
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "address not specified in service connect reply";
}
}
}
@@ -156,7 +156,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
// listen has already been called before
if (d->socket && d->socket->state() == QBluetoothSocket::ListeningState)
- return true;
+ return false;
d->socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
@@ -174,9 +174,9 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
if (__fakeServerPorts.key(port) == 0) {
__fakeServerPorts[d] = port;
- qBBBluetoothDebug() << "Port" << port << "registered";
+ qCDebug(QT_BT_QNX) << "Port" << port << "registered";
} else {
- qWarning() << "server with port" << port << "already registered or port invalid";
+ qCWarning(QT_BT_QNX) << "server with port" << port << "already registered or port invalid";
d->m_lastError = ServiceAlreadyRegisteredError;
emit error(d->m_lastError);
return false;
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.cpp b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
index cff8b813..615d0f4a 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
@@ -39,6 +39,8 @@
**
****************************************************************************/
+#include "qbluetoothhostinfo.h"
+#include "qbluetoothlocaldevice.h"
#include "qbluetoothservicediscoveryagent.h"
#include "qbluetoothservicediscoveryagent_p.h"
@@ -67,6 +69,10 @@ QT_BEGIN_NAMESPACE
use cases this is adequate as QBluetoothSocket::connectToService() will perform additional
discovery if required. If full service information is required, pass \l FullDiscovery as the
discoveryMode parameter to start().
+
+ This class may internally utilize \l QBluetoothDeviceDiscoveryAgent to find unknown devices.
+
+ \sa QBluetoothDeviceDiscoveryAgent
*/
/*!
@@ -77,6 +83,8 @@ QT_BEGIN_NAMESPACE
\value NoError No error has occurred.
\value PoweredOffError The Bluetooth adaptor is powered off, power it on before doing discovery.
\value InputOutputError Writing or reading from the device resulted in an error.
+ \value InvalidBluetoothAdapterError The passed local adapter address does not match the physical
+ adapter address of any local Bluetooth device.
\value UnknownError An unknown error has occurred.
*/
@@ -99,20 +107,24 @@ QT_BEGIN_NAMESPACE
/*!
\fn QBluetoothServiceDiscoveryAgent::finished()
- This signal is emitted when Bluetooth service discovery completes. This signal will even
- be emitted when an error occurred during the service discovery.
+ This signal is emitted when the Bluetooth service discovery completes.
+
+ Unlike the \l QBluetoothDeviceDiscoveryAgent::finished() signal this
+ signal will even be emitted when an error occurred during the service discovery. Therefore
+ it is recommended to check the \l error() signal to evaluate the success of the
+ service discovery discovery.
*/
/*!
\fn void QBluetoothServiceDiscoveryAgent::error(QBluetoothServiceDiscoveryAgent::Error error)
- This signal is emitted when an error occurs. The \a error parameter describes the error that
+ This signal is emitted when an \a error occurs. The \a error parameter describes the error that
occurred.
*/
/*!
- Constructs a new QBluetoothServiceDiscoveryAgent with \a parent. Services will be discovered on all
- contactable devices.
+ Constructs a new QBluetoothServiceDiscoveryAgent with \a parent. The search is performed via the
+ local default Bluetooth adapter.
*/
QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(QObject *parent)
: QObject(parent), d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(QBluetoothAddress()))
@@ -123,12 +135,28 @@ QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(QObject *parent
/*!
Constructs a new QBluetoothServiceDiscoveryAgent for \a deviceAdapter and with \a parent.
- If \a deviceAdapter is null, the default adapter will be used.
+ It uses \a deviceAdapter for the service search. If \a deviceAdapter is default constructed
+ the resulting QBluetoothServiceDiscoveryAgent object will use the local default Bluetooth adapter.
+
+ If a \a deviceAdapter is specified that is not a local adapter \l error() will be set to
+ \l InvalidBluetoothAdapterError. Therefore it is recommended to test the error flag immediately after
+ using this constructor.
+
+ \sa error()
*/
QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(const QBluetoothAddress &deviceAdapter, QObject *parent)
: QObject(parent), d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(deviceAdapter))
{
d_ptr->q_ptr = this;
+ if (!deviceAdapter.isNull()) {
+ const QList<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices();
+ foreach (const QBluetoothHostInfo &hostInfo, localDevices) {
+ if (hostInfo.address() == deviceAdapter)
+ return;
+ }
+ d_ptr->error = InvalidBluetoothAdapterError;
+ d_ptr->errorString = tr("Invalid Bluetooth adapter address");
+ }
}
/*!
@@ -144,6 +172,13 @@ QBluetoothServiceDiscoveryAgent::~QBluetoothServiceDiscoveryAgent()
/*!
Returns the list of all discovered services.
+
+ This list of services accumulates newly discovered services from multiple calls
+ to \l start(). Unless \l clear() is called the list cannot decrease in size. This implies
+ that if a remote Bluetooth device moves out of range in between two subsequent calls
+ to \l start() the list may contain stale entries.
+
+ \sa clear()
*/
QList<QBluetoothServiceInfo> QBluetoothServiceDiscoveryAgent::discoveredServices() const
{
@@ -194,10 +229,15 @@ QList<QBluetoothUuid> QBluetoothServiceDiscoveryAgent::uuidFilter() const
}
/*!
- Sets remote device address to \a address. If \a address is null, services will be discovered
- on all contactable Bluetooth devices. A new remote address can only be set while there is
- no service discovery in progress; otherwise this function returns false.
+ Sets the remote device address to \a address. If \a address is default constructed,
+ services will be discovered on all contactable Bluetooth devices. A new remote
+ address can only be set while there is no service discovery in progress; otherwise
+ this function returns false.
+
+ On some platforms such as Blackberry the service discovery might lead to pairing requests.
+ Therefore it is not recommended to do service discoveries on all devices.
+ \sa remoteAddress()
*/
bool QBluetoothServiceDiscoveryAgent::setRemoteAddress(const QBluetoothAddress &address)
{
@@ -210,9 +250,10 @@ bool QBluetoothServiceDiscoveryAgent::setRemoteAddress(const QBluetoothAddress &
}
/*!
- Returns the remote device address. If setRemoteAddress is not called, the function
- will return default QBluetoothAddress.
+ Returns the remote device address. If \l setRemoteAddress() is not called, the function
+ will return a default constructed \l QBluetoothAddress.
+ \sa setRemoteAddress()
*/
QBluetoothAddress QBluetoothServiceDiscoveryAgent::remoteAddress() const
{
@@ -233,7 +274,8 @@ void QBluetoothServiceDiscoveryAgent::start(DiscoveryMode mode)
{
Q_D(QBluetoothServiceDiscoveryAgent);
- if (d->discoveryState() == QBluetoothServiceDiscoveryAgentPrivate::Inactive) {
+ if (d->discoveryState() == QBluetoothServiceDiscoveryAgentPrivate::Inactive
+ && d->error != InvalidBluetoothAdapterError) {
d->setDiscoveryMode(mode);
if (d->deviceAddress.isNull()) {
d->startDeviceDiscovery();
@@ -245,12 +287,16 @@ void QBluetoothServiceDiscoveryAgent::start(DiscoveryMode mode)
}
/*!
- Stops service discovery.
+ Stops the service discovery process. The \l canceled() signal will be emitted once
+ the search has stopped.
*/
void QBluetoothServiceDiscoveryAgent::stop()
{
Q_D(QBluetoothServiceDiscoveryAgent);
+ if (d->error == InvalidBluetoothAdapterError || !isActive())
+ return;
+
switch (d->discoveryState()) {
case QBluetoothServiceDiscoveryAgentPrivate::DeviceDiscovery:
d->stopDeviceDiscovery();
@@ -265,19 +311,27 @@ void QBluetoothServiceDiscoveryAgent::stop()
}
/*!
- Clears the results of a previous service discovery.
+ Clears the results of previous service discoveries and resets \l uuidFilter().
+ This function does nothing during an ongoing service discovery (see \l isActive()).
+
+ \sa discoveredServices()
*/
void QBluetoothServiceDiscoveryAgent::clear()
{
Q_D(QBluetoothServiceDiscoveryAgent);
+ //don't clear the list while the search is ongoing
+ if (isActive())
+ return;
+
d->discoveredDevices.clear();
d->discoveredServices.clear();
d->uuidFilter.clear();
}
/*!
- Returns true if service discovery is currently active, otherwise returns false.
+ Returns \c true if the service discovery is currently active; otherwise returns \c false.
+ An active discovery can be stopped by calling \l stop().
*/
bool QBluetoothServiceDiscoveryAgent::isActive() const
{
@@ -287,9 +341,9 @@ bool QBluetoothServiceDiscoveryAgent::isActive() const
}
/*!
- Returns the type of error that last occurred. If service discovery is done
- on a signle address it will return errors that occured while trying to discover
- services on that device. If the alternate constructor is used and devices are
+ Returns the type of error that last occurred. If the service discovery is done
+ for a single \l remoteAddress() it will return errors that occurred while trying to discover
+ services on that device. If the \l remoteAddress() is not set and devices are
discovered by a scan, errors during service discovery on individual
devices are not saved and no signals are emitted. In this case, errors are
fairly normal as some devices may not respond to discovery or
@@ -305,8 +359,8 @@ QBluetoothServiceDiscoveryAgent::Error QBluetoothServiceDiscoveryAgent::error()
}
/*!
- Returns a human-readable description of the last error that occurred during
- service discovery on a single device.
+ Returns a human-readable description of the last error that occurred during the
+ service discovery.
*/
QString QBluetoothServiceDiscoveryAgent::errorString() const
{
@@ -317,7 +371,8 @@ QString QBluetoothServiceDiscoveryAgent::errorString() const
/*!
\fn QBluetoothServiceDiscoveryAgent::canceled()
- Signals the cancellation of the service discovery.
+
+ This signal is triggered when the service discovery was canceled via a call to \l stop().
*/
@@ -371,7 +426,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryFinished()
if (deviceDiscoveryAgent->error() != QBluetoothDeviceDiscoveryAgent::NoError) {
//Forward the device discovery error
error = static_cast<QBluetoothServiceDiscoveryAgent::Error>(deviceDiscoveryAgent->error());
-
+ errorString = deviceDiscoveryAgent->errorString();
setDiscoveryState(Inactive);
Q_Q(QBluetoothServiceDiscoveryAgent);
emit q->error(error);
@@ -379,8 +434,6 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryFinished()
return;
}
-// discoveredDevices = deviceDiscoveryAgent->discoveredDevices();
-
delete deviceDiscoveryAgent;
deviceDiscoveryAgent = 0;
@@ -389,28 +442,18 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryFinished()
void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscovered(const QBluetoothDeviceInfo &info)
{
- if(mode == QBluetoothServiceDiscoveryAgent::FullDiscovery) {
- // look for duplicates, and cached entries
- for(int i = 0; i < discoveredDevices.count(); i++){
- if(discoveredDevices.at(i).address() == info.address()){
- discoveredDevices.removeAt(i);
- }
- }
- discoveredDevices.prepend(info);
- }
- else {
- for(int i = 0; i < discoveredDevices.count(); i++){
- if(discoveredDevices.at(i).address() == info.address()){
- discoveredDevices.removeAt(i);
- }
- }
- discoveredDevices.prepend(info);
+ // look for duplicates, and cached entries
+ for (int i = 0; i < discoveredDevices.count(); i++) {
+ if (discoveredDevices.at(i).address() == info.address())
+ discoveredDevices.removeAt(i);
}
+ discoveredDevices.prepend(info);
}
void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryError(QBluetoothDeviceDiscoveryAgent::Error newError)
{
error = static_cast<QBluetoothServiceDiscoveryAgent::Error>(newError);
+ errorString = deviceDiscoveryAgent->errorString();
deviceDiscoveryAgent->stop();
delete deviceDiscoveryAgent;
@@ -429,8 +472,6 @@ void QBluetoothServiceDiscoveryAgentPrivate::startServiceDiscovery()
{
Q_Q(QBluetoothServiceDiscoveryAgent);
- setDiscoveryState(ServiceDiscovery);
-
if (discoveredDevices.isEmpty()) {
setDiscoveryState(Inactive);
emit q->finished();
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.h b/src/bluetooth/qbluetoothservicediscoveryagent.h
index bbb105fa..90482048 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent.h
+++ b/src/bluetooth/qbluetoothservicediscoveryagent.h
@@ -66,6 +66,7 @@ public:
NoError = QBluetoothDeviceDiscoveryAgent::NoError,
InputOutputError = QBluetoothDeviceDiscoveryAgent::InputOutputError,
PoweredOffError = QBluetoothDeviceDiscoveryAgent::PoweredOffError,
+ InvalidBluetoothAdapterError = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError,
UnknownError = QBluetoothDeviceDiscoveryAgent::UnknownError //=100
//New Errors must be added after Unknown Error the space before UnknownError is reserved
//for future device discovery errors
@@ -116,6 +117,12 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_discoveredServices(QDBusPendingCallWatcher*))
Q_PRIVATE_SLOT(d_func(), void _q_createdDevice(QDBusPendingCallWatcher*))
#endif
+#ifdef QT_ANDROID_BLUETOOTH
+ Q_PRIVATE_SLOT(d_func(), void _q_processFetchedUuids(const QBluetoothAddress &address,
+ const QList<QBluetoothUuid>&))
+ Q_PRIVATE_SLOT(d_func(), void _q_fetchUuidsTimeout())
+ Q_PRIVATE_SLOT(d_func(), void _q_hostModeStateChanged(QBluetoothLocalDevice::HostMode state))
+#endif
};
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
new file mode 100644
index 00000000..caed88e5
--- /dev/null
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
@@ -0,0 +1,513 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QTimer>
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtBluetooth/QBluetoothHostInfo>
+#include <QtBluetooth/QBluetoothLocalDevice>
+#include <QtBluetooth/QBluetoothServiceDiscoveryAgent>
+
+#include "qbluetoothservicediscoveryagent_p.h"
+#include "android/servicediscoverybroadcastreceiver_p.h"
+#include "android/localdevicebroadcastreceiver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+Q_GLOBAL_STATIC_WITH_ARGS(QUuid, btBaseUuid, ("{00000000-0000-1000-8000-00805F9B34FB}"))
+
+QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
+ const QBluetoothAddress &deviceAdapter)
+ : error(QBluetoothServiceDiscoveryAgent::NoError),
+ state(Inactive), deviceDiscoveryAgent(0),
+ mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery),
+ singleDevice(false), receiver(0), localDeviceReceiver(0)
+{
+ QList<QBluetoothHostInfo> devices = QBluetoothLocalDevice::allDevices();
+ Q_ASSERT(devices.count() == 1); //Android only supports one device at the moment
+
+ if (deviceAdapter.isNull() && devices.count() > 0 )
+ m_deviceAdapterAddress = devices.at(0).address();
+ else
+ m_deviceAdapterAddress = deviceAdapter;
+
+ if (QtAndroidPrivate::androidSdkVersion() < 15)
+ qCWarning(QT_BT_ANDROID)
+ << "SDP not supported by Android API below version 15. Detected version: "
+ << QtAndroidPrivate::androidSdkVersion()
+ << "Service discovery will return empty list.";
+
+
+ /* We assume that the current local adapter has been passed.
+ Android only supports one adapter at the moment. If m_deviceAdapterAddress
+ doesn't match the local adapter then we won't get to this point since
+ we have an InvalidBluetoothAdapter error.
+
+ The logic below must change once there is more than one adapter.
+ */
+
+ btAdapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
+ "getDefaultAdapter",
+ "()Landroid/bluetooth/BluetoothAdapter;");
+ if (!btAdapter.isValid())
+ qCWarning(QT_BT_ANDROID) << "Platform does not support Bluetooth";
+
+ qRegisterMetaType<QList<QBluetoothUuid> >("QList<QBluetoothUuid>");
+}
+
+QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate()
+{
+ delete receiver;
+ delete localDeviceReceiver;
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address)
+{
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+
+ if (!btAdapter.isValid()) {
+ error = QBluetoothServiceDiscoveryAgent::UnknownError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Platform does not support Bluetooth");
+
+ //abort any outstanding discoveries
+ discoveredDevices.clear();
+ emit q->error(error);
+ _q_serviceDiscoveryFinished();
+
+ return;
+ }
+
+ /* SDP discovery was officially added by Android API v15
+ * BluetoothDevice.getUuids() existed in earlier APIs already and in the future we may use
+ * reflection to support earlier Android versions than 15. Unfortunately
+ * BluetoothDevice.fetchUuidsWithSdp() and related APIs had some structure changes
+ * over time. Therefore we won't attempt this with reflection.
+ *
+ * TODO: Use reflection to support getUuuids() where possible.
+ * */
+ if (QtAndroidPrivate::androidSdkVersion() < 15) {
+ qCWarning(QT_BT_ANDROID) << "Aborting SDP enquiry due to too low Android API version (requires v15+)";
+
+ error = QBluetoothServiceDiscoveryAgent::UnknownError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Android API below v15 does not support SDP discovery");
+
+ //abort any outstanding discoveries
+ sdpCache.clear();
+ discoveredDevices.clear();
+ emit q->error(error);
+ _q_serviceDiscoveryFinished();
+
+ return;
+ }
+
+ QAndroidJniObject inputString = QAndroidJniObject::fromString(address.toString());
+ QAndroidJniObject remoteDevice =
+ btAdapter.callObjectMethod("getRemoteDevice",
+ "(Ljava/lang/String;)Landroid/bluetooth/BluetoothDevice;",
+ inputString.object<jstring>());
+ QAndroidJniEnvironment env;
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ env->ExceptionDescribe();
+
+ //if it was only device then its error -> otherwise go to next device
+ if (singleDevice) {
+ error = QBluetoothServiceDiscoveryAgent::InputOutputError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Cannot create Android BluetoothDevice");
+
+ qCWarning(QT_BT_ANDROID) << "Cannot start SDP for" << discoveredDevices.at(0).name()
+ << "(" << address.toString() << ")";
+ emit q->error(error);
+ }
+ _q_serviceDiscoveryFinished();
+ return;
+ }
+
+
+ if (mode == QBluetoothServiceDiscoveryAgent::MinimalDiscovery) {
+ qCDebug(QT_BT_ANDROID) << "Minimal discovery on (" << discoveredDevices.at(0).name()
+ << ")" << address.toString() ;
+
+ //Minimal discovery uses BluetoothDevice.getUuids()
+ QAndroidJniObject parcelUuidArray = remoteDevice.callObjectMethod(
+ "getUuids", "()[Landroid/os/ParcelUuid;");
+
+ if (!parcelUuidArray.isValid()) {
+ if (singleDevice) {
+ error = QBluetoothServiceDiscoveryAgent::InputOutputError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Cannot obtain service uuids");
+ emit q->error(error);
+ }
+ qCWarning(QT_BT_ANDROID) << "Cannot retrieve SDP UUIDs for" << discoveredDevices.at(0).name()
+ << "(" << address.toString() << ")";
+ _q_serviceDiscoveryFinished();
+ return;
+ }
+
+ const QList<QBluetoothUuid> results = ServiceDiscoveryBroadcastReceiver::convertParcelableArray(parcelUuidArray);
+ populateDiscoveredServices(discoveredDevices.at(0), results);
+
+ _q_serviceDiscoveryFinished();
+ } else {
+ qCDebug(QT_BT_ANDROID) << "Full discovery on (" << discoveredDevices.at(0).name()
+ << ")" << address.toString();
+
+ //Full discovery uses BluetoothDevice.fetchUuidsWithSdp()
+ if (!receiver) {
+ receiver = new ServiceDiscoveryBroadcastReceiver();
+ QObject::connect(receiver, SIGNAL(uuidFetchFinished(QBluetoothAddress,QList<QBluetoothUuid>)),
+ q, SLOT(_q_processFetchedUuids(const QBluetoothAddress&,const QList<QBluetoothUuid>&)));
+ }
+
+ if (!localDeviceReceiver) {
+ localDeviceReceiver = new LocalDeviceBroadcastReceiver();
+ QObject::connect(localDeviceReceiver, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)),
+ q, SLOT(_q_hostModeStateChanged(QBluetoothLocalDevice::HostMode)));
+ }
+
+ jboolean result = remoteDevice.callMethod<jboolean>("fetchUuidsWithSdp");
+ if (!result) {
+ //kill receiver to limit load of signals
+ receiver->deleteLater();
+ receiver = 0;
+ qCWarning(QT_BT_ANDROID) << "Cannot start dynamic fetch.";
+ _q_serviceDiscoveryFinished();
+ }
+ }
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::stop()
+{
+ sdpCache.clear();
+ discoveredDevices.clear();
+
+ //kill receiver to limit load of signals
+ receiver->deleteLater();
+ receiver = 0;
+
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+ emit q->canceled();
+
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::_q_processFetchedUuids(
+ const QBluetoothAddress &address, const QList<QBluetoothUuid> &uuids)
+{
+ //don't leave more data through if we are not interested anymore
+ if (discoveredDevices.count() == 0)
+ return;
+
+ if (QT_BT_ANDROID().isDebugEnabled()) {
+ qCDebug(QT_BT_ANDROID) << "Found UUID for" << address.toString()
+ << "\ncount: " << uuids.count();
+
+ QString result;
+ for (int i = 0; i<uuids.count(); i++)
+ result += uuids.at(i).toString() + QStringLiteral("**");
+ qCDebug(QT_BT_ANDROID) << result;
+ }
+
+ /* In general there are two uuid events per device.
+ * We'll wait for the second event to arrive before we process the UUIDs.
+ * We utilize a timeout to catch cases when the second
+ * event doesn't arrive at all.
+ * Generally we assume that the second uuid event carries the most up-to-date
+ * set of uuids and discard the first events results.
+ */
+
+ if (sdpCache.contains(address)) {
+ //second event
+ QPair<QBluetoothDeviceInfo,QList<QBluetoothUuid> > pair = sdpCache.take(address);
+
+ //prefer second uuid set over first
+ populateDiscoveredServices(pair.first, uuids);
+
+ if (discoveredDevices.count() == 1 && sdpCache.isEmpty()) {
+ //last regular uuid data set from OS -> we finish here
+ _q_serviceDiscoveryFinished();
+ }
+ } else {
+ //first event
+ QPair<QBluetoothDeviceInfo,QList<QBluetoothUuid> > pair;
+ pair.first = discoveredDevices.at(0);
+ pair.second = uuids;
+
+ if (pair.first.address() != address)
+ return;
+
+ sdpCache.insert(address, pair);
+
+ //the discovery on the last device cannot immediately finish
+ //we have to grant the 2 seconds timeout delay
+ if (discoveredDevices.count() == 1) {
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+ QTimer::singleShot(4000, q, SLOT(_q_fetchUuidsTimeout()));
+ return;
+ }
+
+ _q_serviceDiscoveryFinished();
+ }
+}
+
+
+static QString serviceNameForClassUuid(const uint value)
+{
+ switch (value & 0xffff) {
+ case QBluetoothUuid::ServiceDiscoveryServer: return QBluetoothServiceDiscoveryAgent::tr("Service Discovery");
+ //case QBluetoothUuid::BrowseGroupDescriptor: return QString();
+ //case QBluetoothUuid::PublicBrowseGroup: return QString();
+ case QBluetoothUuid::SerialPort: return QBluetoothServiceDiscoveryAgent::tr("Serial Port Profile");
+ case QBluetoothUuid::LANAccessUsingPPP: return QBluetoothServiceDiscoveryAgent::tr("LAN Access Profile");
+ case QBluetoothUuid::DialupNetworking: return QBluetoothServiceDiscoveryAgent::tr("Dial-up Networking");
+ case QBluetoothUuid::IrMCSync: return QBluetoothServiceDiscoveryAgent::tr("Synchronization");
+ case QBluetoothUuid::ObexObjectPush: return QBluetoothServiceDiscoveryAgent::tr("Object Push");
+ case QBluetoothUuid::OBEXFileTransfer: return QBluetoothServiceDiscoveryAgent::tr("File Transfer");
+ case QBluetoothUuid::IrMCSyncCommand: return QBluetoothServiceDiscoveryAgent::tr("Synchronization Command");
+ case QBluetoothUuid::Headset: return QBluetoothServiceDiscoveryAgent::tr("Headset");
+ case QBluetoothUuid::AudioSource: return QBluetoothServiceDiscoveryAgent::tr("Advanced Audio Distribution Source");
+ case QBluetoothUuid::AudioSink: return QBluetoothServiceDiscoveryAgent::tr("Advanced Audio Distribution Sink");
+ case QBluetoothUuid::AV_RemoteControlTarget: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control Target");
+ case QBluetoothUuid::AdvancedAudioDistribution: return QBluetoothServiceDiscoveryAgent::tr("Advanced Audio Distribution");
+ case QBluetoothUuid::AV_RemoteControl: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control");
+ case QBluetoothUuid::AV_RemoteControlController: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control Controller");
+ case QBluetoothUuid::HeadsetAG: return QBluetoothServiceDiscoveryAgent::tr("Headset AG");
+ case QBluetoothUuid::PANU: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (PANU)");
+ case QBluetoothUuid::NAP: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (NAP)");
+ case QBluetoothUuid::GN: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (GN)");
+ case QBluetoothUuid::DirectPrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing (DP)");
+ //case QBluetoothUuid::ReferencePrinting: return QBluetoothServiceDiscoveryAgent::tr("");
+ case QBluetoothUuid::ImagingResponder: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Responder");
+ case QBluetoothUuid::ImagingAutomaticArchive: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Archive");
+ case QBluetoothUuid::ImagingReferenceObjects: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Ref Objects");
+ case QBluetoothUuid::Handsfree: return QBluetoothServiceDiscoveryAgent::tr("Hands-Free");
+ case QBluetoothUuid::HandsfreeAudioGateway: return QBluetoothServiceDiscoveryAgent::tr("Hands-Free AG");
+ case QBluetoothUuid::DirectPrintingReferenceObjectsService: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing RefObject Service");
+ case QBluetoothUuid::ReflectedUI: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing Reflected UI");
+ case QBluetoothUuid::BasicPrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing");
+ case QBluetoothUuid::PrintingStatus: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing Status");
+ case QBluetoothUuid::HumanInterfaceDeviceService: return QBluetoothServiceDiscoveryAgent::tr("Human Interface Device");
+ case QBluetoothUuid::HardcopyCableReplacement: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement");
+ case QBluetoothUuid::HCRPrint: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement Print");
+ case QBluetoothUuid::HCRScan: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement Scan");
+ case QBluetoothUuid::SIMAccess: return QBluetoothServiceDiscoveryAgent::tr("SIM Access");
+ case QBluetoothUuid::PhonebookAccessPCE: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access PCE");
+ case QBluetoothUuid::PhonebookAccessPSE: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access PSE");
+ case QBluetoothUuid::PhonebookAccess: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access");
+ case QBluetoothUuid::HeadsetHS: return QBluetoothServiceDiscoveryAgent::tr("Headset HS");
+ case QBluetoothUuid::MessageAccessServer: return QBluetoothServiceDiscoveryAgent::tr("Message Access Server");
+ case QBluetoothUuid::MessageNotificationServer: return QBluetoothServiceDiscoveryAgent::tr("Message Notification Server");
+ case QBluetoothUuid::MessageAccessProfile: return QBluetoothServiceDiscoveryAgent::tr("Message Access");
+ case QBluetoothUuid::PnPInformation: return QBluetoothServiceDiscoveryAgent::tr("Navigation Satellite System");
+ //case QBluetoothUuid::GenericNetworking: return QBluetoothServiceDiscoveryAgent::tr("");
+ //case QBluetoothUuid::GenericFileTransfer: return QBluetoothServiceDiscoveryAgent::tr("");
+ //case QBluetoothUuid::GenericAudio: return QBluetoothServiceDiscoveryAgent::tr("");
+ //case QBluetoothUuid::GenericTelephony: return QBluetoothServiceDiscoveryAgent::tr("");
+ case QBluetoothUuid::VideoSource: return QBluetoothServiceDiscoveryAgent::tr("Video Source");
+ case QBluetoothUuid::VideoSink: return QBluetoothServiceDiscoveryAgent::tr("Video Sink");
+ case QBluetoothUuid::VideoDistribution: return QBluetoothServiceDiscoveryAgent::tr("Video Distribution");
+ case QBluetoothUuid::HDP: return QBluetoothServiceDiscoveryAgent::tr("Health Device");
+ case QBluetoothUuid::HDPSource: return QBluetoothServiceDiscoveryAgent::tr("Health Device Source");
+ case QBluetoothUuid::HDPSink: return QBluetoothServiceDiscoveryAgent::tr("Health Device Sink");
+ default:
+ break;
+ }
+
+ return QString();
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QBluetoothDeviceInfo &remoteDevice, const QList<QBluetoothUuid> &uuids)
+{
+ /* Android doesn't provide decent SDP data. A list of uuids is close to meaning-less
+ *
+ * The following approach is chosen:
+ * - If we see an SPP service class and we see
+ * one or more custom uuids we match them up. Such services will always be SPP services.
+ * - If we see a custom uuid but no SPP uuid then we return
+ * BluetoothServiceInfo instance with just a servuceUuid (no service class set)
+ * - Any other service uuid will stand on its own.
+ * */
+
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+
+ //find SPP and custom uuid
+ QBluetoothUuid uuid;
+ int sppIndex = -1;
+ QVector<int> customUuids;
+
+ for (int i = 0; i < uuids.count(); i++) {
+ uuid = uuids.at(i);
+
+ if (uuid.isNull())
+ continue;
+
+ bool isBaseUuuidSuffix = false;
+ if (btBaseUuid()->data2 == uuid.data2 && btBaseUuid()->data3 == uuid.data3
+ && btBaseUuid()->data4[0] == uuid.data4[0] && btBaseUuid()->data4[1] == uuid.data4[1]
+ && btBaseUuid()->data4[2] == uuid.data4[2] && btBaseUuid()->data4[3] == uuid.data4[3]
+ && btBaseUuid()->data4[4] == uuid.data4[4] && btBaseUuid()->data4[5] == uuid.data4[5]
+ && btBaseUuid()->data4[6] == uuid.data4[6] && btBaseUuid()->data4[7] == uuid.data4[7])
+ {
+ isBaseUuuidSuffix = true;
+ }
+
+ //check for SPP protocol
+ if (isBaseUuuidSuffix && ((uuid.data1 & 0xffff) == QBluetoothUuid::SerialPort))
+ sppIndex = i;
+
+ if (!isBaseUuuidSuffix)
+ customUuids.append(i);
+ }
+
+ for (int i = 0; i < uuids.count(); i++) {
+ if (i == sppIndex) //skip SPP service class id
+ continue;
+
+ QBluetoothServiceInfo serviceInfo;
+ serviceInfo.setDevice(remoteDevice);
+
+ QBluetoothServiceInfo::Sequence protocolDescriptorList;
+ protocolDescriptorList << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+
+ if (customUuids.contains(i) && sppIndex > -1) {
+ //we have a custom uuid of service class type SPP
+
+ //set rfcomm protocol
+ QBluetoothServiceInfo::Sequence protocol;
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ << QVariant::fromValue(0);
+ protocolDescriptorList.append(QVariant::fromValue(protocol));
+
+ //set SPP service class uuid
+ QBluetoothServiceInfo::Sequence classId;
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,
+ classId);
+ classId.prepend(QVariant::fromValue(uuids.at(i)));
+ serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
+
+ serviceInfo.setServiceName(QBluetoothServiceDiscoveryAgent::tr("Serial Port Profile"));
+ //TODO Remove line below - work around
+ serviceInfo.setServiceUuid(uuids.at(i));
+ } else if (customUuids.contains(i)) {
+ //custom uuid but no serial port
+ serviceInfo.setServiceUuid(uuids.at(i));
+ }
+
+ //Check if the UUID is in the uuidFilter
+ if (!uuidFilter.isEmpty() && !uuidFilter.contains(serviceInfo.serviceUuid()))
+ continue;
+
+ serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
+ serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList,
+ QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup));
+
+ if (!customUuids.contains(i)) {
+ //if we don't have custom uuid use it as class id as well
+ QList<QBluetoothUuid> serviceClassId;
+ serviceClassId << uuids.at(i);
+ serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, QVariant::fromValue(serviceClassId));
+ serviceInfo.setServiceName(serviceNameForClassUuid(uuids.at(i).data1));
+ }
+
+ //don't include the service if we already discovered it before
+ bool alreadyDiscovered = false;
+ for (int i = 0; i < discoveredServices.count(); i++) {
+ const QBluetoothServiceInfo &info = discoveredServices.at(i);
+ if (info.device() == serviceInfo.device()
+ && info.serviceClassUuids() == serviceInfo.serviceClassUuids()
+ && info.serviceUuid() == serviceInfo.serviceUuid()) {
+ alreadyDiscovered = true;
+ break;
+ }
+ }
+
+ if (!alreadyDiscovered) {
+ discoveredServices << serviceInfo;
+ //qCDebug(QT_BT_ANDROID) << serviceInfo;
+ emit q->serviceDiscovered(serviceInfo);
+ }
+ }
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::_q_fetchUuidsTimeout()
+{
+ if (sdpCache.isEmpty())
+ return;
+
+ QPair<QBluetoothDeviceInfo,QList<QBluetoothUuid> > pair;
+ const QList<QBluetoothAddress> keys = sdpCache.keys();
+ foreach (const QBluetoothAddress &key, keys) {
+ pair = sdpCache.take(key);
+ populateDiscoveredServices(pair.first, pair.second);
+ }
+
+ Q_ASSERT(sdpCache.isEmpty());
+
+ //kill receiver to limit load of signals
+ receiver->deleteLater();
+ receiver = 0;
+ _q_serviceDiscoveryFinished();
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::_q_hostModeStateChanged(QBluetoothLocalDevice::HostMode state)
+{
+ if (discoveryState() == QBluetoothServiceDiscoveryAgentPrivate::ServiceDiscovery &&
+ state == QBluetoothLocalDevice::HostPoweredOff ) {
+
+ discoveredDevices.clear();
+ sdpCache.clear();
+ error = QBluetoothServiceDiscoveryAgent::PoweredOffError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Device is powered off");
+
+ //kill receiver to limit load of signals
+ receiver->deleteLater();
+ receiver = 0;
+
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+ emit q->error(error);
+ _q_serviceDiscoveryFinished();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
index 06b8b59a..9c65f056 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
@@ -49,41 +49,38 @@
#include "bluez/device_p.h"
#include "bluez/characteristic_p.h"
+#include <QtCore/QLoggingCategory>
#include <QtDBus/QDBusPendingCallWatcher>
-//#define QT_SERVICEDISCOVERY_DEBUG
-
-#ifdef QT_SERVICEDISCOVERY_DEBUG
-#include <QtCore/QDebug>
-#endif
-
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter)
-: error(QBluetoothServiceDiscoveryAgent::NoError), state(Inactive), deviceDiscoveryAgent(0),
+: error(QBluetoothServiceDiscoveryAgent::NoError), m_deviceAdapterAddress(deviceAdapter), state(Inactive), deviceDiscoveryAgent(0),
mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery), singleDevice(false),
- manager(0), device(0), m_deviceAdapterAddress(deviceAdapter)
+ manager(0), adapter(0), device(0)
{
qRegisterMetaType<ServiceMap>("ServiceMap");
qDBusRegisterMetaType<ServiceMap>();
+
+ manager = new OrgBluezManagerInterface(QLatin1String("org.bluez"), QLatin1String("/"),
+ QDBusConnection::systemBus());
}
QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate()
{
delete device;
delete manager;
+ delete adapter;
}
void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address)
{
Q_Q(QBluetoothServiceDiscoveryAgent);
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << "Full discovery on: " << address.toString();
-#endif
+ qCDebug(QT_BT_BLUEZ) << "Full discovery on: " << address.toString();
- manager = new OrgBluezManagerInterface(QLatin1String("org.bluez"), QLatin1String("/"),
- QDBusConnection::systemBus());
QDBusPendingReply<QDBusObjectPath> reply;
if (m_deviceAdapterAddress.isNull())
reply = manager->DefaultAdapter();
@@ -113,54 +110,62 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
void QBluetoothServiceDiscoveryAgentPrivate::stop()
{
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << Q_FUNC_INFO << "Stop called";
-#endif
- if(device){
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "Stop called";
+ if (device) {
+ //we are waiting for _q_discoveredServices() slot to be called
+ // adapter is already 0
QDBusPendingReply<> reply = device->CancelDiscovery();
reply.waitForFinished();
- discoveredDevices.clear();
- setDiscoveryState(Inactive);
- Q_Q(QBluetoothServiceDiscoveryAgent);
- emit q->canceled();
-
-// qDebug() << "Stop done";
+ device->deleteLater();
+ device = 0;
+ Q_ASSERT(!adapter);
+ } else if (adapter) {
+ //we are waiting for _q_createdDevice() slot to be called
+ adapter->deleteLater();
+ adapter = 0;
+ Q_ASSERT(!device);
}
+
+ discoveredDevices.clear();
+ setDiscoveryState(Inactive);
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+ emit q->canceled();
}
void QBluetoothServiceDiscoveryAgentPrivate::_q_createdDevice(QDBusPendingCallWatcher *watcher)
{
+ if (!adapter)
+ return;
+
Q_Q(QBluetoothServiceDiscoveryAgent);
const QBluetoothAddress &address = watcher->property("_q_BTaddress").value<QBluetoothAddress>();
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << Q_FUNC_INFO << "created" << address.toString();
-#endif
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "created" << address.toString();
QDBusPendingReply<QDBusObjectPath> deviceObjectPath = *watcher;
if (deviceObjectPath.isError()) {
if (deviceObjectPath.error().name() != QLatin1String("org.bluez.Error.AlreadyExists")) {
+ delete adapter;
+ adapter = 0;
_q_serviceDiscoveryFinished();
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << "Create device failed Error: " << error << deviceObjectPath.error().name();
-#endif
+ qCDebug(QT_BT_BLUEZ) << "Create device failed Error: " << error << deviceObjectPath.error().name();
return;
}
deviceObjectPath = adapter->FindDevice(address.toString());
deviceObjectPath.waitForFinished();
if (deviceObjectPath.isError()) {
+ delete adapter;
+ adapter = 0;
if (singleDevice) {
error = QBluetoothServiceDiscoveryAgent::InputOutputError;
errorString = QBluetoothServiceDiscoveryAgent::tr("Unable to access device");
emit q->error(error);
}
_q_serviceDiscoveryFinished();
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << "Can't find device after creation Error: " << error << deviceObjectPath.error().name();
-#endif
+ qCDebug(QT_BT_BLUEZ) << "Can't find device after creation Error: " << error << deviceObjectPath.error().name();
return;
}
}
@@ -168,13 +173,15 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_createdDevice(QDBusPendingCallWa
device = new OrgBluezDeviceInterface(QLatin1String("org.bluez"),
deviceObjectPath.value().path(),
QDBusConnection::systemBus());
+ delete adapter;
+ adapter = 0;
QDBusPendingReply<QVariantMap> deviceReply = device->GetProperties();
deviceReply.waitForFinished();
if (deviceReply.isError()) {
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << "GetProperties error: " << error << deviceObjectPath.error().name();
-#endif
+ qCDebug(QT_BT_BLUEZ) << "GetProperties error: " << error << deviceObjectPath.error().name();
+ //TODO if we abort here who deletes device?
+ //TODO what happens to still pending discoveredDevices?
return;
}
QVariantMap deviceProperties = deviceReply.value();
@@ -189,15 +196,20 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_createdDevice(QDBusPendingCallWa
for (int i = 0; i < deviceUuids.size(); i++) {
QString b = deviceUuids.at(i);
b = b.remove(QLatin1Char('{')).remove(QLatin1Char('}'));
- QString leServiceCheck = QString(b.at(4)) + QString(b.at(5));
+
+ //TODO this should be bit field and not String operations
+ const QString leServiceCheck = QString(b.at(4)) + QString(b.at(5));
/*
* In this part we want to emit only Bluetooth Low Energy service. BLE services
* have 18xx UUID. Some LE Services contain zeros in last part of UUID.
* In the end in case there is an uuidFilter we need to prevent emitting LE services
*/
+
+ //TODO where is the uuidFilter match -> uuidFilter could contain a BLE uuid
if ((leServiceCheck == QStringLiteral("18") || b.contains(QStringLiteral("000000000000"))) && uuidFilter.size() == 0) {
QBluetoothUuid uuid(b);
QLowEnergyServiceInfo lowEnergyService(uuid);
+ //TODO Fix m_DeviceAdapterAddress may not be the actual address
lowEnergyService.d_ptr->adapterAddress = m_deviceAdapterAddress;
lowEnergyService.setDevice(discoveredDevices.at(0));
q_ptr->serviceDiscovered(lowEnergyService);
@@ -210,35 +222,36 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_createdDevice(QDBusPendingCallWa
* Low Energy devices do not have property Class.
* In case we have have LE device finish service discovery; otherwise search for regular services.
*/
- if (classType.isEmpty())
+ if (classType.isEmpty()) //is BLE device
+ //TODO is is not correct why finish here? We have other devices to discover...
+ //finished signal should not be emitted by this class
+ //Furthermore there is the assumption here that a BLE device cannot have std Bt service. Is that true?
q_ptr->finished();
else {
QString pattern;
foreach (const QBluetoothUuid &uuid, uuidFilter)
pattern += uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')) + QLatin1Char(' ');
- #ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << Q_FUNC_INFO << "Discover: " << pattern.trimmed();
- #endif
- QDBusPendingReply<ServiceMap> discoverReply = device->DiscoverServices(pattern.trimmed());
+ pattern = pattern.trimmed();
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "Discover restrictions:" << pattern;
+
+ QDBusPendingReply<ServiceMap> discoverReply = device->DiscoverServices(pattern);
watcher = new QDBusPendingCallWatcher(discoverReply, q);
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
q, SLOT(_q_discoveredServices(QDBusPendingCallWatcher*)));
}
-
}
void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingCallWatcher *watcher)
{
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << Q_FUNC_INFO;
-#endif
+ if (!device)
+ return;
+
+ qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO;
QDBusPendingReply<ServiceMap> reply = *watcher;
if (reply.isError()) {
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << "discoveredServices error: " << error << reply.error().message();
-#endif
+ qCDebug(QT_BT_BLUEZ) << "discoveredServices error: " << error << reply.error().message();
watcher->deleteLater();
if (singleDevice) {
Q_Q(QBluetoothServiceDiscoveryAgent);
@@ -246,23 +259,19 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingC
errorString = reply.error().message();
emit q->error(error);
}
+ delete device;
+ device = 0;
_q_serviceDiscoveryFinished();
return;
}
ServiceMap map = reply.value();
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << "Parsing xml" << discoveredDevices.at(0).address().toString() << discoveredDevices.count() << map.count();
-#endif
+ qCDebug(QT_BT_BLUEZ) << "Parsing xml" << discoveredDevices.at(0).address().toString() << discoveredDevices.count() << map.count();
foreach (const QString &record, reply.value()) {
QXmlStreamReader xml(record);
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << "Service xml" << record;
-#endif
-
QBluetoothServiceInfo serviceInfo;
serviceInfo.setDevice(discoveredDevices.at(0));
@@ -288,20 +297,18 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingC
Q_Q(QBluetoothServiceDiscoveryAgent);
discoveredServices.append(serviceInfo);
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << "Discovered services" << discoveredDevices.at(0).address().toString();
-#endif
+ qCDebug(QT_BT_BLUEZ) << "Discovered services" << discoveredDevices.at(0).address().toString();
emit q->serviceDiscovered(serviceInfo);
// could stop discovery, check for state
if(discoveryState() == Inactive){
-#ifdef QT_SERVICEDISCOVERY_DEBUG
- qDebug() << "Exit discovery after stop";
-#endif
+ qCDebug(QT_BT_BLUEZ) << "Exit discovery after stop";
break;
}
}
watcher->deleteLater();
+ delete device;
+ device = 0;
_q_serviceDiscoveryFinished();
}
@@ -484,9 +491,9 @@ QVariant QBluetoothServiceDiscoveryAgentPrivate::readAttributeValue(QXmlStreamRe
return QVariant::fromValue<QBluetoothServiceInfo::Sequence>(sequence);
} else {
- qWarning("unknown attribute type %s %s",
- xml.name().toString().toLocal8Bit().constData(),
- xml.attributes().value(QLatin1String("value")).toString().toLocal8Bit().constData());
+ qCWarning(QT_BT_BLUEZ) << "unknown attribute type"
+ << xml.name().toString()
+ << xml.attributes().value(QLatin1String("value")).toString();
Q_ASSERT(false);
xml.skipCurrentElement();
return QVariant();
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp
index 47467463..513d7ea7 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp
@@ -45,6 +45,7 @@
QT_BEGIN_NAMESPACE
QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter)
+ : error(QBluetoothServiceDiscoveryAgent::NoError), state(Inactive)
{
Q_UNUSED(deviceAdapter);
}
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h
index b4281530..65082558 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h
@@ -73,6 +73,12 @@ QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
class QBluetoothDeviceDiscoveryAgent;
+#ifdef QT_ANDROID_BLUETOOTH
+class ServiceDiscoveryBroadcastReceiver;
+class LocalDeviceBroadcastReceiver;
+#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtBluetooth/QBluetoothLocalDevice>
+#endif
class QBluetoothServiceDiscoveryAgentPrivate
#ifdef QT_QNX_BLUETOOTH
@@ -100,7 +106,7 @@ public:
void stopServiceDiscovery();
void setDiscoveryState(DiscoveryState s) { state = s; }
- DiscoveryState discoveryState() { return state; }
+ inline DiscoveryState discoveryState() { return state; }
void setDiscoveryMode(QBluetoothServiceDiscoveryAgent::DiscoveryMode m) { mode = m; }
QBluetoothServiceDiscoveryAgent::DiscoveryMode DiscoveryMode() { return mode; }
@@ -119,6 +125,14 @@ public:
void _q_discoveredGattCharacteristic(QDBusPendingCallWatcher *watcher);
*/
#endif
+#ifdef QT_ANDROID_BLUETOOTH
+ void _q_processFetchedUuids(const QBluetoothAddress &address, const QList<QBluetoothUuid> &uuids);
+
+ void populateDiscoveredServices(const QBluetoothDeviceInfo &remoteDevice,
+ const QList<QBluetoothUuid> &uuids);
+ void _q_fetchUuidsTimeout();
+ void _q_hostModeStateChanged(QBluetoothLocalDevice::HostMode state);
+#endif
private:
void start(const QBluetoothAddress &address);
@@ -152,6 +166,7 @@ public:
QBluetoothAddress deviceAddress;
QList<QBluetoothServiceInfo> discoveredServices;
QList<QBluetoothDeviceInfo> discoveredDevices;
+ QBluetoothAddress m_deviceAdapterAddress;
private:
DiscoveryState state;
@@ -166,14 +181,21 @@ private:
OrgBluezManagerInterface *manager;
OrgBluezAdapterInterface *adapter;
OrgBluezDeviceInterface *device;
- QBluetoothAddress m_deviceAdapterAddress;
- //Varibles below are used for discovering Bluetooth Low Energy devices
+ // variables below are used for discovering Bluetooth Low Energy devices
OrgBluezCharacteristicInterface *characteristic;
QStringList gattServices;
QStringList gattCharacteristics;
QLowEnergyCharacteristicInfo gattCharacteristic;
#endif
+#ifdef QT_ANDROID_BLUETOOTH
+ ServiceDiscoveryBroadcastReceiver *receiver;
+ LocalDeviceBroadcastReceiver *localDeviceReceiver;
+
+ QAndroidJniObject btAdapter;
+ QMap<QBluetoothAddress,QPair<QBluetoothDeviceInfo,QList<QBluetoothUuid> > > sdpCache;
+#endif
+
protected:
QBluetoothServiceDiscoveryAgent *q_ptr;
};
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp
index 442c30e8..5ef4ed49 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp
@@ -70,16 +70,16 @@ QT_BEGIN_NAMESPACE
void QBluetoothServiceDiscoveryAgentPrivate::deviceServicesDiscoveryCallback(bt_sdp_list_t *result, void *user_data, uint8_t error)
{
if (error != 0)
- qWarning() << "Error received in callback: " << errno << strerror(errno);
+ qCWarning(QT_BT_QNX) << "Error received in callback: " << errno << strerror(errno);
QPointer<QBluetoothServiceDiscoveryAgentPrivate> *classPointer = static_cast<QPointer<QBluetoothServiceDiscoveryAgentPrivate> *>(user_data);
if (classPointer->isNull()) {
- qBBBluetoothDebug() << "Pointer received in callback is null";
+ qCDebug(QT_BT_QNX) << "Pointer received in callback is null";
return;
}
QBluetoothServiceDiscoveryAgentPrivate *p = classPointer->data();
if ( result == 0) {
- qBBBluetoothDebug() << "Result received in callback is null.";
- p->errorString = QBluetoothServiceDiscoveryAgent::tr("Result received in callback is null.");
+ qCDebug(QT_BT_QNX) << "Result received in callback is null.";
+ p->errorString = QBluetoothServiceDiscoveryAgent::tr("Result received in callback is null");
p->error = QBluetoothServiceDiscoveryAgent::InputOutputError;
p->q_ptr->error(p->error);
p->_q_serviceDiscoveryFinished();
@@ -105,14 +105,14 @@ void QBluetoothServiceDiscoveryAgentPrivate::deviceServicesDiscoveryCallback(bt_
protocolDescriptorList << QVariant::fromValue(QString::fromLatin1(protoc.parm[k]));
}
serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
- qBBBluetoothDebug() << "Service name " << rec.name << " Description: " << rec.description << "uuid " << rec.serviceId << "provider: " << rec.provider;
- qBBBluetoothDebug() << "num protocol " << rec.num_protocol << "record handle " << rec.record_handle << "class id" << rec.num_classId << "availability " << rec.availability << rec.num_language;
+ qCDebug(QT_BT_QNX) << "Service name " << rec.name << " Description: " << rec.description << "uuid " << rec.serviceId << "provider: " << rec.provider;
+ qCDebug(QT_BT_QNX) << "num protocol " << rec.num_protocol << "record handle " << rec.record_handle << "class id" << rec.num_classId << "availability " << rec.availability << rec.num_language;
QList<QBluetoothUuid> serviceClassId;
for (int j = 0; j < rec.num_classId; j++) {
bt_sdp_class_t uuid = rec.classId[j];
- qBBBluetoothDebug() << "uuid: " << uuid.uuid;
+ qCDebug(QT_BT_QNX) << "uuid: " << uuid.uuid;
QString protocolUuid(uuid.uuid);
protocolUuid = QStringLiteral("0x") + protocolUuid;
QBluetoothUuid Uuid(protocolUuid.toUShort(0,0));
@@ -160,9 +160,9 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
errno = 0;
if (!m_btInitialized) {
if (bt_device_init( 0 ) < 0) {
- qWarning() << "Failed to initialize bluetooth stack.";
+ qCWarning(QT_BT_QNX) << "Failed to initialize Bluetooth stack.";
error = QBluetoothServiceDiscoveryAgent::InputOutputError;
- errorString = QBluetoothServiceDiscoveryAgent::tr("Failed to open to initialize bluetooth stack");
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Failed to initialize Bluetooth stack");
q->error(error);
_q_serviceDiscoveryFinished();
return;
@@ -173,9 +173,9 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
bt_remote_device_t *remoteDevice = bt_rdev_get_device(address.toString().toLocal8Bit().constData());
int deviceType = bt_rdev_get_type(remoteDevice);
if (deviceType == -1) {
- qWarning() << "Could not retrieve remote device (address is 00:00:00:00:00:00).";
+ qCWarning(QT_BT_QNX) << "Could not retrieve remote device address (address is 00:00:00:00:00:00).";
error = QBluetoothServiceDiscoveryAgent::InputOutputError;
- errorString = QBluetoothServiceDiscoveryAgent::tr("Could not retrieve remote device (address is 00:00:00:00:00:00).");
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Could not retrieve remote device address");
q->error(error);
_q_serviceDiscoveryFinished();
return;
@@ -189,7 +189,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
QPointer<QBluetoothServiceDiscoveryAgentPrivate> *classPointer = new QPointer<QBluetoothServiceDiscoveryAgentPrivate>(this);
int b = bt_rdev_sdp_search_async(remoteDevice, 0, &(this->deviceServicesDiscoveryCallback), classPointer);
if ( b != 0 ) {
- qWarning() << "Failed to run search on device: " << address.toString();
+ qCWarning(QT_BT_QNX) << "Failed to run search on device: " << address.toString();
error = QBluetoothServiceDiscoveryAgent::InputOutputError;
errorString = QBluetoothServiceDiscoveryAgent::tr(strerror(errno));
q->error(error);
@@ -200,22 +200,33 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
else
_q_serviceDiscoveryFinished();
#else
- QString devicePath = address.toString();
- const char *filePath = QByteArray("/pps/services/bluetooth/remote_devices/").append(devicePath.toUtf8().constData()).constData();
- if ( (m_rdfd = qt_safe_open(filePath, O_RDONLY)) == -1) {
- devicePath = address.toString() + "-00";
- const char *lowEnergyPublicPath = QByteArray("/pps/services/bluetooth/remote_devices/").append(devicePath.toUtf8().constData()).constData();
- if ((m_rdfd = qt_safe_open(lowEnergyPublicPath, O_RDONLY)) == -1) {
- devicePath = address.toString() + "-01";qDebug() << "teessttt inside 01";
- const char *lowEnergyPrivatePath = QByteArray("/pps/services/bluetooth/remote_devices/").append(devicePath.toUtf8().constData()).constData();
- if ((m_rdfd = qt_safe_open(lowEnergyPrivatePath, O_RDONLY)) == -1) {
- qWarning() << "Failed to open " << filePath;
- error = QBluetoothServiceDiscoveryAgent::InputOutputError;
- errorString = QStringLiteral("Failed to open remote device file");
- q->error(error);
+ qCDebug(QT_BT_QNX) << "Starting Service discovery for" << address.toString();
+ const QString filePath = QStringLiteral("/pps/services/bluetooth/remote_devices/").append(address.toString());
+ bool hasError = false;
+ if ((m_rdfd = qt_safe_open(filePath.toLocal8Bit().constData(), O_RDONLY)) == -1) {
+ if (QFile::exists(filePath + QLatin1String("-00")) ||
+ QFile::exists(filePath + QLatin1String("-01")))
+ {
+ qCDebug(QT_BT_QNX) << "LE device discovered...";
+ QString lePath = filePath + QStringLiteral("-00");
+ if ((m_rdfd = qt_safe_open(lePath.toLocal8Bit().constData(), O_RDONLY)) == -1) {
+ lePath = filePath + QStringLiteral("-01");
+ if ((m_rdfd = qt_safe_open(lePath.toLocal8Bit().constData(), O_RDONLY)) == -1)
+ hasError = true;
}
+ } else {
+ hasError = true;
}
}
+ if (hasError) {
+ qCWarning(QT_BT_QNX) << "Failed to open " << filePath;
+ error = QBluetoothServiceDiscoveryAgent::InputOutputError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Failed to open remote device file");
+ q->error(error);
+ _q_serviceDiscoveryFinished();
+ return;
+ }
+
if (rdNotifier)
delete rdNotifier;
rdNotifier = new QSocketNotifier(m_rdfd, QSocketNotifier::Read, this);
@@ -273,7 +284,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::remoteDevicesChanged(int fd)
if (next_service == 0)
break;
- qBBBluetoothDebug() << Q_FUNC_INFO << "Service" << next_service;
+ qCDebug(QT_BT_QNX) << Q_FUNC_INFO << "Service" << next_service;
QBluetoothServiceInfo serviceInfo;
serviceInfo.setDevice(discoveredDevices.at(0));
@@ -320,13 +331,13 @@ void QBluetoothServiceDiscoveryAgentPrivate::remoteDevicesChanged(int fd)
&& sInfo.serviceUuid() == serviceInfo.serviceUuid()
&& sInfo.serviceClassUuids() == serviceInfo.serviceClassUuids()) {
entryExists = true;
- //qBBBluetoothDebug() << "Entry exists" << serviceInfo.serviceClassUuids().first() << sInfo.serviceClassUuids().first();
+ //qCDebug(QT_BT_QNX) << "Entry exists" << serviceInfo.serviceClassUuids().first() << sInfo.serviceClassUuids().first();
break;
}
}
if (!entryExists) {
- qBBBluetoothDebug() << "Adding service" << next_service << " " << serviceInfo.socketProtocol();
+ qCDebug(QT_BT_QNX) << "Adding service" << next_service << " " << serviceInfo.socketProtocol();
discoveredServices << serviceInfo;
q_ptr->serviceDiscovered(serviceInfo);
}
@@ -365,13 +376,13 @@ void QBluetoothServiceDiscoveryAgentPrivate::remoteDevicesChanged(int fd)
void QBluetoothServiceDiscoveryAgentPrivate::controlReply(ppsResult result)
{
- qBBBluetoothDebug() << "Control reply" << result.msg << result.dat;
+ qCDebug(QT_BT_QNX) << "Control reply" << result.msg << result.dat;
if (!m_queryTimer.isActive())
return;
m_queryTimer.stop();
Q_Q(QBluetoothServiceDiscoveryAgent);
if (!result.errorMsg.isEmpty()) {
- qWarning() << Q_FUNC_INFO << result.errorMsg;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << result.errorMsg;
errorString = result.errorMsg;
if (errorString == QObject::tr("Operation canceled"))
_q_serviceDiscoveryFinished();
@@ -384,13 +395,13 @@ void QBluetoothServiceDiscoveryAgentPrivate::controlReply(ppsResult result)
void QBluetoothServiceDiscoveryAgentPrivate::controlEvent(ppsResult result)
{
- qBBBluetoothDebug() << "Control event" << result.msg << result.dat;
+ qCDebug(QT_BT_QNX) << "Control event" << result.msg << result.dat;
if (!m_queryTimer.isActive())
return;
m_queryTimer.stop();
Q_Q(QBluetoothServiceDiscoveryAgent);
if (!result.errorMsg.isEmpty()) {
- qWarning() << Q_FUNC_INFO << result.errorMsg;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << result.errorMsg;
errorString = result.errorMsg;
error = QBluetoothServiceDiscoveryAgent::InputOutputError;
q->error(error);
@@ -403,7 +414,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::queryTimeout()
{
Q_Q(QBluetoothServiceDiscoveryAgent);
error = QBluetoothServiceDiscoveryAgent::UnknownError;
- errorString = QStringLiteral("Service query timed out");
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Service query timed out");
q->error(error);
_q_serviceDiscoveryFinished();
}
diff --git a/src/bluetooth/qbluetoothserviceinfo.cpp b/src/bluetooth/qbluetoothserviceinfo.cpp
index 3a864b3c..84655b77 100644
--- a/src/bluetooth/qbluetoothserviceinfo.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo.cpp
@@ -332,18 +332,6 @@ bool QBluetoothServiceInfo::unregisterService()
*/
/*!
- \fn QList<QBluetoothUuid> QBluetoothServiceInfo::serviceClassUuids() const
-
- This is a convenience function. It is equivalent to calling
- attribute(QBluetoothServiceInfo::ServiceClassIds).value<QList<QBluetoothUuid> >().
-
- Returns a list of UUIDs describing the service classes that this service conforms to.
-
- \sa attribute()
-*/
-
-
-/*!
Construct a new invalid QBluetoothServiceInfo;
*/
QBluetoothServiceInfo::QBluetoothServiceInfo()
@@ -514,6 +502,30 @@ QBluetoothServiceInfo::Sequence QBluetoothServiceInfo::protocolDescriptor(QBluet
}
/*!
+ Returns a list of UUIDs describing the service classes that this service conforms to.
+
+ This is a convenience function. It is equivalent to calling
+ attribute(QBluetoothServiceInfo::ServiceClassIds).value<QBluetoothServiceInfo::Sequence>()
+ and subsequently iterating over its QBluetoothUuid entries.
+
+ \sa attribute()
+*/
+QList<QBluetoothUuid> QBluetoothServiceInfo::serviceClassUuids() const
+{
+ QList<QBluetoothUuid> results;
+
+ const QVariant var = attribute(QBluetoothServiceInfo::ServiceClassIds);
+ if (!var.isValid())
+ return results;
+
+ const QBluetoothServiceInfo::Sequence seq = var.value<QBluetoothServiceInfo::Sequence>();
+ for (int i = 0; i < seq.count(); i++)
+ results.append(seq.at(i).value<QBluetoothUuid>());
+
+ return results;
+}
+
+/*!
Makes a copy of the \a other and assigns it to this QBluetoothServiceInfo object.
The two copies continue to share the same service and registration details.
*/
diff --git a/src/bluetooth/qbluetoothserviceinfo.h b/src/bluetooth/qbluetoothserviceinfo.h
index 0e6555c0..4d3b8612 100644
--- a/src/bluetooth/qbluetoothserviceinfo.h
+++ b/src/bluetooth/qbluetoothserviceinfo.h
@@ -141,7 +141,7 @@ public:
inline void setServiceUuid(const QBluetoothUuid &uuid);
inline QBluetoothUuid serviceUuid() const;
- inline QList<QBluetoothUuid> serviceClassUuids() const;
+ QList<QBluetoothUuid> serviceClassUuids() const;
QBluetoothServiceInfo &operator=(const QBluetoothServiceInfo &other);
@@ -228,12 +228,6 @@ inline QBluetoothUuid QBluetoothServiceInfo::serviceUuid() const
{
return attribute(ServiceId).value<QBluetoothUuid>();
}
-
-inline QList<QBluetoothUuid> QBluetoothServiceInfo::serviceClassUuids() const
-{
- return attribute(ServiceClassIds).value<QList<QBluetoothUuid> >();
-}
-
QT_END_NAMESPACE
#endif
diff --git a/src/bluetooth/qbluetoothserviceinfo_android.cpp b/src/bluetooth/qbluetoothserviceinfo_android.cpp
new file mode 100644
index 00000000..078554d0
--- /dev/null
+++ b/src/bluetooth/qbluetoothserviceinfo_android.cpp
@@ -0,0 +1,140 @@
+/***************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QLoggingCategory>
+
+#include "qbluetoothhostinfo.h"
+#include "qbluetoothlocaldevice.h"
+#include "qbluetoothserviceinfo.h"
+#include "qbluetoothserviceinfo_p.h"
+#include "qbluetoothserver_p.h"
+#include "qbluetoothserver.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+extern QHash<QBluetoothServerPrivate*, int> __fakeServerPorts;
+
+QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate()
+: registered(false)
+{
+}
+
+QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate()
+{
+}
+
+bool QBluetoothServiceInfoPrivate::isRegistered() const
+{
+ return registered;
+}
+
+bool QBluetoothServiceInfoPrivate::unregisterService()
+{
+ if (!registered)
+ return false;
+
+ QBluetoothServerPrivate *sPriv = __fakeServerPorts.key(serverChannel());
+ if (!sPriv) {
+ //QBluetoothServer::close() was called without prior call to unregisterService().
+ //Now it is unregistered anyway.
+ registered = false;
+ return true;
+ }
+
+ bool result = sPriv->deactivateActiveListening();
+ if (!result)
+ return false;
+
+ registered = false;
+ return true;
+}
+
+bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress& localAdapter)
+{
+ const QList<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices();
+ if (!localDevices.count())
+ return false; //no Bluetooth device
+
+ if (!localAdapter.isNull()) {
+ bool found = false;
+ foreach (const QBluetoothHostInfo &hostInfo, localDevices) {
+ if (hostInfo.address() == localAdapter) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ qCWarning(QT_BT_ANDROID) << localAdapter.toString() << "is not a valid local Bt adapter";
+ return false;
+ }
+ }
+
+ //already registered on local adapter => nothing to do
+ if (registered)
+ return false;
+
+ if (protocolDescriptor(QBluetoothUuid::Rfcomm).isEmpty()) {
+ qCWarning(QT_BT_ANDROID) << Q_FUNC_INFO << "Only RFCOMM services can be registered on QNX";
+ return false;
+ }
+
+ QBluetoothServerPrivate *sPriv = __fakeServerPorts.key(serverChannel());
+ if (!sPriv)
+ return false;
+
+ //tell the server what service name and uuid our listener should have
+ //and start the real listener
+ bool result = sPriv->initiateActiveListening(
+ attributes.value(QBluetoothServiceInfo::ServiceId).value<QBluetoothUuid>(),
+ attributes.value(QBluetoothServiceInfo::ServiceName).toString());
+ if (!result) {
+ return false;
+ }
+
+
+ registered = true;
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothserviceinfo_bluez.cpp b/src/bluetooth/qbluetoothserviceinfo_bluez.cpp
index d8344589..bde3e264 100644
--- a/src/bluetooth/qbluetoothserviceinfo_bluez.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo_bluez.cpp
@@ -45,10 +45,13 @@
#include "bluez/manager_p.h"
#include "bluez/service_p.h"
+#include <QtCore/QLoggingCategory>
#include <QtCore/QXmlStreamWriter>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
static void writeAttribute(QXmlStreamWriter *stream, const QVariant &attribute)
{
const QString unsignedFormat(QLatin1String("0x%1"));
@@ -163,7 +166,7 @@ static void writeAttribute(QXmlStreamWriter *stream, const QVariant &attribute)
}
break;
default:
- qWarning() << "Unknown variant type", attribute.userType();
+ qCWarning(QT_BT_BLUEZ) << "Unknown variant type", attribute.userType();
}
}
@@ -234,7 +237,7 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca
unregisterService();
if (!ensureSdpConnection(localAdapter)) {
- qWarning() << "SDP not connected. Cannot register";
+ qCWarning(QT_BT_BLUEZ) << "SDP not connected. Cannot register";
return false;
}
@@ -263,13 +266,11 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca
stream.writeEndDocument();
-// qDebug() << xmlServiceRecord;
-
if (!registered) {
QDBusPendingReply<uint> reply = service->AddRecord(xmlServiceRecord);
reply.waitForFinished();
if (reply.isError()) {
- qWarning() << "AddRecord returned error" << reply.error();
+ qCWarning(QT_BT_BLUEZ) << "AddRecord returned error" << reply.error();
return false;
}
@@ -278,7 +279,7 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca
QDBusPendingReply<> reply = service->UpdateRecord(serviceRecord, xmlServiceRecord);
reply.waitForFinished();
if (reply.isError()) {
- qWarning() << "UpdateRecord returned error" << reply.error();
+ qCWarning(QT_BT_BLUEZ) << "UpdateRecord returned error" << reply.error();
return false;
}
}
diff --git a/src/bluetooth/qbluetoothserviceinfo_qnx.cpp b/src/bluetooth/qbluetoothserviceinfo_qnx.cpp
index b744feff..0ce566e3 100644
--- a/src/bluetooth/qbluetoothserviceinfo_qnx.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo_qnx.cpp
@@ -75,7 +75,7 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress& loca
{
Q_UNUSED(localAdapter); //QNX always uses default local adapter
if (protocolDescriptor(QBluetoothUuid::Rfcomm).isEmpty()) {
- qWarning() << Q_FUNC_INFO << "Only SPP services can be registered on QNX";
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "Only SPP services can be registered on QNX";
return false;
}
diff --git a/src/bluetooth/qbluetoothsocket.cpp b/src/bluetooth/qbluetoothsocket.cpp
index 96ed9dae..c7aea0b7 100644
--- a/src/bluetooth/qbluetoothsocket.cpp
+++ b/src/bluetooth/qbluetoothsocket.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
@@ -48,11 +48,14 @@
#include "qbluetoothservicediscoveryagent.h"
-#include <QDebug>
+#include <QtCore/QLoggingCategory>
#include <QSocketNotifier>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_BT)
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_QNX)
+
/*!
\class QBluetoothSocket
\inmodule QtBluetooth
@@ -63,6 +66,8 @@ QT_BEGIN_NAMESPACE
\l {QBluetoothServiceInfo::RfcommProtocol}{RFCOMM}.
\l {QBluetoothServiceInfo::L2capProtocol}{L2CAP} is a low level datagram-oriented Bluetooth socket.
+ Android and BlackBerry do not support \l {QBluetoothServiceInfo::L2capProtocol}{L2CAP} for socket
+ connections.
\l {QBluetoothServiceInfo::RfcommProtocol}{RFCOMM} is a reliable, stream-oriented socket. RFCOMM
sockets emulate an RS-232 serial port.
@@ -103,6 +108,8 @@ QT_BEGIN_NAMESPACE
\value NetworkError Attempt to read or write from socket returned an error
\value UnsupportedProtocolError The \l {QBluetoothServiceInfo::Protocol}{Protocol} is not
supported on this platform.
+ \value OperationError An operation was attempted while the socket was in a state
+ that did not permit it.
*/
/*!
@@ -166,19 +173,30 @@ QT_BEGIN_NAMESPACE
\fn QString QBluetoothSocket::localName() const
Returns the name of the local device.
+
+ Although some platforms may differ the socket must generally be connected to guarantee
+ the return of a valid name. In particular, this is true when dealing with platforms
+ that support multiple local Bluetooth adapters.
*/
/*!
\fn QBluetoothAddress QBluetoothSocket::localAddress() const
Returns the address of the local device.
+
+ Although some platforms may differ the socket must generally be connected to guarantee
+ the return of a valid address. In particular, this is true when dealing with platforms
+ that support multiple local Bluetooth adapters.
*/
/*!
\fn quint16 QBluetoothSocket::localPort() const
Returns the port number of the local socket if available, otherwise returns 0.
- On BlackBerry, this feature is not supported and returns 0.
+ Although some platforms may differ the socket must generally be connected to guarantee
+ the return of a valid port number.
+
+ On BlackBerry and Android, this feature is not supported and returns 0.
*/
/*!
@@ -197,7 +215,7 @@ QT_BEGIN_NAMESPACE
\fn quint16 QBluetoothSocket::peerPort() const
Return the port number of the peer socket if available, otherwise returns 0.
- On BlackBerry, this feature is not supported.
+ On BlackBerry and Android, this feature is not supported.
*/
/*!
@@ -277,51 +295,62 @@ qint64 QBluetoothSocket::bytesToWrite() const
/*!
Attempts to connect to the service described by \a service.
- The socket is opened in the given \a openMode.
+ The socket is opened in the given \a openMode. The \l socketType() may change
+ depending on the protocol required by \a service.
- For BlueZ, the socket first enters ConnectingState and attempts to connect to the device providing
+ The socket first enters ConnectingState and attempts to connect to the device providing
\a service. If a connection is established, QBluetoothSocket enters ConnectedState and
emits connected().
- On QNX the service connection can be established directly using the UUID of the remote service.
+ At any point, the socket can emit error() to signal that an error occurred.
- At any point, the socket can emit error() to siganl that an error occurred.
+ Note that most platforms require a pairing prior to connecting to the remote device. Otherwise
+ the connection process may fail.
\sa state(), disconnectFromService()
*/
void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, OpenMode openMode)
{
Q_D(QBluetoothSocket);
+
+ if (state() != QBluetoothSocket::UnconnectedState) {
+ qCWarning(QT_BT) << "QBluetoothSocket::connectToService called on busy socket";
+ d->errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
+ setSocketError(QBluetoothSocket::OperationError);
+ return;
+ }
+
setOpenMode(openMode);
-#ifdef QT_QNX_BLUETOOTH
- if (socketType() != QBluetoothServiceInfo::RfcommProtocol) {
- d->socketError = QBluetoothSocket::UnsupportedProtocolError;
+#if defined(QT_QNX_BLUETOOTH) || defined(QT_ANDROID_BLUETOOTH)
+ if (!d->ensureNativeSocket(service.socketProtocol())) {
d->errorString = tr("Socket type not supported");
- Q_EMIT error(d->socketError);
+ setSocketError(QBluetoothSocket::UnsupportedProtocolError);
return;
}
d->connectToService(service.device().address(), service.serviceUuid(), openMode);
#else
if (service.protocolServiceMultiplexer() > 0) {
if (!d->ensureNativeSocket(QBluetoothServiceInfo::L2capProtocol)) {
- emit error(UnknownSocketError);
+ d->errorString = tr("Unknown socket error");
+ setSocketError(UnknownSocketError);
return;
}
d->connectToService(service.device().address(), service.protocolServiceMultiplexer(), openMode);
} else if (service.serverChannel() > 0) {
if (!d->ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
- emit error(UnknownSocketError);
+ d->errorString = tr("Unknown socket error");
+ setSocketError(UnknownSocketError);
return;
}
d->connectToService(service.device().address(), service.serverChannel(), openMode);
} else {
// try doing service discovery to see if we can find the socket
if(service.serviceUuid().isNull()){
- qWarning() << "No port, no PSM, and no UUID provided, unable to connect";
+ qCWarning(QT_BT) << "No port, no PSM, and no UUID provided, unable to connect";
return;
}
- //qDebug() << "Need a port/psm, doing discovery";
+ qCDebug(QT_BT) << "Need a port/psm, doing discovery";
doDeviceDiscovery(service, openMode);
}
#endif
@@ -333,25 +362,38 @@ void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, Op
The socket is opened in the given \a openMode.
- For BlueZ, the socket first enters the ServiceLookupState and queries the connection parameters for
+ For BlueZ, the socket first enters the \l ServiceLookupState and queries the connection parameters for
\a uuid. If the service parameters are successfully retrieved the socket enters
ConnectingState, and attempts to connect to \a address. If a connection is established,
QBluetoothSocket enters Connected State and emits connected().
- On BlackBerry, the service connection can be established directly using the UUID of the remote service.
+ On BlackBerry and Android, the service connection can directly be established
+ using the UUID of the remote service. Therefore these platforms do not require
+ the \l ServiceLookupState and \l socketType() is always set to
+ \l QBluetoothServiceInfo::RfcommProtocol.
At any point, the socket can emit error() to signal that an error occurred.
+ Note that most platforms require a pairing prior to connecting to the remote device. Otherwise
+ the connection process may fail.
+
\sa state(), disconnectFromService()
*/
void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, OpenMode openMode)
{
-#ifdef QT_QNX_BLUETOOTH
Q_D(QBluetoothSocket);
- if (socketType() != QBluetoothServiceInfo::RfcommProtocol) {
- d->socketError = QBluetoothSocket::UnsupportedProtocolError;
+
+ if (state() != QBluetoothSocket::UnconnectedState) {
+ qCWarning(QT_BT) << "QBluetoothSocket::connectToService called on busy socket";
+ d->errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
+ setSocketError(QBluetoothSocket::OperationError);
+ return;
+ }
+
+#if defined(QT_QNX_BLUETOOTH) || defined(QT_ANDROID_BLUETOOTH)
+ if (!d->ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
d->errorString = tr("Socket type not supported");
- Q_EMIT error(d->socketError);
+ setSocketError(QBluetoothSocket::UnsupportedProtocolError);
return;
}
d->connectToService(address, uuid, openMode);
@@ -374,30 +416,43 @@ void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const
At any point, the socket can emit error() to signal that an error occurred.
- On BlackBerry, a connection to a service can not be established using a port. Calling this function
+ On BlackBerry and Android, a connection to a service can not be established using a port. Calling this function
will emit a \l {QBluetoothSocket::ServiceNotFoundError}{ServiceNotFoundError}
+ Note that most platforms require a pairing prior to connecting to the remote device. Otherwise
+ the connection process may fail.
+
\sa state(), disconnectFromService()
*/
void QBluetoothSocket::connectToService(const QBluetoothAddress &address, quint16 port, OpenMode openMode)
{
Q_D(QBluetoothSocket);
-#ifdef QT_QNX_BLUETOOTH
+#if defined(QT_QNX_BLUETOOTH) || defined(QT_ANDROID_BLUETOOTH)
Q_UNUSED(port);
Q_UNUSED(openMode);
Q_UNUSED(address);
- d->socketError = QBluetoothSocket::ServiceNotFoundError;
- d->errorString = tr("Connecting to port is not supported on QNX");
- Q_EMIT error(d->socketError);
- qWarning("Connecting to port is not supported");
+ d->errorString = tr("Connecting to port is not supported");
+ setSocketError(QBluetoothSocket::ServiceNotFoundError);
+ qCWarning(QT_BT) << "Connecting to port is not supported";
#else
+ if (state() != QBluetoothSocket::UnconnectedState) {
+ qCWarning(QT_BT) << "QBluetoothSocket::connectToService called on busy socket";
+ d->errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
+ setSocketError(QBluetoothSocket::OperationError);
+ return;
+ }
+
setOpenMode(openMode);
d->connectToService(address, port, openMode);
#endif
}
/*!
- Returns the socket type.
+ Returns the socket type. The socket automatically adjusts to the protocol
+ offered by the remote service.
+
+ Blackberry and Android only support \l{QBluetoothServiceInfo::RfcommProtocol}{RFCOMM}
+ based sockets.
*/
QBluetoothServiceInfo::Protocol QBluetoothSocket::socketType() const
{
@@ -482,13 +537,15 @@ void QBluetoothSocket::doDeviceDiscovery(const QBluetoothServiceInfo &service, O
Q_D(QBluetoothSocket);
setSocketState(QBluetoothSocket::ServiceLookupState);
- //qDebug() << "Starting discovery";
+ qCDebug(QT_BT) << "Starting discovery";
if(d->discoveryAgent) {
+ d->discoveryAgent->stop();
delete d->discoveryAgent;
}
- d->discoveryAgent = new QBluetoothServiceDiscoveryAgent(service.device().address(),this);
+ d->discoveryAgent = new QBluetoothServiceDiscoveryAgent(this);
+ d->discoveryAgent->setRemoteAddress(service.device().address());
//qDebug() << "Got agent";
@@ -506,7 +563,7 @@ void QBluetoothSocket::doDeviceDiscovery(const QBluetoothServiceInfo &service, O
// we have to ID the service somehow
Q_ASSERT(!d->discoveryAgent->uuidFilter().isEmpty());
- //qDebug() << "UUID filter" << d->discoveryAgent->uuidFilter();
+ qCDebug(QT_BT) << "UUID filter" << d->discoveryAgent->uuidFilter();
d->discoveryAgent->start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
}
@@ -514,7 +571,7 @@ void QBluetoothSocket::doDeviceDiscovery(const QBluetoothServiceInfo &service, O
void QBluetoothSocket::serviceDiscovered(const QBluetoothServiceInfo &service)
{
Q_D(QBluetoothSocket);
- //qDebug() << "FOUND SERVICE!" << service;
+ qCDebug(QT_BT) << "FOUND SERVICE!" << service;
if(service.protocolServiceMultiplexer() != 0 || service.serverChannel() != 0) {
connectToService(service, d->openMode);
d->discoveryAgent->deleteLater();
@@ -524,11 +581,13 @@ void QBluetoothSocket::serviceDiscovered(const QBluetoothServiceInfo &service)
void QBluetoothSocket::discoveryFinished()
{
- //qDebug() << "Socket discovery finished";
+ qCDebug(QT_BT) << "Socket discovery finished";
Q_D(QBluetoothSocket);
- if(d->discoveryAgent){
- //qDebug() << "Didn't find any";
- emit error(QBluetoothSocket::ServiceNotFoundError);
+ if (d->discoveryAgent){
+ qCDebug(QT_BT) << "Didn't find any";
+ d->errorString = tr("Service cannot be found");
+ setSocketError(ServiceNotFoundError);
+ setSocketState(QBluetoothSocket::UnconnectedState);
d->discoveryAgent->deleteLater();
d->discoveryAgent = 0;
}
@@ -536,6 +595,9 @@ void QBluetoothSocket::discoveryFinished()
void QBluetoothSocket::abort()
{
+ if (state() == UnconnectedState)
+ return;
+
Q_D(QBluetoothSocket);
d->abort();
setSocketState(QBluetoothSocket::UnconnectedState);
@@ -543,9 +605,7 @@ void QBluetoothSocket::abort()
void QBluetoothSocket::disconnectFromService()
{
- // TODO: is this all we need to do?
- Q_D(QBluetoothSocket);
- d->close();
+ close();
}
QString QBluetoothSocket::localName() const
@@ -598,6 +658,9 @@ qint64 QBluetoothSocket::readData(char *data, qint64 maxSize)
void QBluetoothSocket::close()
{
+ if (state() == UnconnectedState)
+ return;
+
Q_D(QBluetoothSocket);
setSocketState(ClosingState);
diff --git a/src/bluetooth/qbluetoothsocket.h b/src/bluetooth/qbluetoothsocket.h
index cc580d0b..0cc765cd 100644
--- a/src/bluetooth/qbluetoothsocket.h
+++ b/src/bluetooth/qbluetoothsocket.h
@@ -58,7 +58,7 @@ class QBluetoothServiceInfo;
class Q_BLUETOOTH_EXPORT QBluetoothSocket : public QIODevice
{
- Q_OBJECT
+ Q_OBJECT
Q_DECLARE_PRIVATE(QBluetoothSocket)
friend class QBluetoothServer;
@@ -78,11 +78,13 @@ public:
enum SocketError {
NoSocketError = -2,
- UnknownSocketError = QAbstractSocket::UnknownSocketError,
- HostNotFoundError = QAbstractSocket::HostNotFoundError,
- ServiceNotFoundError = QAbstractSocket::SocketAddressNotAvailableError,
- NetworkError = QAbstractSocket::NetworkError,
- UnsupportedProtocolError
+ UnknownSocketError = QAbstractSocket::UnknownSocketError, //-1
+ HostNotFoundError = QAbstractSocket::HostNotFoundError, //2
+ ServiceNotFoundError = QAbstractSocket::SocketAddressNotAvailableError, //9
+ NetworkError = QAbstractSocket::NetworkError, //7
+ UnsupportedProtocolError = 8,
+ OperationError = QAbstractSocket::OperationError //19
+ //New enums (independent of QAbstractSocket) should be added from 100 onwards
};
explicit QBluetoothSocket(QBluetoothServiceInfo::Protocol socketType, QObject *parent = 0); // create socket of type socketType
diff --git a/src/bluetooth/qbluetoothsocket_android.cpp b/src/bluetooth/qbluetoothsocket_android.cpp
new file mode 100644
index 00000000..93089182
--- /dev/null
+++ b/src/bluetooth/qbluetoothsocket_android.cpp
@@ -0,0 +1,451 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothsocket.h"
+#include "qbluetoothsocket_p.h"
+#include "qbluetoothaddress.h"
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QTime>
+#include <QtConcurrent/QtConcurrentRun>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+QBluetoothSocketPrivate::QBluetoothSocketPrivate()
+ : socket(-1),
+ socketType(QBluetoothServiceInfo::UnknownProtocol),
+ state(QBluetoothSocket::UnconnectedState),
+ socketError(QBluetoothSocket::NoSocketError),
+ connecting(false),
+ discoveryAgent(0),
+ inputThread(0)
+{
+ adapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
+ "getDefaultAdapter",
+ "()Landroid/bluetooth/BluetoothAdapter;");
+ qRegisterMetaType<QBluetoothSocket::SocketError>("QBluetoothSocket::SocketError");
+ qRegisterMetaType<QBluetoothSocket::SocketState>("QBluetoothSocket::SocketState");
+}
+
+QBluetoothSocketPrivate::~QBluetoothSocketPrivate()
+{
+}
+
+bool QBluetoothSocketPrivate::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
+{
+ socketType = type;
+ if (socketType == QBluetoothServiceInfo::RfcommProtocol)
+ return true;
+
+ return false;
+}
+
+//TODO Convert uuid parameter to const reference (affects QNX too)
+void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, QBluetoothUuid uuid, QIODevice::OpenMode openMode)
+{
+ Q_Q(QBluetoothSocket);
+
+ q->setSocketState(QBluetoothSocket::ConnectingState);
+ QtConcurrent::run(this, &QBluetoothSocketPrivate::connectToServiceConc, address, uuid, openMode);
+}
+
+void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &address,
+ const QBluetoothUuid &uuid, QIODevice::OpenMode openMode)
+{
+ Q_Q(QBluetoothSocket);
+ Q_UNUSED(openMode);
+
+ qDebug() << "GGGGConnecting to" << address.toString() << uuid.toString();
+ if (!adapter.isValid()) {
+ qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
+ errorString = QBluetoothSocket::tr("Device does not support Bluetooth");
+ q->setSocketError(QBluetoothSocket::NetworkError);
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
+ return;
+ }
+
+ const int state = adapter.callMethod<jint>("getState");
+ if (state != 12 ) { //BluetoothAdapter.STATE_ON
+ qCWarning(QT_BT_ANDROID) << "Bt device offline";
+ errorString = QBluetoothSocket::tr("Device is powered off");
+ q->setSocketError(QBluetoothSocket::NetworkError);
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
+ return;
+ }
+
+ QAndroidJniEnvironment env;
+ QAndroidJniObject inputString = QAndroidJniObject::fromString(address.toString());
+ remoteDevice = adapter.callObjectMethod("getRemoteDevice",
+ "(Ljava/lang/String;)Landroid/bluetooth/BluetoothDevice;",
+ inputString.object<jstring>());
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+
+ errorString = QBluetoothSocket::tr("Cannot access address %1", "%1 = Bt address e.g. 11:22:33:44:55:66").arg(address.toString());
+ q->setSocketError(QBluetoothSocket::HostNotFoundError);
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
+ return;
+ }
+
+ //cut leading { and trailing } {xxx-xxx}
+ QString tempUuid = uuid.toString();
+ tempUuid.chop(1); //remove trailing '}'
+ tempUuid.remove(0, 1); //remove first '{'
+
+ inputString = QAndroidJniObject::fromString(tempUuid);
+ QAndroidJniObject uuidObject = QAndroidJniObject::callStaticObjectMethod("java/util/UUID", "fromString",
+ "(Ljava/lang/String;)Ljava/util/UUID;",
+ inputString.object<jstring>());
+
+ socketObject = remoteDevice.callObjectMethod("createRfcommSocketToServiceRecord",
+ "(Ljava/util/UUID;)Landroid/bluetooth/BluetoothSocket;",
+ uuidObject.object<jobject>());
+
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+
+ socketObject = remoteDevice = QAndroidJniObject();
+ errorString = QBluetoothSocket::tr("Cannot connect to %1 on %2",
+ "%1 = uuid, %2 = Bt address").arg(uuid.toString()).arg(address.toString());
+ q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
+ return;
+ }
+
+ socketObject.callMethod<void>("connect");
+ if (env->ExceptionCheck() || socketObject.callMethod<jboolean>("isConnected") == JNI_FALSE) {
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ socketObject = remoteDevice = QAndroidJniObject();
+ errorString = QBluetoothSocket::tr("Connection to service failed");
+ q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
+ return;
+ }
+
+ if (inputThread) {
+ inputThread->stop();
+ inputThread->wait();
+ delete inputThread;
+ inputThread = 0;
+ }
+
+ inputStream = socketObject.callObjectMethod("getInputStream", "()Ljava/io/InputStream;");
+ outputStream = socketObject.callObjectMethod("getOutputStream", "()Ljava/io/OutputStream;");
+
+ if (env->ExceptionCheck() || !inputStream.isValid() || !outputStream.isValid()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+
+ //close socket again
+ socketObject.callMethod<void>("close");
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ socketObject = inputStream = outputStream = remoteDevice = QAndroidJniObject();
+
+
+ errorString = QBluetoothSocket::tr("Obtaining streams for service failed");
+ q->setSocketError(QBluetoothSocket::NetworkError);
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
+ return;
+ }
+
+ inputThread = new InputStreamThread(this);
+ QObject::connect(inputThread, SIGNAL(dataAvailable()), q, SIGNAL(readyRead()), Qt::QueuedConnection);
+ QObject::connect(inputThread, SIGNAL(error()),
+ this, SLOT(inputThreadError()), Qt::QueuedConnection);
+ inputThread->start();
+
+ q->setSocketState(QBluetoothSocket::ConnectedState);
+ emit q->connected();
+}
+
+void QBluetoothSocketPrivate::_q_writeNotify()
+{
+}
+
+void QBluetoothSocketPrivate::_q_readNotify()
+{
+}
+
+void QBluetoothSocketPrivate::abort()
+{
+ if (state == QBluetoothSocket::UnconnectedState)
+ return;
+
+ if (socketObject.isValid()) {
+ QAndroidJniEnvironment env;
+
+ /*
+ * BluetoothSocket.close() triggers an abort of the input stream
+ * thread because inputStream.read() throws IOException
+ * In turn the thread stops and throws an error which sets
+ * new state, error and emits relevant signals.
+ * See QBluetoothSocketPrivate::inputThreadError() for details
+ */
+ //triggers abort of input thread as well
+ socketObject.callMethod<void>("close");
+ if (env->ExceptionCheck()) {
+
+ qCWarning(QT_BT_ANDROID) << "Error during closure of socket";
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ if (inputThread) {
+ inputThread->stop();
+ inputThread->wait();
+ delete inputThread;
+ inputThread = 0;
+ }
+
+ inputStream = outputStream = socketObject = remoteDevice = QAndroidJniObject();
+ }
+}
+
+QString QBluetoothSocketPrivate::localName() const
+{
+ if (adapter.isValid())
+ return adapter.callObjectMethod<jstring>("getName").toString();
+
+ return QString();
+}
+
+QBluetoothAddress QBluetoothSocketPrivate::localAddress() const
+{
+ QString result;
+ if (adapter.isValid())
+ result = adapter.callObjectMethod("getAddress", "()Ljava/lang/String;").toString();
+
+ return QBluetoothAddress(result);
+}
+
+quint16 QBluetoothSocketPrivate::localPort() const
+{
+ // Impossible to get channel number with current Android API (Levels 5 to 19)
+ return 0;
+}
+
+QString QBluetoothSocketPrivate::peerName() const
+{
+ if (!remoteDevice.isValid())
+ return QString();
+
+ return remoteDevice.callObjectMethod("getName", "()Ljava/lang/String;").toString();
+}
+
+QBluetoothAddress QBluetoothSocketPrivate::peerAddress() const
+{
+ if (!remoteDevice.isValid())
+ return QBluetoothAddress();
+
+ const QString address = remoteDevice.callObjectMethod("getAddress",
+ "()Ljava/lang/String;").toString();
+
+ return QBluetoothAddress(address);
+}
+
+quint16 QBluetoothSocketPrivate::peerPort() const
+{
+ // Impossible to get channel number with current Android API (Levels 5 to 13)
+ return 0;
+}
+
+qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize)
+{
+ //TODO implement buffered behavior (so far only unbuffered)
+ //TODO check that readData and writeData return -1 on error (on all platforms)
+ Q_Q(QBluetoothSocket);
+ if (state != QBluetoothSocket::ConnectedState || !outputStream.isValid()) {
+ qCWarning(QT_BT_ANDROID) << "Socket::writeData: " << (int)state << outputStream.isValid() ;
+ errorString = QBluetoothSocket::tr("Cannot write while not connected");
+ q->setSocketError(QBluetoothSocket::OperationError);
+ return -1;
+ }
+
+ QAndroidJniEnvironment env;
+ jbyteArray nativeData = env->NewByteArray((qint32)maxSize);
+ env->SetByteArrayRegion(nativeData, 0, (qint32)maxSize, reinterpret_cast<const jbyte*>(data));
+ outputStream.callMethod<void>("write", "([BII)V", nativeData, 0, (qint32)maxSize);
+ env->DeleteLocalRef(nativeData);
+
+ if (env->ExceptionCheck()) {
+ qCWarning(QT_BT_ANDROID) << "Error while writing";
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ errorString = QBluetoothSocket::tr("Error during write on socket.");
+ q->setSocketError(QBluetoothSocket::NetworkError);
+ return -1;
+ }
+
+ return maxSize;
+}
+
+qint64 QBluetoothSocketPrivate::readData(char *data, qint64 maxSize)
+{
+ Q_Q(QBluetoothSocket);
+ if (state != QBluetoothSocket::ConnectedState || !inputThread) {
+ qCWarning(QT_BT_ANDROID) << "Socket::writeData: " << (int)state << outputStream.isValid() ;
+ errorString = QBluetoothSocket::tr("Cannot write while not connected");
+ q->setSocketError(QBluetoothSocket::OperationError);
+ return -1;
+ }
+
+ return inputThread->readData(data, maxSize);
+}
+
+void QBluetoothSocketPrivate::inputThreadError()
+{
+ Q_Q(QBluetoothSocket);
+
+ //any error from InputThread is a NetworkError
+ errorString = QBluetoothSocket::tr("Network error during read");
+ q->setSocketError(QBluetoothSocket::NetworkError);
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
+ emit q->disconnected();
+}
+
+void QBluetoothSocketPrivate::close()
+{
+ /* This function is called by QBluetoothSocket::close and softer version
+ QBluetoothSocket::disconnectFromService() which difference I do not quite fully understand.
+ Anyways we end up in Android "close" function call.
+ */
+ abort();
+}
+
+bool QBluetoothSocketPrivate::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
+ QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
+{
+ Q_UNUSED(socketDescriptor);
+ Q_UNUSED(socketType)
+ Q_UNUSED(socketState);
+ Q_UNUSED(openMode);
+ qCWarning(QT_BT_ANDROID) << "No socket descriptor support on Android.";
+ return false;
+}
+
+bool QBluetoothSocketPrivate::setSocketDescriptor(const QAndroidJniObject &socket, QBluetoothServiceInfo::Protocol socketType_,
+ QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
+{
+ Q_Q(QBluetoothSocket);
+
+ if (q->state() != QBluetoothSocket::UnconnectedState || !socket.isValid())
+ return false;
+
+ if (!ensureNativeSocket(socketType_))
+ return false;
+
+ socketObject = socket;
+
+ QAndroidJniEnvironment env;
+ inputStream = socketObject.callObjectMethod("getInputStream", "()Ljava/io/InputStream;");
+ outputStream = socketObject.callObjectMethod("getOutputStream", "()Ljava/io/OutputStream;");
+
+ if (env->ExceptionCheck() || !inputStream.isValid() || !outputStream.isValid()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+
+ //close socket again
+ socketObject.callMethod<void>("close");
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ socketObject = inputStream = outputStream = remoteDevice = QAndroidJniObject();
+
+
+ errorString = QBluetoothSocket::tr("Obtaining streams for service failed");
+ q->setSocketError(QBluetoothSocket::NetworkError);
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
+ return false;
+ }
+
+ if (inputThread) {
+ inputThread->stop();
+ inputThread->wait();
+ delete inputThread;
+ inputThread = 0;
+ }
+ inputThread = new InputStreamThread(this);
+ QObject::connect(inputThread, SIGNAL(dataAvailable()), q, SIGNAL(readyRead()), Qt::QueuedConnection);
+ QObject::connect(inputThread, SIGNAL(error()),
+ this, SLOT(inputThreadError()), Qt::QueuedConnection);
+ inputThread->start();
+
+
+ q->setSocketState(socketState);
+ q->setOpenMode(openMode);
+
+ if (openMode == QBluetoothSocket::ConnectedState)
+ emit q->connected();
+
+ return true;
+}
+
+int QBluetoothSocketPrivate::socketDescriptor() const
+{
+ return 0;
+}
+
+qint64 QBluetoothSocketPrivate::bytesAvailable() const
+{
+ //We cannot access buffer directly as it is part of different thread
+ if (inputThread)
+ return inputThread->bytesAvailable();
+
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothsocket_bluez.cpp b/src/bluetooth/qbluetoothsocket_bluez.cpp
index c6f332e3..235f21d3 100644
--- a/src/bluetooth/qbluetoothsocket_bluez.cpp
+++ b/src/bluetooth/qbluetoothsocket_bluez.cpp
@@ -48,6 +48,7 @@
#include <qplatformdefs.h>
+#include <QtCore/QLoggingCategory>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/l2cap.h>
@@ -60,10 +61,13 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
QBluetoothSocketPrivate::QBluetoothSocketPrivate()
: socket(-1),
socketType(QBluetoothServiceInfo::UnknownProtocol),
state(QBluetoothSocket::UnconnectedState),
+ socketError(QBluetoothSocket::NoSocketError),
readNotifier(0),
connectWriteNotifier(0),
connecting(false),
@@ -114,7 +118,7 @@ bool QBluetoothSocketPrivate::ensureNativeSocket(QBluetoothServiceInfo::Protocol
Q_Q(QBluetoothSocket);
readNotifier = new QSocketNotifier(socket, QSocketNotifier::Read);
QObject::connect(readNotifier, SIGNAL(activated(int)), q, SLOT(_q_readNotify()));
- connectWriteNotifier = new QSocketNotifier(socket, QSocketNotifier::Write, q);
+ connectWriteNotifier = new QSocketNotifier(socket, QSocketNotifier::Write, q);
QObject::connect(connectWriteNotifier, SIGNAL(activated(int)), q, SLOT(_q_writeNotify()));
connectWriteNotifier->setEnabled(false);
@@ -162,7 +166,7 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address,
connecting = true;
q->setSocketState(QBluetoothSocket::ConnectingState);
} else {
- errorString = QString::fromLocal8Bit(strerror(errno));
+ errorString = qt_error_string(errno);
q->setSocketError(QBluetoothSocket::UnknownSocketError);
}
}
@@ -175,8 +179,8 @@ void QBluetoothSocketPrivate::_q_writeNotify()
len = sizeof(errorno);
::getsockopt(socket, SOL_SOCKET, SO_ERROR, &errorno, (socklen_t*)&len);
if(errorno) {
- errorString = QString::fromLocal8Bit(strerror(errorno));
- emit q->error(QBluetoothSocket::UnknownSocketError);
+ errorString = qt_error_string(errorno);
+ q->setSocketError(QBluetoothSocket::UnknownSocketError);
return;
}
@@ -193,13 +197,12 @@ void QBluetoothSocketPrivate::_q_writeNotify()
}
char buf[1024];
- Q_Q(QBluetoothSocket);
int size = txBuffer.read(buf, 1024);
if (::write(socket, buf, size) != size) {
- socketError = QBluetoothSocket::NetworkError;
- emit q->error(socketError);
+ errorString = QBluetoothSocket::tr("Network Error");
+ q->setSocketError(QBluetoothSocket::NetworkError);
}
else {
emit q->bytesWritten(size);
@@ -212,7 +215,7 @@ void QBluetoothSocketPrivate::_q_writeNotify()
connectWriteNotifier->setEnabled(false);
this->close();
}
- }
+ }
}
// TODO: move to private backend?
@@ -227,15 +230,15 @@ void QBluetoothSocketPrivate::_q_readNotify()
int errsv = errno;
readNotifier->setEnabled(false);
connectWriteNotifier->setEnabled(false);
- errorString = QString::fromLocal8Bit(strerror(errsv));
- qWarning() << Q_FUNC_INFO << socket << "error:" << readFromDevice << errorString;
+ errorString = qt_error_string(errsv);
+ qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << socket << "error:" << readFromDevice << errorString;
if(errsv == EHOSTDOWN)
- emit q->error(QBluetoothSocket::HostNotFoundError);
+ q->setSocketError(QBluetoothSocket::HostNotFoundError);
else
- emit q->error(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::UnknownSocketError);
q->disconnectFromService();
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
}
else {
buffer.chop(QPRIVATELINEARBUFFER_BUFFERSIZE - (readFromDevice < 0 ? 0 : readFromDevice));
@@ -255,6 +258,7 @@ void QBluetoothSocketPrivate::abort()
// we don't call disconnectFromService or
// QBluetoothSocket::close
QT_CLOSE(socket);
+ socket = -1;
Q_Q(QBluetoothSocket);
emit q->disconnected();
@@ -262,9 +266,6 @@ void QBluetoothSocketPrivate::abort()
QString QBluetoothSocketPrivate::localName() const
{
- if (!m_localName.isEmpty())
- return m_localName;
-
const QBluetoothAddress address = localAddress();
if (address.isNull())
return QString();
@@ -285,9 +286,7 @@ QString QBluetoothSocketPrivate::localName() const
if (properties.isError())
return QString();
- m_localName = properties.value().value(QLatin1String("Name")).toString();
-
- return m_localName;
+ return properties.value().value(QLatin1String("Name")).toString();
}
QBluetoothAddress QBluetoothSocketPrivate::localAddress() const
@@ -336,9 +335,6 @@ quint16 QBluetoothSocketPrivate::localPort() const
QString QBluetoothSocketPrivate::peerName() const
{
- if (!m_peerName.isEmpty())
- return m_peerName;
-
quint64 bdaddr;
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
@@ -358,7 +354,7 @@ QString QBluetoothSocketPrivate::peerName() const
convertAddress(addr.l2_bdaddr.b, bdaddr);
} else {
- qWarning("peerName() called on socket of known type");
+ qCWarning(QT_BT_BLUEZ) << "peerName() called on socket of unknown type";
return QString();
}
@@ -396,9 +392,7 @@ QString QBluetoothSocketPrivate::peerName() const
if (properties.isError())
return QString();
- m_peerName = properties.value().value(QLatin1String("Alias")).toString();
-
- return m_peerName;
+ return properties.value().value(QLatin1String("Alias")).toString();
}
QBluetoothAddress QBluetoothSocketPrivate::peerAddress() const
@@ -450,8 +444,8 @@ qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize)
Q_Q(QBluetoothSocket);
if (q->openMode() & QIODevice::Unbuffered) {
if (::write(socket, data, maxSize) != maxSize) {
- socketError = QBluetoothSocket::NetworkError;
- emit q->error(socketError);
+ errorString = QBluetoothSocket::tr("Network Error");
+ q->setSocketError(QBluetoothSocket::NetworkError);
}
emit q->bytesWritten(maxSize);
@@ -464,7 +458,7 @@ qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize)
return 0;
if(txBuffer.size() == 0) {
- connectWriteNotifier->setEnabled(true);
+ connectWriteNotifier->setEnabled(true);
QMetaObject::invokeMethod(q, "_q_writeNotify", Qt::QueuedConnection);
}
@@ -507,7 +501,8 @@ void QBluetoothSocketPrivate::close()
// We are disconnected now, so go to unconnected.
q->setSocketState(QBluetoothSocket::UnconnectedState);
emit q->disconnected();
- ::close(socket);
+ QT_CLOSE(socket);
+ socket = -1;
}
}
diff --git a/src/bluetooth/qbluetoothsocket_p.h b/src/bluetooth/qbluetoothsocket_p.h
index 92712911..95e67e51 100644
--- a/src/bluetooth/qbluetoothsocket_p.h
+++ b/src/bluetooth/qbluetoothsocket_p.h
@@ -47,6 +47,11 @@
#ifdef QT_QNX_BLUETOOTH
#include "qnx/ppshelpers_p.h"
#endif
+#ifdef QT_ANDROID_BLUETOOTH
+#include <QtAndroidExtras/QAndroidJniObject>
+#include "android/inputstreamthread_p.h"
+#include <jni.h>
+#endif
#ifndef QPRIVATELINEARBUFFER_BUFFERSIZE
#define QPRIVATELINEARBUFFER_BUFFERSIZE Q_INT64_C(16384)
@@ -74,7 +79,7 @@ class QBluetoothSocket;
class QBluetoothServiceDiscoveryAgent;
class QBluetoothSocketPrivate
-#ifdef QT_QNX_BLUETOOTH
+#if defined(QT_QNX_BLUETOOTH) || defined(QT_ANDROID_BLUETOOTH)
: public QObject
{
Q_OBJECT
@@ -87,12 +92,16 @@ public:
QBluetoothSocketPrivate();
~QBluetoothSocketPrivate();
-//On qnx we connect using the uuid not the port
-#ifdef QT_QNX_BLUETOOTH
+//On QNX and Android we connect using the uuid not the port
+#if defined(QT_QNX_BLUETOOTH) || defined(QT_ANDROID_BLUETOOTH)
void connectToService(const QBluetoothAddress &address, QBluetoothUuid uuid, QIODevice::OpenMode openMode);
#else
void connectToService(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode);
#endif
+#ifdef QT_ANDROID_BLUETOOTH
+ void connectToServiceConc(const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode);
+#endif
+
bool ensureNativeSocket(QBluetoothServiceInfo::Protocol type);
@@ -114,6 +123,11 @@ public:
qint64 writeData(const char *data, qint64 maxSize);
qint64 readData(char *data, qint64 maxSize);
+#ifdef QT_ANDROID_BLUETOOTH
+ bool setSocketDescriptor(const QAndroidJniObject &socket, QBluetoothServiceInfo::Protocol socketType,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite);
+#endif
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite);
@@ -146,12 +160,23 @@ public:
void _q_serviceDiscovered(const QBluetoothServiceInfo &service);
void _q_discoveryFinished();
+#ifdef QT_ANDROID_BLUETOOTH
+ QAndroidJniObject adapter;
+ QAndroidJniObject socketObject;
+ QAndroidJniObject remoteDevice;
+ QAndroidJniObject inputStream;
+ QAndroidJniObject outputStream;
+ InputStreamThread *inputThread;
+
+private Q_SLOTS:
+ void inputThreadError();
+
+#endif
+
protected:
QBluetoothSocket *q_ptr;
private:
- mutable QString m_localName;
- mutable QString m_peerName;
#ifdef QT_QNX_BLUETOOTH
QBluetoothAddress m_peerAddress;
QBluetoothUuid m_uuid;
diff --git a/src/bluetooth/qbluetoothsocket_qnx.cpp b/src/bluetooth/qbluetoothsocket_qnx.cpp
index 6e14ae13..81c46dd7 100644
--- a/src/bluetooth/qbluetoothsocket_qnx.cpp
+++ b/src/bluetooth/qbluetoothsocket_qnx.cpp
@@ -50,6 +50,7 @@ QBluetoothSocketPrivate::QBluetoothSocketPrivate()
: socket(-1),
socketType(QBluetoothServiceInfo::UnknownProtocol),
state(QBluetoothSocket::UnconnectedState),
+ socketError(QBluetoothSocket::NoSocketError),
readNotifier(0),
connectWriteNotifier(0),
connecting(false),
@@ -68,13 +69,16 @@ QBluetoothSocketPrivate::~QBluetoothSocketPrivate()
bool QBluetoothSocketPrivate::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
{
socketType = type;
+ if (socketType == QBluetoothServiceInfo::RfcommProtocol)
+ return true;
+
return false;
}
void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, QBluetoothUuid uuid, QIODevice::OpenMode openMode)
{
Q_UNUSED(openMode);
- qBBBluetoothDebug() << "Connecting socket";
+ qCDebug(QT_BT_QNX) << "Connecting socket";
if (isServerSocket) {
m_peerAddress = address;
m_uuid = uuid;
@@ -82,7 +86,7 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address,
}
if (state != QBluetoothSocket::UnconnectedState) {
- qBBBluetoothDebug() << "Socket already connected";
+ qCDebug(QT_BT_QNX) << "Socket already connected";
return;
}
state = QBluetoothSocket::ConnectingState;
@@ -117,8 +121,8 @@ void QBluetoothSocketPrivate::_q_writeNotify()
int size = txBuffer.read(buf, 1024);
if (::write(socket, buf, size) != size) {
- socketError = QBluetoothSocket::NetworkError;
- emit q->error(socketError);
+ errorString = QBluetoothSocket::tr("Network Error");
+ q->setSocketError(QBluetoothSocket::NetworkError);
}
else {
emit q->bytesWritten(size);
@@ -143,9 +147,9 @@ void QBluetoothSocketPrivate::_q_readNotify()
int errsv = errno;
readNotifier->setEnabled(false);
connectWriteNotifier->setEnabled(false);
- errorString = QString::fromLocal8Bit(strerror(errsv));
- qWarning() << Q_FUNC_INFO << socket << " error:" << readFromDevice << errorString; //TODO Try if this actually works
- emit q->error(QBluetoothSocket::UnknownSocketError);
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << socket << " error:" << readFromDevice << errorString; //TODO Try if this actually works
+ errorString = qt_error_string(errsv);
+ q->setSocketError(QBluetoothSocket::UnknownSocketError);
q->disconnectFromService();
q->setSocketState(QBluetoothSocket::UnconnectedState);
@@ -159,7 +163,7 @@ void QBluetoothSocketPrivate::_q_readNotify()
void QBluetoothSocketPrivate::abort()
{
Q_Q(QBluetoothSocket);
- qBBBluetoothDebug() << "Disconnecting service";
+ qCDebug(QT_BT_QNX) << "Disconnecting service";
if (q->state() != QBluetoothSocket::ClosingState)
ppsSendControlMessage("disconnect_service", 0x1101, m_uuid, m_peerAddress.toString(), QString(), 0,
isServerSocket ? BT_SPP_SERVER_SUBTYPE : BT_SPP_CLIENT_SUBTYPE);
@@ -194,7 +198,7 @@ quint16 QBluetoothSocketPrivate::localPort() const
QString QBluetoothSocketPrivate::peerName() const
{
- return m_peerName;
+ return QString();
}
QBluetoothAddress QBluetoothSocketPrivate::peerAddress() const
@@ -212,9 +216,9 @@ qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize)
Q_Q(QBluetoothSocket);
if (q->openMode() & QIODevice::Unbuffered) {
if (::write(socket, data, maxSize) != maxSize) {
- socketError = QBluetoothSocket::NetworkError;
- qWarning() << Q_FUNC_INFO << "Socket error";
- Q_EMIT q->error(socketError);
+ errorString = QBluetoothSocket::tr("Network Error");
+ q->setSocketError(QBluetoothSocket::NetworkError);
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "Socket error";
}
Q_EMIT q->bytesWritten(maxSize);
@@ -250,7 +254,7 @@ void QBluetoothSocketPrivate::close()
abort();
}
-bool QBluetoothSocketPrivate::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
+bool QBluetoothSocketPrivate::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType_,
QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
{
Q_Q(QBluetoothSocket);
@@ -260,7 +264,7 @@ bool QBluetoothSocketPrivate::setSocketDescriptor(int socketDescriptor, QBluetoo
connectWriteNotifier = 0;
socket = socketDescriptor;
- socketType = socketType;
+ socketType = socketType_;
// ensure that O_NONBLOCK is set on new connections.
int flags = fcntl(socket, F_GETFL, 0);
@@ -300,35 +304,33 @@ void QBluetoothSocketPrivate::controlReply(ppsResult result)
if (result.msg == QStringLiteral("connect_service")) {
if (!result.errorMsg.isEmpty()) {
- qWarning() << Q_FUNC_INFO << "Error connecting to service:" << result.errorMsg;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "Error connecting to service:" << result.errorMsg;
errorString = result.errorMsg;
- socketError = QBluetoothSocket::UnknownSocketError;
- emit q->error(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::UnknownSocketError);
q->setSocketState(QBluetoothSocket::UnconnectedState);
return;
} else {
- qBBBluetoothDebug() << Q_FUNC_INFO << "Sending request for mount point";
+ qCDebug(QT_BT_QNX) << Q_FUNC_INFO << "Sending request for mount point";
ppsSendControlMessage("get_mount_point_path", 0x1101, m_uuid, m_peerAddress.toString(), QString(), this, BT_SPP_CLIENT_SUBTYPE);
}
} else if (result.msg == QStringLiteral("get_mount_point_path")) {
QString path;
path = result.dat.first();
- qBBBluetoothDebug() << Q_FUNC_INFO << "PATH is" << path;
+ qCDebug(QT_BT_QNX) << Q_FUNC_INFO << "PATH is" << path;
if (!result.errorMsg.isEmpty()) {
- qWarning() << Q_FUNC_INFO << result.errorMsg;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << result.errorMsg;
errorString = result.errorMsg;
- socketError = QBluetoothSocket::UnknownSocketError;
- emit q->error(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::UnknownSocketError);
q->setSocketState(QBluetoothSocket::UnconnectedState);
return;
} else {
- qBBBluetoothDebug() << "Mount point path is:" << path;
+ qCDebug(QT_BT_QNX) << "Mount point path is:" << path;
socket = ::open(path.toStdString().c_str(), O_RDWR);
if (socket == -1) {
- errorString = QString::fromLocal8Bit(strerror(errno));
- qWarning() << Q_FUNC_INFO << socket << " error:" << errno << errorString; //TODO Try if this actually works
- emit q->error(QBluetoothSocket::UnknownSocketError);
+ errorString = qt_error_string(errno);
+ q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << socket << " error:" << errno << errorString; //TODO Try if this actually works
q->disconnectFromService();
q->setSocketState(QBluetoothSocket::UnconnectedState);
diff --git a/src/bluetooth/qbluetoothtransfermanager.cpp b/src/bluetooth/qbluetoothtransfermanager.cpp
index ffb4862c..6e1d7f83 100644
--- a/src/bluetooth/qbluetoothtransfermanager.cpp
+++ b/src/bluetooth/qbluetoothtransfermanager.cpp
@@ -58,6 +58,8 @@ QT_BEGIN_NAMESPACE
using Object Push Profile (OPP).
QBluetoothTransferManager uses OBEX to send put commands to remote devices.
+
+ Note that this API is not currently supported on Android.
*/
/*!
@@ -65,6 +67,8 @@ QT_BEGIN_NAMESPACE
Sends the contents of \a data to the remote device identified by \a request, and returns a new
QBluetoothTransferReply that can be used to track the request's progress.
+
+ If the platform does not support the Object Push profile, this function will return \c 0.
*/
diff --git a/src/bluetooth/qbluetoothtransfermanager.h b/src/bluetooth/qbluetoothtransfermanager.h
index 520e0d73..501a40a0 100644
--- a/src/bluetooth/qbluetoothtransfermanager.h
+++ b/src/bluetooth/qbluetoothtransfermanager.h
@@ -63,7 +63,7 @@ public:
explicit QBluetoothTransferManager(QObject *parent = 0);
~QBluetoothTransferManager();
- QBluetoothTransferReply *put(const QBluetoothTransferRequest &request, QIODevice *data);
+ QBluetoothTransferReply *put(const QBluetoothTransferRequest &request, QIODevice *data);
Q_SIGNALS:
void finished(QBluetoothTransferReply *reply);
diff --git a/src/bluetooth/qbluetoothtransferreply_bluez.cpp b/src/bluetooth/qbluetoothtransferreply_bluez.cpp
index 0634f080..8b271789 100644
--- a/src/bluetooth/qbluetoothtransferreply_bluez.cpp
+++ b/src/bluetooth/qbluetoothtransferreply_bluez.cpp
@@ -49,6 +49,7 @@
#include "bluez/obex_transfer_p.h"
#include "qbluetoothtransferreply.h"
+#include <QtCore/QLoggingCategory>
#include <QFuture>
#include <QFutureWatcher>
#include <QtConcurrentRun>
@@ -57,6 +58,8 @@ static const QLatin1String agentPath("/qt/agent");
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
QBluetoothTransferReplyBluez::QBluetoothTransferReplyBluez(QIODevice *input, const QBluetoothTransferRequest &request,
QBluetoothTransferManager *parent)
: QBluetoothTransferReply(parent), tempfile(0), source(input),
@@ -76,7 +79,7 @@ QBluetoothTransferReplyBluez::QBluetoothTransferReplyBluez(QIODevice *input, con
bool res = QDBusConnection::sessionBus().registerObject(m_agent_path, this);
if(!res)
- qWarning() << "Failed Creating dbus objects";
+ qCWarning(QT_BT_BLUEZ) << "Failed Creating dbus objects";
qRegisterMetaType<QBluetoothTransferReply*>("QBluetoothTransferReply*");
QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection);
@@ -100,7 +103,7 @@ bool QBluetoothTransferReplyBluez::start()
if(!file){
tempfile = new QTemporaryFile(this );
tempfile->open();
-// qDebug() << "Not a QFile, making a copy" << tempfile->fileName();
+ qCDebug(QT_BT_BLUEZ) << "Not a QFile, making a copy" << tempfile->fileName();
QFutureWatcher<bool> *watcher = new QFutureWatcher<bool>();
QObject::connect(watcher, SIGNAL(finished()), this, SLOT(copyDone()));
@@ -110,7 +113,7 @@ bool QBluetoothTransferReplyBluez::start()
}
else {
if (!file->exists()) {
- m_errorStr = QBluetoothTransferReply::tr("File does not exist");
+ m_errorStr = QBluetoothTransferReply::tr("Source file does not exist");
m_error = QBluetoothTransferReply::FileNotFoundError;
m_finished = true;
m_running = false;
@@ -125,7 +128,7 @@ bool QBluetoothTransferReplyBluez::start()
QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection, Q_ARG(QBluetoothTransferReply*, this));
return false;
}
- m_size = file->size();
+ m_size = file->size();
startOPP(file->fileName());
}
return true;
@@ -272,7 +275,7 @@ void QBluetoothTransferReplyBluez::abort()
QDBusPendingReply<> reply = xfer->Cancel();
reply.waitForFinished();
if(reply.isError()){
- qWarning() << "Failed to abort transfer" << reply.error();
+ qCWarning(QT_BT_BLUEZ) << "Failed to abort transfer" << reply.error();
}
delete xfer;
}
diff --git a/src/bluetooth/qbluetoothtransferreply_qnx.cpp b/src/bluetooth/qbluetoothtransferreply_qnx.cpp
index b3425300..bc15fbde 100644
--- a/src/bluetooth/qbluetoothtransferreply_qnx.cpp
+++ b/src/bluetooth/qbluetoothtransferreply_qnx.cpp
@@ -114,7 +114,7 @@ bool QBluetoothTransferReplyQnx::start()
} else {
if (!file->exists()) {
- m_errorStr = QBluetoothTransferReply::tr("File does not exist");
+ m_errorStr = QBluetoothTransferReply::tr("Source file does not exist");
m_error = QBluetoothTransferReply::FileNotFoundError;
m_finished = true;
m_running = false;
@@ -150,14 +150,14 @@ bool QBluetoothTransferReplyQnx::copyToTempFile(QIODevice *to, QIODevice *from)
void QBluetoothTransferReplyQnx::copyDone()
{
- qBBBluetoothDebug() << "Copy done";
+ qCDebug(QT_BT_QNX) << "Copy done";
startOPP(tempfile->fileName());
QObject::sender()->deleteLater();
}
void QBluetoothTransferReplyQnx::startOPP(QString filename)
{
- qBBBluetoothDebug() << "Sending Push object command";
+ qCDebug(QT_BT_QNX) << "Sending Push object command";
ppsSendOpp("push_object", filename.toUtf8(), request().address(), this);
}
@@ -182,7 +182,7 @@ void QBluetoothTransferReplyQnx::controlReply(ppsResult result)
void QBluetoothTransferReplyQnx::controlEvent(ppsResult result)
{
if (result.msg == QStringLiteral("opp_cancelled")) {
- qBBBluetoothDebug() << "opp cancelled" << result.errorMsg << result.error;
+ qCDebug(QT_BT_QNX) << "opp cancelled" << result.errorMsg << result.error;
if (m_running)
return;
m_finished = true;
@@ -203,18 +203,18 @@ void QBluetoothTransferReplyQnx::controlEvent(ppsResult result)
bool ok;
qint64 sentBytes = result.dat.at(result.dat.indexOf(QStringLiteral("sent")) + 1).toDouble(&ok);
if (!ok) {
- qWarning() << "Could not convert sent bytes";
+ qCWarning(QT_BT_QNX) << "Could not convert sent bytes";
return;
}
qint64 totalBytes = result.dat.at(result.dat.indexOf(QStringLiteral("total")) + 1).toDouble(&ok);
if (!ok) {
- qWarning() << "Could not convert total bytes";
+ qCWarning(QT_BT_QNX) << "Could not convert total bytes";
return;
}
- qBBBluetoothDebug() << "opp update" << sentBytes << totalBytes;
+ qCDebug(QT_BT_QNX) << "opp update" << sentBytes << totalBytes;
Q_EMIT transferProgress(sentBytes, totalBytes);
} else if (result.msg == QStringLiteral("opp_complete")) {
- qBBBluetoothDebug() << "opp complete";
+ qCDebug(QT_BT_QNX) << "opp complete";
m_finished = true;
m_running = false;
Q_EMIT finished(this);
diff --git a/src/bluetooth/qbluetoothtransferrequest.h b/src/bluetooth/qbluetoothtransferrequest.h
index 072d330f..b91429a0 100644
--- a/src/bluetooth/qbluetoothtransferrequest.h
+++ b/src/bluetooth/qbluetoothtransferrequest.h
@@ -72,7 +72,7 @@ public:
void setAttribute(Attribute code, const QVariant &value);
QBluetoothAddress address() const;
-
+
bool operator!=(const QBluetoothTransferRequest &other) const;
QBluetoothTransferRequest &operator=(const QBluetoothTransferRequest &other);
bool operator==(const QBluetoothTransferRequest &other) const;
diff --git a/src/bluetooth/qbluetoothuuid.cpp b/src/bluetooth/qbluetoothuuid.cpp
index 9bb8ef67..9dadad7c 100644
--- a/src/bluetooth/qbluetoothuuid.cpp
+++ b/src/bluetooth/qbluetoothuuid.cpp
@@ -42,13 +42,8 @@
#include "qbluetoothuuid.h"
#include <QStringList>
-
-#include <QDebug>
-
#include <QtEndian>
-//#include <arpa/inet.h>
-//#include <netinet/in.h>
#include <string.h>
QT_BEGIN_NAMESPACE
diff --git a/src/bluetooth/qnx/ppshelpers.cpp b/src/bluetooth/qnx/ppshelpers.cpp
index 4acb36ef..9b1d3e4b 100644
--- a/src/bluetooth/qnx/ppshelpers.cpp
+++ b/src/bluetooth/qnx/ppshelpers.cpp
@@ -99,12 +99,12 @@ void ppsRegisterControl()
count++;
if (count == 1) {
if (ppsCtrlFD != -1) {
- qBBBluetoothDebug() << "PPS control FD not properly deinitialized";
+ qCDebug(QT_BT_QNX) << "PPS control FD not properly deinitialized";
return;
}
ppsCtrlFD = qt_safe_open(btControlFDPath, O_RDWR | O_SYNC);
if (ppsCtrlFD == -1) {
- qWarning() << Q_FUNC_INFO << "ppsCtrlFD - failed to qt_safe_open" << btControlFDPath;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "ppsCtrlFD - failed to qt_safe_open" << btControlFDPath;
} else {
ppsCtrlNotifier = new QSocketNotifier(ppsCtrlFD, QSocketNotifier::Read);
QObject::connect(ppsCtrlNotifier, SIGNAL(activated(int)), &bbSocketNotifier, SLOT(distribute()));
@@ -140,11 +140,11 @@ pps_encoder_t *beginCtrlMessage(const char *msg, QObject *sender)
bool endCtrlMessage(pps_encoder_t *encoder)
{
- qBBBluetoothDebug() << "writing" << pps_encoder_buffer(encoder);
+ qCDebug(QT_BT_QNX) << "writing" << pps_encoder_buffer(encoder);
if (pps_encoder_buffer(encoder) != 0) {
int res = qt_safe_write(ppsCtrlFD, pps_encoder_buffer(encoder), pps_encoder_length(encoder));
if (res == -1) {
- qWarning() << Q_FUNC_INFO << "Error when writing to control FD. Is Bluetooth powerd on?"
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "Error when writing to control FD. Is Bluetooth powerd on?"
<< errno << ppsCtrlFD << count;
return false;
}
@@ -206,7 +206,7 @@ void ppsDecodeControlResponse()
qt_safe_read(ppsCtrlFD, &buf, sizeof(buf) );
if (buf[0] != '@')
return;
- qBBBluetoothDebug() << "CTRL Response" << buf;
+ qCDebug(QT_BT_QNX) << "CTRL Response" << buf;
pps_decoder_t ppsDecoder;
pps_decoder_initialize(&ppsDecoder, 0);
@@ -266,16 +266,16 @@ void ppsDecodeControlResponse()
}
}
} else {
- qBBBluetoothDebug() << "Control Response: No node type" << result.msg;
+ qCDebug(QT_BT_QNX) << "Control Response: No node type" << result.msg;
}
}
pps_decoder_cleanup(&ppsDecoder);
}
if (result.msg == QStringLiteral("radio_init")) {
- qBBBluetoothDebug() << "Radio initialized";
+ qCDebug(QT_BT_QNX) << "Radio initialized";
} else if (result.msg == QStringLiteral("access_changed") && __newHostMode != -1) {
- qBBBluetoothDebug() << "Access changed after radio init";
+ qCDebug(QT_BT_QNX) << "Access changed after radio init";
ppsSendControlMessage("set_access", QStringLiteral("{\"access\":%1}").arg(__newHostMode), 0);
__newHostMode = -1;
}
@@ -285,7 +285,7 @@ void ppsDecodeControlResponse()
if (wMessage.second != 0)
wMessage.second->metaObject()->invokeMethod(wMessage.second, "controlReply", Q_ARG(ppsResult, result));
} else if (resType == EVENT) {
- //qBBBluetoothDebug() << "Distributing event" << result.msg;
+ //qCDebug(QT_BT_QNX) << "Distributing event" << result.msg;
for (int i=0; i < evtRegistration.size(); i++) {
if (result.msg == evtRegistration.at(i).first)
evtRegistration.at(i).second->metaObject()->invokeMethod(evtRegistration.at(i).second, "controlEvent", Q_ARG(ppsResult, result));
@@ -312,7 +312,7 @@ QVariant ppsReadSetting(const char *property)
int settingsFD;
char buf[ppsBufferSize];
if ((settingsFD = qt_safe_open(btSettingsFDPath, O_RDONLY)) == -1) {
- qWarning() << Q_FUNC_INFO << "failed to open "<< btSettingsFDPath;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "failed to open "<< btSettingsFDPath;
return QVariant();
}
@@ -329,31 +329,31 @@ QVariant ppsReadSetting(const char *property)
const char *dat;
if (pps_decoder_get_string(&decoder, property, &dat) == PPS_DECODER_OK) {
result = QString::fromUtf8(dat);
- qBBBluetoothDebug() << "Read setting" << result;
+ qCDebug(QT_BT_QNX) << "Read setting" << result;
} else {
- qWarning() << Q_FUNC_INFO << "could not read"<< property;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "could not read"<< property;
return QVariant();
}
} else if (nodeType == PPS_TYPE_BOOL) {
bool dat;
if (pps_decoder_get_bool(&decoder, property, &dat) == PPS_DECODER_OK) {
result = dat;
- qBBBluetoothDebug() << "Read setting" << result;
+ qCDebug(QT_BT_QNX) << "Read setting" << result;
} else {
- qWarning() << Q_FUNC_INFO << "could not read"<< property;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "could not read"<< property;
return QVariant();
}
} else if (nodeType == PPS_TYPE_NUMBER) {
int dat;
if (pps_decoder_get_int(&decoder, property, &dat) == PPS_DECODER_OK) {
result = dat;
- qBBBluetoothDebug() << "Read setting" << result;
+ qCDebug(QT_BT_QNX) << "Read setting" << result;
} else {
- qWarning() << Q_FUNC_INFO << "could not read"<< property;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "could not read"<< property;
return QVariant();
}
} else {
- qBBBluetoothDebug() << Q_FUNC_INFO << "unrecognized entry for settings";
+ qCDebug(QT_BT_QNX) << Q_FUNC_INFO << "unrecognized entry for settings";
}
}
pps_decoder_cleanup(&decoder);
@@ -369,7 +369,7 @@ QVariant ppsRemoteDeviceStatus(const QByteArray &address, const char *property)
filename.append(address);
if ((rmFD = qt_safe_open(filename.constData(), O_RDONLY)) < 0) {
- qWarning() << Q_FUNC_INFO << "failed to open "<< btRemoteDevFDPath << address;
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "failed to open "<< btRemoteDevFDPath << address;
return false;
}
@@ -392,7 +392,7 @@ QVariant ppsRemoteDeviceStatus(const QByteArray &address, const char *property)
pps_decoder_get_bool(&ppsDecoder,property,&dat);
res = QVariant(dat);
} else {
- qBBBluetoothDebug() << "RDStatus: No node type" << property;
+ qCDebug(QT_BT_QNX) << "RDStatus: No node type" << property;
}
}
pps_decoder_cleanup(&ppsDecoder);
@@ -408,11 +408,11 @@ bool ppsReadRemoteDevice(int fd, pps_decoder_t *decoder, QBluetoothAddress *btAd
addr_buf[17] = '\0';
if (qt_safe_read(fd, &buf, sizeof(buf)) == -1) {
- qWarning() << Q_FUNC_INFO << "Could not qt_safe_read from pps remote device file";
+ qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "Could not qt_safe_read from pps remote device file";
return false;
}
- qBBBluetoothDebug() << "Remote device" << buf;
+ qCDebug(QT_BT_QNX) << "Remote device" << buf;
//the address of the BT device is stored at the beginning of the qt_safe_read
if (buf[0] != '-') {
diff --git a/src/bluetooth/qnx/ppshelpers_p.h b/src/bluetooth/qnx/ppshelpers_p.h
index 1633bab8..0eaea981 100644
--- a/src/bluetooth/qnx/ppshelpers_p.h
+++ b/src/bluetooth/qnx/ppshelpers_p.h
@@ -57,23 +57,20 @@
#include <errno.h>
#include <sys/pps.h>
-#include <QSocketNotifier>
-#include <QStringList>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QSocketNotifier>
+#include <QtCore/QStringList>
#include <QtBluetooth/qbluetoothuuid.h>
#include <QtBluetooth/qbluetoothaddress.h>
-#ifdef BT_BBPPSDEBUG
-#define qBBBluetoothDebug qDebug
-#else
-#define qBBBluetoothDebug QT_NO_QDEBUG_MACRO
-#endif
-
#define BT_SPP_SERVER_SUBTYPE 1
#define BT_SPP_CLIENT_SUBTYPE 2
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_QNX)
+
class BBSocketNotifier : public QObject
{
Q_OBJECT