summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.qmake.conf1
-rw-r--r--config.tests/libbb2/libbb2.pro5
-rw-r--r--config.tests/libbb2/main.cpp47
-rw-r--r--dist/changes-5.2.158
-rw-r--r--examples/bluetooth/bluetooth.pro5
-rw-r--r--examples/bluetooth/btchat/btchat.pro3
-rw-r--r--examples/bluetooth/btfiletransfer/btfiletransfer.pro3
-rw-r--r--examples/bluetooth/btscanner/btscanner.pro2
-rw-r--r--examples/bluetooth/bttennis/bttennis.pro6
-rw-r--r--examples/bluetooth/picturetransfer/Button.qml65
-rw-r--r--examples/bluetooth/picturetransfer/DeviceDiscovery.qml91
-rw-r--r--examples/bluetooth/picturetransfer/FileSending.qml101
-rw-r--r--examples/bluetooth/picturetransfer/PictureSelector.qml132
-rw-r--r--examples/bluetooth/picturetransfer/background.pngbin0 -> 189737 bytes
-rw-r--r--examples/bluetooth/picturetransfer/bttransfer.qml73
-rw-r--r--examples/bluetooth/picturetransfer/doc/images/opp-example-1.pngbin0 -> 152761 bytes
-rw-r--r--examples/bluetooth/picturetransfer/doc/images/opp-example-2.pngbin0 -> 155969 bytes
-rw-r--r--examples/bluetooth/picturetransfer/doc/images/opp-example-3.pngbin0 -> 169273 bytes
-rw-r--r--examples/bluetooth/picturetransfer/doc/src/picturetransfer.qdoc91
-rw-r--r--examples/bluetooth/picturetransfer/filetransfer.cpp67
-rw-r--r--examples/bluetooth/picturetransfer/filetransfer.h68
-rw-r--r--examples/bluetooth/picturetransfer/icon.pngbin0 -> 4712 bytes
-rw-r--r--examples/bluetooth/picturetransfer/main.cpp66
-rw-r--r--examples/bluetooth/picturetransfer/picturetransfer.pro25
-rw-r--r--examples/bluetooth/picturetransfer/qmltransfer.qrc10
-rw-r--r--examples/bluetooth/scanner/Button.qml8
-rw-r--r--examples/bluetooth/scanner/qmlscanner.cpp2
-rw-r--r--examples/bluetooth/scanner/scanner.pro8
-rw-r--r--examples/bluetooth/scanner/scanner.qml32
-rw-r--r--examples/nfc/annotatedurl/annotatedurl.pro2
-rw-r--r--examples/nfc/corkboard/Mode.qml157
-rw-r--r--examples/nfc/corkboard/NfcFlag.pngbin0 -> 8591 bytes
-rw-r--r--examples/nfc/corkboard/bar-descriptor.xml32
-rw-r--r--examples/nfc/corkboard/cork.jpgbin0 -> 149337 bytes
-rw-r--r--examples/nfc/corkboard/corkboard.pro14
-rw-r--r--examples/nfc/corkboard/corkboard.qrc10
-rw-r--r--examples/nfc/corkboard/corkboards.qml88
-rw-r--r--examples/nfc/corkboard/doc/images/corkboard.pngbin0 -> 639743 bytes
-rw-r--r--examples/nfc/corkboard/doc/src/corkboard.qdoc39
-rw-r--r--examples/nfc/corkboard/icon.pngbin0 -> 6594 bytes
-rw-r--r--examples/nfc/corkboard/main.cpp54
-rw-r--r--examples/nfc/corkboard/note-yellow.pngbin0 -> 54559 bytes
-rw-r--r--examples/nfc/corkboard/tack.pngbin0 -> 7282 bytes
-rw-r--r--examples/nfc/ndefeditor/ndefeditor.pro3
-rw-r--r--examples/nfc/nfc.pro2
-rw-r--r--examples/nfc/poster/poster.pro3
-rw-r--r--qtconnectivity.pro1
-rw-r--r--src/android/android.pro2
-rw-r--r--src/android/bluetooth/AndroidManifest.xml7
-rw-r--r--src/android/bluetooth/bluetooth.pri12
-rw-r--r--src/android/bluetooth/bluetooth.pro2
-rw-r--r--src/android/bluetooth/bundledjar.pro3
-rw-r--r--src/android/bluetooth/distributedjar.pro2
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java116
-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
-rw-r--r--src/imports/bluetooth/plugin.cpp8
-rw-r--r--src/imports/bluetooth/plugins.qmltypes7
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp26
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothservice.cpp24
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothsocket.cpp18
-rw-r--r--src/imports/nfc/plugin.cpp5
-rw-r--r--src/imports/nfc/plugins.qmltypes10
-rw-r--r--src/nfc/doc/qtnfc.qdocconf2
-rw-r--r--src/nfc/doc/src/examples.qdoc3
-rw-r--r--src/nfc/doc/src/nfc-index.qdoc1
-rw-r--r--src/nfc/nfc.pro53
-rw-r--r--src/nfc/qllcpserver_p.cpp2
-rw-r--r--src/nfc/qllcpsocket.cpp2
-rw-r--r--src/nfc/qllcpsocket_p.cpp2
-rw-r--r--src/nfc/qnearfieldmanager_qnx.cpp10
-rw-r--r--src/nfc/qnearfieldsharemanager.cpp186
-rw-r--r--src/nfc/qnearfieldsharemanager.h106
-rw-r--r--src/nfc/qnearfieldsharemanager_p.h82
-rw-r--r--src/nfc/qnearfieldsharemanager_qnx_p.cpp151
-rw-r--r--src/nfc/qnearfieldsharemanager_qnx_p.h83
-rw-r--r--src/nfc/qnearfieldsharemanagerimpl_p.cpp60
-rw-r--r--src/nfc/qnearfieldsharemanagerimpl_p.h60
-rw-r--r--src/nfc/qnearfieldsharetarget.cpp151
-rw-r--r--src/nfc/qnearfieldsharetarget.h86
-rw-r--r--src/nfc/qnearfieldsharetarget_p.h99
-rw-r--r--src/nfc/qnearfieldsharetarget_qnx_p.cpp120
-rw-r--r--src/nfc/qnearfieldsharetarget_qnx_p.h85
-rw-r--r--src/nfc/qnearfieldsharetargetimpl_p.cpp55
-rw-r--r--src/nfc/qnearfieldsharetargetimpl_p.h59
-rw-r--r--src/nfc/qnx/qnxnfcmanager.cpp4
-rw-r--r--src/nfc/qnx/qnxnfcsharemanager_p.cpp280
-rw-r--r--src/nfc/qnx/qnxnfcsharemanager_p.h90
-rw-r--r--src/nfc/qqmlndefrecord.cpp1
-rw-r--r--src/src.pro1
-rw-r--r--sync.profile1
-rw-r--r--tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp20
-rw-r--r--tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp19
-rw-r--r--tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp23
-rw-r--r--tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp8
-rw-r--r--tests/btclient/btclient.c12
-rw-r--r--tests/bttestui/Button.qml66
-rw-r--r--tests/bttestui/README21
-rw-r--r--tests/bttestui/btlocaldevice.cpp710
-rw-r--r--tests/bttestui/btlocaldevice.h135
-rw-r--r--tests/bttestui/bttest.qrc6
-rw-r--r--tests/bttestui/bttestui.pro16
-rw-r--r--tests/bttestui/main.cpp67
-rw-r--r--tests/bttestui/main.qml262
-rw-r--r--tests/tests.pro2
172 files changed, 9375 insertions, 537 deletions
diff --git a/.gitignore b/.gitignore
index 4d888b1d..7263c4fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,7 @@ moc_*.cpp
ui_*.h
qrc_*.cpp
*.moc
+*so-deployment-settings.json
.qmake.cache
config.log
tmp
@@ -31,6 +32,7 @@ examples/bluetooth/scanner/qml_scanner
examples/nfc/annotatedurl/annotatedurl
examples/nfc/ndefeditor/ndefeditor
examples/nfc/poster/qml_poster
+examples/nfc/corkboard/qml_corkboard
tests/auto/cmake/build
tests/auto/qbluetoothaddress/tst_qbluetoothaddress
tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent
diff --git a/.qmake.conf b/.qmake.conf
index 16328b7d..efd0e68f 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,4 @@
load(qt_build_config)
+CONFIG += qt_example_installs
MODULE_VERSION = 5.3.0
diff --git a/config.tests/libbb2/libbb2.pro b/config.tests/libbb2/libbb2.pro
new file mode 100644
index 00000000..92c9b765
--- /dev/null
+++ b/config.tests/libbb2/libbb2.pro
@@ -0,0 +1,5 @@
+TEMPLATE = app
+
+TARGET = blackberry
+
+SOURCES += main.cpp
diff --git a/config.tests/libbb2/main.cpp b/config.tests/libbb2/main.cpp
new file mode 100644
index 00000000..0f7707f8
--- /dev/null
+++ b/config.tests/libbb2/main.cpp
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtConnectivity 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$
+**
+****************************************************************************/
+#define BB_CORE_GLOBAL_HPP
+#include "bb2/bb/Global"
+
+int main()
+{
+ return 0;
+}
diff --git a/dist/changes-5.2.1 b/dist/changes-5.2.1
new file mode 100644
index 00000000..efcf5363
--- /dev/null
+++ b/dist/changes-5.2.1
@@ -0,0 +1,58 @@
+Qt 5.2.1 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.2.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+ http://qt-project.org/doc/qt-5.2
+
+The Qt version 5.2 series is binary compatible with the 5.1.x series.
+Applications compiled for 5.1 will continue to run with 5.2.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+ http://bugreports.qt-project.org/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* General *
+****************************************************************************
+
+General Improvements
+--------------------
+
+ - Fixed make install rules for all examples
+
+ - Minor code improvements made such as removal of compiler warnings and
+ code cleanups.
+
+****************************************************************************
+* Library *
+****************************************************************************
+
+QtBluetooth
+-----------
+
+ - Fixed cases where device and service discovery classes emitted an error
+ signal but the human readable error string was not adjusted
+
+ - Marked untranslated error strings for translation
+
+ - [QTBUG-32253]
+ * Utilized new QLoggingCategory API for warnings and debug messages
+
+QtNfc
+------
+
+****************************************************************************
+* Platform Specific Changes *
+****************************************************************************
+
+Blackberry
+-------
+
+ - Dangling pointer in QBluetoothServiceDiscoveryAgent fixed
+
diff --git a/examples/bluetooth/bluetooth.pro b/examples/bluetooth/bluetooth.pro
index 4d520550..78ba1fc1 100644
--- a/examples/bluetooth/bluetooth.pro
+++ b/examples/bluetooth/bluetooth.pro
@@ -6,5 +6,6 @@ qtHaveModule(widgets) {
bttennis
}
-SUBDIRS += scanner \
- lowenergyscanner
+qtHaveModule(quick): SUBDIRS += scanner \
+ picturetransfer \
+ lowenergyscanner
diff --git a/examples/bluetooth/btchat/btchat.pro b/examples/bluetooth/btchat/btchat.pro
index 6d6a928b..08fdd4a7 100644
--- a/examples/bluetooth/btchat/btchat.pro
+++ b/examples/bluetooth/btchat/btchat.pro
@@ -19,3 +19,6 @@ HEADERS = \
FORMS = \
chat.ui \
remoteselector.ui
+
+target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/btchat
+INSTALLS += target
diff --git a/examples/bluetooth/btfiletransfer/btfiletransfer.pro b/examples/bluetooth/btfiletransfer/btfiletransfer.pro
index 58d4e638..00b16415 100644
--- a/examples/bluetooth/btfiletransfer/btfiletransfer.pro
+++ b/examples/bluetooth/btfiletransfer/btfiletransfer.pro
@@ -25,3 +25,6 @@ OTHER_FILES += \
RESOURCES += \
btfiletransfer.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/scanner
+INSTALLS += target
diff --git a/examples/bluetooth/btscanner/btscanner.pro b/examples/bluetooth/btscanner/btscanner.pro
index 81d83cae..f1254629 100644
--- a/examples/bluetooth/btscanner/btscanner.pro
+++ b/examples/bluetooth/btscanner/btscanner.pro
@@ -16,3 +16,5 @@ FORMS = \
device.ui \
service.ui
+target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/btscanner
+INSTALLS += target
diff --git a/examples/bluetooth/bttennis/bttennis.pro b/examples/bluetooth/bttennis/bttennis.pro
index 878795da..1c014784 100644
--- a/examples/bluetooth/bttennis/bttennis.pro
+++ b/examples/bluetooth/bttennis/bttennis.pro
@@ -28,3 +28,9 @@ FORMS = \
RESOURCES += \
tennis.qrc
+
+OTHER_FILES = \
+ connect.png
+
+target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/bttennis
+INSTALLS += target
diff --git a/examples/bluetooth/picturetransfer/Button.qml b/examples/bluetooth/picturetransfer/Button.qml
new file mode 100644
index 00000000..eed6a4e9
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/Button.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+
+Rectangle {
+ property alias text: label.text
+ signal clicked();
+ opacity: 0.7
+ height: label.height + 30
+ width: label.width + 90
+ border.color: Qt.lighter("#67b0d1")
+ border.width: 1
+ color: mArea.pressed ? "#5c9fba" : "#67b0d1"
+ Text {
+ id: label
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.pointSize: 10
+ color: "black"
+ }
+ MouseArea {
+ id: mArea
+ anchors.fill: parent
+ onClicked: parent.clicked()
+ }
+}
diff --git a/examples/bluetooth/picturetransfer/DeviceDiscovery.qml b/examples/bluetooth/picturetransfer/DeviceDiscovery.qml
new file mode 100644
index 00000000..1da77975
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/DeviceDiscovery.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** 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:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+import QtBluetooth 5.2
+
+Item {
+ Rectangle {
+ id: title
+ opacity: 0.7
+ height: titleLabel.height + 90
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.margins: 100
+
+ color: "#5c9fba"
+ Text {
+ id: titleLabel
+ text: "Select device"
+ color: "black"
+ font.pointSize: 15
+ anchors.centerIn: parent
+ }
+ }
+
+//! [Discovery-1]
+ ListView {
+//! [Discovery-1]
+ id: listView
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.top: title.bottom
+ anchors.topMargin: 0
+ anchors.margins: 100
+ clip: true
+ add: Transition {
+ NumberAnimation { properties: "x"; from: 1000; duration: 500 }
+ }
+//! [Discovery-2]
+ model: BluetoothDiscoveryModel {
+ discoveryMode: BluetoothDiscoveryModel.DeviceDiscovery
+ }
+
+ delegate: Button {
+ width: listView.width + 2
+ text: model.name
+ onClicked: root.remoteDevice = model.remoteAddress
+ }
+ }
+//! [Discovery-2]
+}
diff --git a/examples/bluetooth/picturetransfer/FileSending.qml b/examples/bluetooth/picturetransfer/FileSending.qml
new file mode 100644
index 00000000..3a4a282f
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/FileSending.qml
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+
+Item {
+ Button {
+ x: 40
+ y: 40
+ text: "Back"
+ onClicked: loader.source = "DeviceDiscovery.qml"
+ }
+
+ Text {
+ anchors.bottom: theProgress.top
+ anchors.left: theProgress.left
+ anchors.right: parent.right
+ anchors.rightMargin: 100
+ anchors.bottomMargin: 40
+ wrapMode: Text.Wrap
+ color: "white"
+ text: "Sending file: " + root.fileName + "<br>" + "Remote-Device:" + root.remoteDevice
+ }
+
+ Rectangle {
+ id: theProgress
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.leftMargin: 100
+ width: (parent.width - 200) * fileTransfer.progress
+ height: 50
+ color: "#5c9fba"
+ opacity: 0.7
+ Behavior on width {
+ NumberAnimation {duration: 300}
+ }
+ }
+ Text {
+ text: "0%"
+ anchors.horizontalCenter: theProgress.left
+ anchors.top: theProgress.bottom
+ anchors.topMargin: 10
+ color: "white"
+ }
+
+ Text {
+ text: "100%"
+ anchors.right: parent.right
+ anchors.rightMargin: 100 - width/2
+ anchors.top: theProgress.bottom
+ anchors.topMargin: 10
+ color: "white"
+ }
+
+ Image {
+ anchors.top: theProgress.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.margins: 60
+ fillMode: Image.PreserveAspectFit
+ source: "file://" + root.fileName
+ }
+}
diff --git a/examples/bluetooth/picturetransfer/PictureSelector.qml b/examples/bluetooth/picturetransfer/PictureSelector.qml
new file mode 100644
index 00000000..ca81ae44
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/PictureSelector.qml
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** 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:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+import Qt.labs.folderlistmodel 1.0
+
+Item {
+ Rectangle {
+ id: title
+ opacity: 0.7
+ height: titleLabel.height + 90
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.margins: 70
+
+ color: "#5c9fba"
+ Text {
+ id: titleLabel
+ text: "Select picture"
+ color: "white"
+ font.bold: true
+ font.pointSize: 15
+ anchors.centerIn: parent
+ }
+ }
+
+ ListView {
+ id: listView
+ clip: true
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.top: title.bottom
+ anchors.topMargin: 0
+ anchors.margins: 70
+ spacing: 5
+ add: Transition {
+ NumberAnimation { properties: "x"; from: 1000; duration: 500 }
+ }
+
+//! [FileSelect-1]
+ model: FolderListModel {
+ folder: "file://"+SystemPictureFolder
+ showDirs: false
+ }
+
+ delegate: Rectangle {
+//! [FileSelect-1]
+ opacity: 0.7
+ height: label.height + 130
+ width: listView.width + 2
+ x: -1
+ border.color: Qt.lighter("#67b0d1")
+ border.width: 1
+ color: mArea.pressed ? "#5c9fba" : "#67b0d1"
+ Image {
+ id: picture
+ anchors.verticalCenter: parent.verticalCenter
+ height: parent.height-10
+ fillMode: Image.PreserveAspectFit
+ asynchronous: true
+ source: "file://" + model.filePath
+ }
+
+//! [FileSelect-2]
+ Text {
+//! [FileSelect-2]
+ id: label
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.margins: 20
+ anchors.left: picture.right
+//! [FileSelect-3]
+ text: model.fileName
+//! [FileSelect-3]
+ font.bold: true
+ font.pointSize: 10
+ color: "white"
+ wrapMode: Text.WordWrap
+//! [FileSelect-4]
+ }
+ MouseArea {
+ id: mArea
+ anchors.fill: parent
+ onClicked: {
+ print ("path: " + model.filePath + " " + model.fileName)
+ root.fileName = model.filePath
+ }
+ }
+ }
+//! [FileSelect-4]
+ }
+}
diff --git a/examples/bluetooth/picturetransfer/background.png b/examples/bluetooth/picturetransfer/background.png
new file mode 100644
index 00000000..c9f80fb5
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/background.png
Binary files differ
diff --git a/examples/bluetooth/picturetransfer/bttransfer.qml b/examples/bluetooth/picturetransfer/bttransfer.qml
new file mode 100644
index 00000000..bdfb47f0
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/bttransfer.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** 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:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+
+//! [Root-1]
+Image {
+ id: root
+//! [Root-1]
+ width: 600; height: 800
+ fillMode: Image.PreserveAspectCrop
+ source: "background.png"
+//! [Root-2]
+ property string remoteDevice;
+ property string fileName;
+//! [Root-2]
+ onRemoteDeviceChanged: {
+ loader.source = "PictureSelector.qml"
+ }
+
+//! [Root-3]
+ onFileNameChanged: {
+ fileTransfer.initTransfer(remoteDevice, fileName);
+ loader.source = "FileSending.qml"
+ }
+//! [Root-3]
+
+ Loader {
+ id: loader
+ anchors.fill: parent
+ source: "DeviceDiscovery.qml"
+ }
+//! [Root-4]
+}
+//! [Root-4]
diff --git a/examples/bluetooth/picturetransfer/doc/images/opp-example-1.png b/examples/bluetooth/picturetransfer/doc/images/opp-example-1.png
new file mode 100644
index 00000000..0b33bc8a
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/doc/images/opp-example-1.png
Binary files differ
diff --git a/examples/bluetooth/picturetransfer/doc/images/opp-example-2.png b/examples/bluetooth/picturetransfer/doc/images/opp-example-2.png
new file mode 100644
index 00000000..d3d325d5
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/doc/images/opp-example-2.png
Binary files differ
diff --git a/examples/bluetooth/picturetransfer/doc/images/opp-example-3.png b/examples/bluetooth/picturetransfer/doc/images/opp-example-3.png
new file mode 100644
index 00000000..cef9830c
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/doc/images/opp-example-3.png
Binary files differ
diff --git a/examples/bluetooth/picturetransfer/doc/src/picturetransfer.qdoc b/examples/bluetooth/picturetransfer/doc/src/picturetransfer.qdoc
new file mode 100644
index 00000000..fc2ffa32
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/doc/src/picturetransfer.qdoc
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the QtBluetooth module.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\example picturetransfer
+\title QML Bluetooth Picture Push Example
+
+The Bluetooth Picture Push example shows how to use the \l QBluetoothTransferManager
+API. The example transfers a local image to a remote device.
+
+On the first user interface page the application scans for remote Bluetooth devices. The user must select
+the appropriate device to continue:
+
+\image opp-example-1.png
+
+The next page presents a list of image files on the device. The files must be located under
+\l QStandardPaths::PictureLocation}:
+
+\image opp-example-2.png
+
+Once the picture was selected the UI shows the progress of the file transfer:
+
+\image opp-example-3.png
+
+\section1 Device Discovery
+
+The device discovery uses the \l BluetoothDiscoveryModel to detect the remote devices. Each discovery is displayed
+as an entry in a list. Once a device was selected the device address is stored in the \c root element. More
+details about the \c root element will follow further below.
+
+\snippet picturetransfer/DeviceDiscovery.qml Discovery-1
+\snippet picturetransfer/DeviceDiscovery.qml Discovery-2
+
+\section1 File Selection
+
+The file is selected with the help of \l FolderListModel. Once again the selected file is stored in the \c root
+element:
+
+\snippet picturetransfer/PictureSelector.qml FileSelect-1
+\snippet picturetransfer/PictureSelector.qml FileSelect-2
+\snippet picturetransfer/PictureSelector.qml FileSelect-3
+\snippet picturetransfer/PictureSelector.qml FileSelect-4
+
+\section1 The root element
+
+The already mentioned \c root element collects the necessary pieces of data for the picture transfer.
+Once the file name has been set it triggers the file transfer:
+
+
+\snippet picturetransfer/bttransfer.qml Root-1
+\snippet picturetransfer/bttransfer.qml Root-2
+\snippet picturetransfer/bttransfer.qml Root-3
+\snippet picturetransfer/bttransfer.qml Root-3
+
+\section1 The File Transfer
+
+The file transfer is implemented in C++:
+
+\snippet picturetransfer/filetransfer.cpp Transfer-1
+
+and exposed to QML via a context property:
+
+\snippet picturetransfer/main.cpp Transfer-2
+
+
+
+*/
diff --git a/examples/bluetooth/picturetransfer/filetransfer.cpp b/examples/bluetooth/picturetransfer/filetransfer.cpp
new file mode 100644
index 00000000..7cfd041d
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/filetransfer.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "filetransfer.h"
+#include <QFile>
+#include <QBluetoothTransferReply>
+#include <QDebug>
+
+FileTransfer::FileTransfer(QObject *parent) :
+ QObject(parent), m_progress(0)
+{
+}
+
+//! [Transfer-1]
+void FileTransfer::initTransfer(QString address, QString fileName)
+{
+ qDebug() << "Begin sharing file: " << address << fileName;
+ QBluetoothAddress btAddress = QBluetoothAddress(address);
+ QBluetoothTransferRequest request(btAddress);
+ QFile *file = new QFile(fileName);
+ reply = manager.put(request, file);
+ connect(reply, SIGNAL(transferProgress(qint64,qint64)), this, SLOT(updateProgress(qint64,qint64)));
+}
+//! [Transfer-1]
+
+void FileTransfer::updateProgress(qint64 transferred, qint64 total)
+{
+ m_progress = ((float)transferred)/((float)total);
+ Q_EMIT progressChanged();
+}
diff --git a/examples/bluetooth/picturetransfer/filetransfer.h b/examples/bluetooth/picturetransfer/filetransfer.h
new file mode 100644
index 00000000..1bc9c78d
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/filetransfer.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FILETRANSFER_H
+#define FILETRANSFER_H
+
+#include <QObject>
+#include <QBluetoothTransferManager>
+
+class FileTransfer : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(float progress READ getProgress NOTIFY progressChanged)
+public:
+ explicit FileTransfer(QObject *parent = 0);
+ float getProgress() { return m_progress;}
+
+signals:
+ void progressChanged();
+
+public slots:
+ void initTransfer(QString address, QString fileName);
+ void updateProgress(qint64,qint64);
+
+private:
+ QBluetoothTransferManager manager;
+ QBluetoothTransferReply *reply;
+ float m_progress;
+};
+
+#endif // FILETRANSFER_H
diff --git a/examples/bluetooth/picturetransfer/icon.png b/examples/bluetooth/picturetransfer/icon.png
new file mode 100644
index 00000000..e378a26d
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/icon.png
Binary files differ
diff --git a/examples/bluetooth/picturetransfer/main.cpp b/examples/bluetooth/picturetransfer/main.cpp
new file mode 100644
index 00000000..7db3053e
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/main.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QtQml/QQmlEngine>
+#include <QtQuick/QQuickView>
+#include <QDebug>
+#include <QQmlContext>
+#include <QStandardPaths>
+#include "filetransfer.h"
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication application(argc, argv);
+//! [Transfer-2]
+ QQuickView view;
+ FileTransfer fileTransfer;
+ view.rootContext()->setContextProperty("fileTransfer", QVariant::fromValue(&fileTransfer));
+//! [Transfer-2]
+ view.rootContext()->setContextProperty("SystemPictureFolder",
+ QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first());
+ qDebug() << QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
+
+ view.setSource(QUrl(QLatin1String("qrc:/bttransfer.qml")));
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ QObject::connect(view.engine(), SIGNAL(quit()), qApp, SLOT(quit()));
+ view.show();
+ return application.exec();
+}
diff --git a/examples/bluetooth/picturetransfer/picturetransfer.pro b/examples/bluetooth/picturetransfer/picturetransfer.pro
new file mode 100644
index 00000000..0eee46a2
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/picturetransfer.pro
@@ -0,0 +1,25 @@
+QT += quick bluetooth
+
+
+TARGET = qml_picturetransfer
+TEMPLATE = app
+
+RESOURCES += \
+ qmltransfer.qrc
+
+OTHER_FILES += \
+ bttransfer.qml \
+ Button.qml \
+ DeviceDiscovery.qml \
+ PictureSelector.qml \
+ FileSending.qml
+
+HEADERS += \
+ filetransfer.h
+
+SOURCES += \
+ filetransfer.cpp \
+ main.cpp
+
+
+
diff --git a/examples/bluetooth/picturetransfer/qmltransfer.qrc b/examples/bluetooth/picturetransfer/qmltransfer.qrc
new file mode 100644
index 00000000..f28e97ea
--- /dev/null
+++ b/examples/bluetooth/picturetransfer/qmltransfer.qrc
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/">
+ <file>bttransfer.qml</file>
+ <file>DeviceDiscovery.qml</file>
+ <file>PictureSelector.qml</file>
+ <file>FileSending.qml</file>
+ <file>Button.qml</file>
+ <file>background.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/bluetooth/scanner/Button.qml b/examples/bluetooth/scanner/Button.qml
index a3debfca..17fb38b5 100644
--- a/examples/bluetooth/scanner/Button.qml
+++ b/examples/bluetooth/scanner/Button.qml
@@ -48,9 +48,7 @@ Rectangle {
property alias text: label.text
signal clicked()
-
- height: 60
- width: 105
+ height: label.height*1.1
color: active ? "#1c56f3" : "white"
@@ -61,9 +59,11 @@ Rectangle {
id: label
text: "Full Discovery"
font.bold: true
- anchors.fill: parent
+ font.pointSize: 17
+ width: parent.width
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
+ anchors.centerIn: parent
}
MouseArea {
diff --git a/examples/bluetooth/scanner/qmlscanner.cpp b/examples/bluetooth/scanner/qmlscanner.cpp
index 3602674b..47d0bb26 100644
--- a/examples/bluetooth/scanner/qmlscanner.cpp
+++ b/examples/bluetooth/scanner/qmlscanner.cpp
@@ -41,9 +41,11 @@
#include <QtGui/QGuiApplication>
#include <QtQuick/QQuickView>
#include <QtQml/QQmlEngine>
+#include <QtCore/QLoggingCategory>
int main(int argc, char *argv[])
{
+ //QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
QGuiApplication application(argc, argv);
const QString mainQmlApp = QLatin1String("qrc:/scanner.qml");
QQuickView view;
diff --git a/examples/bluetooth/scanner/scanner.pro b/examples/bluetooth/scanner/scanner.pro
index 7e5c00f7..68572533 100644
--- a/examples/bluetooth/scanner/scanner.pro
+++ b/examples/bluetooth/scanner/scanner.pro
@@ -8,9 +8,11 @@ RESOURCES += \
scanner.qrc
OTHER_FILES += \
- scanner.qml
+ scanner.qml \
+ Button.qml \
+ default.png
#DEFINES += QMLJSDEBUGGER
-OTHER_FILES += \
- Button.qml
+target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/scanner
+INSTALLS += target
diff --git a/examples/bluetooth/scanner/scanner.qml b/examples/bluetooth/scanner/scanner.qml
index 48b2ee53..67aaecf0 100644
--- a/examples/bluetooth/scanner/scanner.qml
+++ b/examples/bluetooth/scanner/scanner.qml
@@ -54,6 +54,18 @@ Item {
onDiscoveryModeChanged: console.log("Discovery mode: " + discoveryMode)
onServiceDiscovered: console.log("Found new service " + service.deviceAddress + " " + service.deviceName + " " + service.serviceName);
onDeviceDiscovered: console.log("New device: " + device)
+ onErrorChanged: {
+ switch (btModel.error) {
+ case BluetoothDiscoveryModel.PoweredOffError:
+ console.log("Error: Bluetooth device not turned on"); break;
+ case BluetoothDiscoveryModel.InputOutputError:
+ console.log("Error: Bluetooth I/O Error"); break;
+ case BluetoothDiscoveryModel.NoError:
+ break;
+ default:
+ console.log("Error: Unknown Error"); break;
+ }
+ }
}
Rectangle {
@@ -62,7 +74,7 @@ Item {
width: top.width * 0.7;
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: top.top;
- height: 30;
+ height: text.height*1.2;
radius: 5
color: "#1c56f3"
visible: btModel.running
@@ -71,6 +83,7 @@ Item {
id: text
text: "Scanning"
font.bold: true
+ font.pointSize: 20
anchors.centerIn: parent
}
@@ -115,9 +128,9 @@ Item {
anchors.leftMargin: 5
Text {
id: bttext
- text: name;
+ text: deviceName ? deviceName : name
font.family: "FreeSerif"
- font.pointSize: 12
+ font.pointSize: 16
}
Text {
@@ -138,7 +151,8 @@ Item {
visible: opacity !== 0
opacity: btDelegate.expended ? 1 : 0.0
text: get_details(service)
- font: bttext.font
+ font.family: "FreeSerif"
+ font.pointSize: 14
Behavior on opacity {
NumberAnimation { duration: 200}
}
@@ -160,20 +174,28 @@ Item {
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
- spacing: 20
+ anchors.bottomMargin: 5
+ spacing: 10
Button {
id: fdButton
+ width: top.width/3*0.9
+ //mdButton has longest text
+ height: mdButton.height
text: "Full Discovery"
onClicked: btModel.discoveryMode = BluetoothDiscoveryModel.FullServiceDiscovery
}
Button {
id: mdButton
+ width: top.width/3*0.9
text: "Minimal Discovery"
onClicked: btModel.discoveryMode = BluetoothDiscoveryModel.MinimalServiceDiscovery
}
Button {
id: devButton
+ width: top.width/3*0.9
+ //mdButton has longest text
+ height: mdButton.height
text: "Device Discovery"
onClicked: btModel.discoveryMode = BluetoothDiscoveryModel.DeviceDiscovery
}
diff --git a/examples/nfc/annotatedurl/annotatedurl.pro b/examples/nfc/annotatedurl/annotatedurl.pro
index 65ed7c8d..e2bb7c06 100644
--- a/examples/nfc/annotatedurl/annotatedurl.pro
+++ b/examples/nfc/annotatedurl/annotatedurl.pro
@@ -13,3 +13,5 @@ HEADERS += mainwindow.h \
FORMS += mainwindow.ui
+target.path = $$[QT_INSTALL_EXAMPLES]/nfc/annotatedurl
+INSTALLS += target
diff --git a/examples/nfc/corkboard/Mode.qml b/examples/nfc/corkboard/Mode.qml
new file mode 100644
index 00000000..a3df4448
--- /dev/null
+++ b/examples/nfc/corkboard/Mode.qml
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the QtNfc module.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+
+Item {
+ id: page
+ width: ListView.view.width;
+ height: ListView.view.height
+ Rectangle {
+ id: frame
+ anchors.fill: parent
+ z: 1
+ color: "transparent"
+ border.color: "darkred"
+ border.width: 10
+ }
+
+ Image {
+ source: "qrc:/cork.jpg"
+ width: listView.width
+ height: listView.height
+ fillMode: Image.PreserveAspectCrop
+ }
+
+ Text {
+ anchors { horizontalCenter: parent.horizontalCenter; top: parent.top; topMargin: 10}
+ text: name;
+ font.pixelSize: 30; font.bold: true; color: "white"
+ style: Text.Outline; styleColor: "black"
+ }
+
+ Repeater {
+ model: notes
+ Item {
+ id: stickyPage
+ z: 2
+
+ x: Math.random() * (listView.width-listView.width*0.30) + listView.width*0.10
+ y: Math.random() * (listView.height-listView.height*0.30) + listView.height*0.10
+
+ rotation: -listView.horizontalVelocity / 200;
+ Behavior on rotation {
+ SpringAnimation { spring: 2.0; damping: 0.15 }
+ }
+
+ Item {
+ id: sticky
+ scale: mouse.pressed ? 1 : 0.7
+ rotation: mouse.pressed ? 8 : 0
+ Behavior on rotation{
+ NumberAnimation {duration: 200 }
+ }
+ Behavior on scale{
+ NumberAnimation { duration: 200 }
+ }
+
+ Image {
+ id: stickyImage
+ x: 8 + -width * 0.6 / 2; y: -20
+ source: "qrc:/note-yellow.png"
+ scale: 0.6; transformOrigin: Item.TopLeft
+ smooth: true
+ }
+
+ TextEdit {
+ id: myText
+ text: noteText
+ x: -104; y: 36; width: 215; height: 200
+ smooth: true
+ font.pixelSize: 24
+ readOnly: false
+ rotation: -8
+ wrapMode: TextEdit.Wrap
+ }
+
+ Item {
+ id: interactionItem
+ x: stickyImage.x; y: -20
+ width: stickyImage.width * stickyImage.scale
+ height: stickyImage.height * stickyImage.scale
+
+ MouseArea {
+ id: mouse
+ anchors.fill: parent
+ drag.target: stickyPage
+ drag.axis: Drag.XandYAxis
+ }
+ Image {
+ id: writeButton
+ source: "qrc:/NfcFlag.png"
+ rotation: -8 // Note image itself is rotated
+ anchors { bottom: parent.bottom; right:parent.right }
+ scale: flagMouse.pressed ? 1.3 : 1
+ MouseArea {
+ id: flagMouse
+ anchors.fill: parent
+ //onClicked: { }
+ }
+ }
+ }
+ }
+
+ Image {
+ x: -width / 2; y: -height * 0.5 / 2
+ source: "qrc:/tack.png"
+ scale: 0.7; transformOrigin: Item.TopLeft
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/examples/nfc/corkboard/NfcFlag.png b/examples/nfc/corkboard/NfcFlag.png
new file mode 100644
index 00000000..6d2b9f89
--- /dev/null
+++ b/examples/nfc/corkboard/NfcFlag.png
Binary files differ
diff --git a/examples/nfc/corkboard/bar-descriptor.xml b/examples/nfc/corkboard/bar-descriptor.xml
new file mode 100644
index 00000000..f46eb355
--- /dev/null
+++ b/examples/nfc/corkboard/bar-descriptor.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<qnx >
+ <id>com.qt-project.cork</id>
+ <filename>corkboard</filename>
+ <name>NFC Corkboard</name>
+ <versionNumber>1.0.0</versionNumber>
+
+ <!-- adding the invoke target for a nfc Text element -->
+ <invoke-target id="com.fabian.cork">
+ <type>APPLICATION</type>
+ <filter>
+ <action>bb.action.OPEN</action>
+ <mime-type>application/vnd.rim.nfc.ndef</mime-type>
+ <property var="uris" value="ndef://1/T"/>
+ </filter>
+ </invoke-target>
+
+ <initialWindow>
+ <systemChrome>none</systemChrome>
+ <transparent>false</transparent>
+ <autoOrients>true</autoOrients>
+ <aspectRatio>portrait</aspectRatio>
+ </initialWindow>
+
+ <permission system="true">run_native</permission>
+
+ <asset entry="true" path="qml_corkboard" type="Qnx/Elf">qml_corkboard</asset>
+ <asset path="icon.png">icon.png</asset>
+ <icon>
+ <image>icon.png</image>
+ </icon>
+ </qnx>
diff --git a/examples/nfc/corkboard/cork.jpg b/examples/nfc/corkboard/cork.jpg
new file mode 100644
index 00000000..160bc002
--- /dev/null
+++ b/examples/nfc/corkboard/cork.jpg
Binary files differ
diff --git a/examples/nfc/corkboard/corkboard.pro b/examples/nfc/corkboard/corkboard.pro
new file mode 100644
index 00000000..d6247032
--- /dev/null
+++ b/examples/nfc/corkboard/corkboard.pro
@@ -0,0 +1,14 @@
+QT += quick nfc
+
+SOURCES += \
+ main.cpp
+
+TARGET = qml_corkboard
+TEMPLATE = app
+
+RESOURCES += \
+ corkboard.qrc
+
+OTHER_FILES += \
+ corkboards.qml \
+ Mode.qml
diff --git a/examples/nfc/corkboard/corkboard.qrc b/examples/nfc/corkboard/corkboard.qrc
new file mode 100644
index 00000000..10d80ce3
--- /dev/null
+++ b/examples/nfc/corkboard/corkboard.qrc
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/">
+ <file>corkboards.qml</file>
+ <file>NfcFlag.png</file>
+ <file>tack.png</file>
+ <file>note-yellow.png</file>
+ <file>cork.jpg</file>
+ <file>Mode.qml</file>
+ </qresource>
+</RCC>
diff --git a/examples/nfc/corkboard/corkboards.qml b/examples/nfc/corkboard/corkboards.qml
new file mode 100644
index 00000000..55c83723
--- /dev/null
+++ b/examples/nfc/corkboard/corkboards.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the QtNfc module.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+import QtNfc 5.2
+
+Rectangle {
+ width: 800; height: 480
+ color: "black"
+
+ NearField {
+ orderMatch: false
+
+ onMessageRecordsChanged: {
+ list.get(listView.currentIndex).notes.append({"noteText":messageRecords[0].text})
+ }
+ }
+
+ ListModel {
+ id: list
+
+ ListElement {
+ name: "Personal"
+ notes: [
+ ListElement { noteText: "https://developer.blackberry.com" },
+ ListElement { noteText: "Near Field Communication" },
+ ListElement { noteText: "Touch a tag and its contents will appear as a new note" }
+ ]
+ }
+
+ ListElement {
+ name: "Work"
+ notes: [
+ //ListElement { noteText: "To write a tag, click the red flag of a note and then touch a tag" },
+ ListElement { noteText: "https://developer.blackberry.com/native/documentation/core/com.qnx.doc.nfc/topic/manual/c_stub_nfcdevguide_general_introduction.html" }
+ ]
+ }
+ }
+
+ ListView {
+ id: listView
+
+ anchors.fill: parent
+ orientation: ListView.Horizontal
+ snapMode: ListView.SnapOneItem
+ model: list
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ delegate: Mode {}
+ }
+}
diff --git a/examples/nfc/corkboard/doc/images/corkboard.png b/examples/nfc/corkboard/doc/images/corkboard.png
new file mode 100644
index 00000000..3f54ea18
--- /dev/null
+++ b/examples/nfc/corkboard/doc/images/corkboard.png
Binary files differ
diff --git a/examples/nfc/corkboard/doc/src/corkboard.qdoc b/examples/nfc/corkboard/doc/src/corkboard.qdoc
new file mode 100644
index 00000000..4027fc26
--- /dev/null
+++ b/examples/nfc/corkboard/doc/src/corkboard.qdoc
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the QtNfc module.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\example corkboard
+\title QML CorkBoard Example
+
+The QML CorkBoard example displays the contents of NDEF messages read from an
+NFC Tag. Each newly detected NDEF message is added to the corkboard and can be
+dragged into an arbitrary position on the board. The corkboard has a "Personal"
+and "Work" space. The workspace can be changed by sliding left or right.
+
+\image corkboard.png
+
+*/
diff --git a/examples/nfc/corkboard/icon.png b/examples/nfc/corkboard/icon.png
new file mode 100644
index 00000000..b115f836
--- /dev/null
+++ b/examples/nfc/corkboard/icon.png
Binary files differ
diff --git a/examples/nfc/corkboard/main.cpp b/examples/nfc/corkboard/main.cpp
new file mode 100644
index 00000000..044c083f
--- /dev/null
+++ b/examples/nfc/corkboard/main.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the QtNfc module.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include <QtQml/QQmlEngine>
+#include <QtQuick/QQuickView>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication application(argc, argv);
+ QQuickView view;
+ view.setSource(QUrl("qrc:/corkboards.qml"));
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.show();
+ return application.exec();
+}
diff --git a/examples/nfc/corkboard/note-yellow.png b/examples/nfc/corkboard/note-yellow.png
new file mode 100644
index 00000000..8ddecc8b
--- /dev/null
+++ b/examples/nfc/corkboard/note-yellow.png
Binary files differ
diff --git a/examples/nfc/corkboard/tack.png b/examples/nfc/corkboard/tack.png
new file mode 100644
index 00000000..cef2d1cd
--- /dev/null
+++ b/examples/nfc/corkboard/tack.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/ndefeditor.pro b/examples/nfc/ndefeditor/ndefeditor.pro
index 47971fdb..43ab47fa 100644
--- a/examples/nfc/ndefeditor/ndefeditor.pro
+++ b/examples/nfc/ndefeditor/ndefeditor.pro
@@ -21,3 +21,6 @@ FORMS += \
textrecordeditor.ui \
urirecordeditor.ui \
mimeimagerecordeditor.ui
+
+target.path = $$[QT_INSTALL_EXAMPLES]/nfc/ndefeditor
+INSTALLS += target
diff --git a/examples/nfc/nfc.pro b/examples/nfc/nfc.pro
index ddf7456b..e4f7e35b 100644
--- a/examples/nfc/nfc.pro
+++ b/examples/nfc/nfc.pro
@@ -5,3 +5,5 @@ qtHaveModule(widgets) {
ndefeditor \
poster
}
+
+qtHaveModule(quick): SUBDIRS += corkboard
diff --git a/examples/nfc/poster/poster.pro b/examples/nfc/poster/poster.pro
index d108b2a2..47de2986 100644
--- a/examples/nfc/poster/poster.pro
+++ b/examples/nfc/poster/poster.pro
@@ -11,3 +11,6 @@ RESOURCES += \
OTHER_FILES += \
poster.qml
+
+target.path = $$[QT_INSTALL_EXAMPLES]/nfc/poster
+INSTALLS += target
diff --git a/qtconnectivity.pro b/qtconnectivity.pro
index 40663d70..e2a73944 100644
--- a/qtconnectivity.pro
+++ b/qtconnectivity.pro
@@ -1,4 +1,5 @@
load(configure)
qtCompileTest(bluez)
qtCompileTest(btapi10_2_1)
+qtCompileTest(libbb2)
load(qt_parts)
diff --git a/src/android/android.pro b/src/android/android.pro
new file mode 100644
index 00000000..07feb78f
--- /dev/null
+++ b/src/android/android.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+qtHaveModule(bluetooth): SUBDIRS += bluetooth
diff --git a/src/android/bluetooth/AndroidManifest.xml b/src/android/bluetooth/AndroidManifest.xml
new file mode 100644
index 00000000..9148e171
--- /dev/null
+++ b/src/android/bluetooth/AndroidManifest.xml
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0"
+ package="org.qtproject.qt5.android.bluetooth">
+ <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
+</manifest>
diff --git a/src/android/bluetooth/bluetooth.pri b/src/android/bluetooth/bluetooth.pri
new file mode 100644
index 00000000..5c2cb8f8
--- /dev/null
+++ b/src/android/bluetooth/bluetooth.pri
@@ -0,0 +1,12 @@
+CONFIG += java
+DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar
+
+PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/bluetooth
+
+JAVACLASSPATH += $$PWD/src/
+JAVASOURCES += \
+ $$PATHPREFIX/QtBluetoothBroadcastReceiver.java
+
+# install
+target.path = $$[QT_INSTALL_PREFIX]/jar
+INSTALLS += target
diff --git a/src/android/bluetooth/bluetooth.pro b/src/android/bluetooth/bluetooth.pro
new file mode 100644
index 00000000..8d19c1b7
--- /dev/null
+++ b/src/android/bluetooth/bluetooth.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += bundledjar.pro distributedjar.pro
diff --git a/src/android/bluetooth/bundledjar.pro b/src/android/bluetooth/bundledjar.pro
new file mode 100644
index 00000000..8912674a
--- /dev/null
+++ b/src/android/bluetooth/bundledjar.pro
@@ -0,0 +1,3 @@
+TARGET = QtAndroidBluetooth-bundled
+CONFIG += bundled_jar_file
+include(bluetooth.pri)
diff --git a/src/android/bluetooth/distributedjar.pro b/src/android/bluetooth/distributedjar.pro
new file mode 100644
index 00000000..a155bdf2
--- /dev/null
+++ b/src/android/bluetooth/distributedjar.pro
@@ -0,0 +1,2 @@
+TARGET = QtAndroidBluetooth
+include(bluetooth.pri)
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java
new file mode 100644
index 00000000..1f0049ef
--- /dev/null
+++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android.bluetooth;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import java.lang.reflect.Method;
+
+public class QtBluetoothBroadcastReceiver extends BroadcastReceiver
+{
+ /* Pointer to the Qt object that "owns" the Java object */
+ long qtObject = 0;
+ static Activity qtactivity = null;
+
+ private static final int TURN_BT_ON = 3330;
+ private static final int TURN_BT_DISCOVERABLE = 3331;
+
+ public void onReceive(Context context, Intent intent)
+ {
+ jniOnReceive(qtObject, context, intent);
+ }
+
+ public native void jniOnReceive(long qtObject, Context context, Intent intent);
+
+ static public void setActivity(Activity activity, Object activityDelegate)
+ {
+ qtactivity = activity;
+ }
+
+ static public void setDiscoverable()
+ {
+ Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
+ intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
+ try {
+ qtactivity.startActivityForResult(intent, TURN_BT_ON);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ static public void setConnectable()
+ {
+ Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ try {
+ qtactivity.startActivityForResult(intent, TURN_BT_DISCOVERABLE);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ static public boolean setPairingMode(String address, boolean isPairing)
+ {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ try {
+ BluetoothDevice device = adapter.getRemoteDevice(address);
+ String methodName = "createBond";
+ if (!isPairing)
+ methodName = "removeBond";
+
+ Method m = device.getClass()
+ .getMethod(methodName, (Class[]) null);
+ m.invoke(device, (Object[]) null);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return false;
+ }
+
+ return true;
+ }
+
+}
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
diff --git a/src/imports/bluetooth/plugin.cpp b/src/imports/bluetooth/plugin.cpp
index 2311d6b8..bcf59794 100644
--- a/src/imports/bluetooth/plugin.cpp
+++ b/src/imports/bluetooth/plugin.cpp
@@ -39,7 +39,7 @@
**
****************************************************************************/
-
+#include <QtCore/QLoggingCategory>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlExtensionPlugin>
@@ -75,7 +75,13 @@ public:
qmlRegisterType<QDeclarativeBluetoothService >(uri, major, minor, "BluetoothService");
qmlRegisterType<QDeclarativeBluetoothSocket >(uri, major, minor, "BluetoothSocket");
+ // Register the 5.3 types
+ // introduces 5.3 version, other existing 5.2 exports automatically become availabe under 5.3 as well
+ minor = 3;
+ qmlRegisterType<QDeclarativeBluetoothDiscoveryModel >(uri, major, minor, "BluetoothDiscoveryModel");
}
};
+Q_LOGGING_CATEGORY(QT_BT_QML, "qt.bluetooth.qml")
+
#include "plugin.moc"
diff --git a/src/imports/bluetooth/plugins.qmltypes b/src/imports/bluetooth/plugins.qmltypes
index 20d57574..18647c2c 100644
--- a/src/imports/bluetooth/plugins.qmltypes
+++ b/src/imports/bluetooth/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.1
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -notrelocatable QtBluetooth 5.2'
+// 'qmlplugindump -notrelocatable QtBluetooth 5.3'
Module {
Component {
@@ -12,9 +12,10 @@ Module {
prototype: "QAbstractListModel"
exports: [
"QtBluetooth/BluetoothDiscoveryModel 5.0",
- "QtBluetooth/BluetoothDiscoveryModel 5.2"
+ "QtBluetooth/BluetoothDiscoveryModel 5.2",
+ "QtBluetooth/BluetoothDiscoveryModel 5.3"
]
- exportMetaObjectRevisions: [0, 0]
+ exportMetaObjectRevisions: [0, 0, 0]
Enum {
name: "DiscoveryMode"
values: {
diff --git a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
index 67b71902..bec7b717 100644
--- a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
+++ b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
@@ -44,7 +44,8 @@
#include <QPixmap>
-#include <qbluetoothdeviceinfo.h>
+#include <QtCore/QLoggingCategory>
+#include <QtBluetooth/QBluetoothDeviceInfo>
#include <QtBluetooth/QBluetoothAddress>
#include "qdeclarativebluetoothservice_p.h"
@@ -91,6 +92,8 @@
\sa QBluetoothServiceDiscoveryAgent
*/
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_QML)
+
class QDeclarativeBluetoothDiscoveryModelPrivate
{
public:
@@ -164,6 +167,11 @@ void QDeclarativeBluetoothDiscoveryModel::errorDeviceDiscovery(QBluetoothDeviceD
{
d->m_error = static_cast<QDeclarativeBluetoothDiscoveryModel::Error>(error);
emit errorChanged();
+
+ //QBluetoothDeviceDiscoveryAgent::finished() signal is not emitted in case of an error
+ //Note that this behavior is different from QBluetoothServiceDiscoveryAgent.
+ //This reset the models running flag.
+ setRunning(false);
}
void QDeclarativeBluetoothDiscoveryModel::clearModel()
@@ -214,7 +222,7 @@ QVariant QDeclarativeBluetoothDiscoveryModel::data(const QModelIndex &index, int
if (discoveryMode() != DeviceDiscovery) {
if (index.row() >= d->m_services.count()){
- qWarning() << "index out of bounds";
+ qCWarning(QT_BT_QML) << "index out of bounds";
return QVariant();
}
@@ -239,7 +247,7 @@ QVariant QDeclarativeBluetoothDiscoveryModel::data(const QModelIndex &index, int
}
} else {
if (index.row() >= d->m_devices.count()) {
- qWarning() << "index out of bounds";
+ qCWarning(QT_BT_QML) << "index out of bounds";
return QVariant();
}
@@ -277,7 +285,8 @@ void QDeclarativeBluetoothDiscoveryModel::serviceDiscovered(const QBluetoothServ
for (int i = 0; i < d->m_services.count(); i++) {
current = d->m_services.at(i);
if (bs->deviceAddress() == current->deviceAddress()
- && bs->serviceName() == current->serviceName()) {
+ && bs->serviceName() == current->serviceName()
+ && bs->serviceUuid() == current->serviceUuid()) {
delete bs;
return;
}
@@ -364,11 +373,10 @@ void QDeclarativeBluetoothDiscoveryModel::setRunning(bool running)
d->m_running = running;
if (!running) {
- if (d->m_deviceAgent) {
+ if (d->m_deviceAgent)
d->m_deviceAgent->stop();
- } else if (d->m_serviceAgent) {
+ if (d->m_serviceAgent)
d->m_serviceAgent->stop();
- }
} else {
clearModel();
d->m_error = NoError;
@@ -384,7 +392,7 @@ void QDeclarativeBluetoothDiscoveryModel::setRunning(bool running)
} else {
if (!d->m_serviceAgent) {
d->m_serviceAgent = new QBluetoothServiceDiscoveryAgent(this);
- connect(d->m_serviceAgent, SIGNAL(serviceDiscovered(const QBluetoothServiceInfo&)), this, SLOT(serviceDiscovered(const QBluetoothServiceInfo&)));
+ connect(d->m_serviceAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)), this, SLOT(serviceDiscovered(QBluetoothServiceInfo)));
connect(d->m_serviceAgent, SIGNAL(finished()), this, SLOT(finishedDiscovery()));
connect(d->m_serviceAgent, SIGNAL(canceled()), this, SLOT(finishedDiscovery()));
connect(d->m_serviceAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)), this, SLOT(errorDiscovery(QBluetoothServiceDiscoveryAgent::Error)));
@@ -432,7 +440,7 @@ void QDeclarativeBluetoothDiscoveryModel::setUuidFilter(QString uuid)
QBluetoothUuid qbuuid(uuid);
if (qbuuid.isNull()) {
- qWarning() << "Invalid UUID providded " << uuid;
+ qCWarning(QT_BT_QML) << "Invalid UUID providded " << uuid;
return;
}
d->m_uuid = uuid;
diff --git a/src/imports/bluetooth/qdeclarativebluetoothservice.cpp b/src/imports/bluetooth/qdeclarativebluetoothservice.cpp
index be8f90c0..6d4e3dc0 100644
--- a/src/imports/bluetooth/qdeclarativebluetoothservice.cpp
+++ b/src/imports/bluetooth/qdeclarativebluetoothservice.cpp
@@ -41,7 +41,9 @@
#include "qdeclarativebluetoothservice_p.h"
-#include <qbluetoothdeviceinfo.h>
+#include <QtCore/QLoggingCategory>
+
+#include <QtBluetooth/QBluetoothDeviceInfo>
#include <QtBluetooth/QBluetoothSocket>
#include <QtBluetooth/QBluetoothAddress>
#include <QtBluetooth/QBluetoothServer>
@@ -80,6 +82,8 @@
\endlist
*/
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_QML)
+
class QDeclarativeBluetoothServicePrivate
{
public:
@@ -269,16 +273,14 @@ bool QDeclarativeBluetoothService::isRegistered() const
int QDeclarativeBluetoothServicePrivate::listen() {
if (m_service->socketProtocol() == QBluetoothServiceInfo::UnknownProtocol) {
- qWarning() << "Unknown protocol, can't make service" << m_protocol;
+ qCWarning(QT_BT_QML) << "Unknown protocol, can't make service" << m_protocol;
return -1;
}
- QBluetoothServiceInfo::Protocol serverType;
- if (m_service->socketProtocol() == QBluetoothServiceInfo::L2capProtocol) {
+ QBluetoothServiceInfo::Protocol serverType = QBluetoothServiceInfo::UnknownProtocol;
+ if (m_service->socketProtocol() == QBluetoothServiceInfo::L2capProtocol)
serverType = QBluetoothServiceInfo::L2capProtocol;
- }
- else if (m_service->socketProtocol() == QBluetoothServiceInfo::RfcommProtocol) {
+ else if (m_service->socketProtocol() == QBluetoothServiceInfo::RfcommProtocol)
serverType = QBluetoothServiceInfo::RfcommProtocol;
- }
QBluetoothServer *server = new QBluetoothServer(serverType);
server->setMaxPendingConnections(1);
@@ -333,7 +335,7 @@ void QDeclarativeBluetoothService::setRegistered(bool registered)
protocolDescriptorList.append(QVariant::fromValue(protocol));
}
else {
- qWarning() << "No protocol specified for bluetooth service";
+ qCWarning(QT_BT_QML) << "No protocol specified for bluetooth service";
}
d->m_service->setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList,
protocolDescriptorList);
@@ -342,7 +344,7 @@ void QDeclarativeBluetoothService::setRegistered(bool registered)
emit registeredChanged();
}
else {
- qWarning() << "Register service failed";
+ qCWarning(QT_BT_QML) << "Register service failed";
//TODO propaget this error to the user
}
}
@@ -366,7 +368,7 @@ QDeclarativeBluetoothSocket *QDeclarativeBluetoothService::nextClient()
return new QDeclarativeBluetoothSocket(socket, this, 0);
}
else {
- qWarning() << "Socket has no pending connection, failing";
+ qCWarning(QT_BT_QML) << "Socket has no pending connection, failing";
return 0;
}
}
@@ -383,7 +385,7 @@ void QDeclarativeBluetoothService::assignNextClient(QDeclarativeBluetoothSocket
return;
}
else {
- qWarning() << "Socket has no pending connection, failing";
+ qCWarning(QT_BT_QML) << "Socket has no pending connection, failing";
return;
}
}
diff --git a/src/imports/bluetooth/qdeclarativebluetoothsocket.cpp b/src/imports/bluetooth/qdeclarativebluetoothsocket.cpp
index a1329182..75a1b85c 100644
--- a/src/imports/bluetooth/qdeclarativebluetoothsocket.cpp
+++ b/src/imports/bluetooth/qdeclarativebluetoothsocket.cpp
@@ -41,13 +41,13 @@
#include "qdeclarativebluetoothsocket_p.h"
-#include <QPointer>
-#include <QStringList>
-#include <QDataStream>
-#include <QByteArray>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QPointer>
+#include <QtCore/QStringList>
+#include <QtCore/QDataStream>
+#include <QtCore/QByteArray>
-
-#include <qbluetoothdeviceinfo.h>
+#include <QtBluetooth/QBluetoothDeviceInfo>
#include <QtBluetooth/QBluetoothAddress>
#include <QtBluetooth/QBluetoothSocket>
@@ -75,6 +75,8 @@
or passing in the service return from BluetoothDiscoveryModel.
*/
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_QML)
+
class QDeclarativeBluetoothSocketPrivate
{
public:
@@ -224,7 +226,7 @@ void QDeclarativeBluetoothSocket::setConnected(bool connected)
d->connect();
}
else {
- qWarning() << "BluetoothSocket::setConnected called before a service was set";
+ qCWarning(QT_BT_QML) << "BluetoothSocket::setConnected called before a service was set";
}
}
@@ -341,7 +343,7 @@ QString QDeclarativeBluetoothSocket::stringData()
void QDeclarativeBluetoothSocket::sendStringData(const QString &data)
{
if (!d->m_connected || !d->m_socket){
- qWarning() << "Writing data to unconnected socket";
+ qCWarning(QT_BT_QML) << "Writing data to unconnected socket";
return;
}
diff --git a/src/imports/nfc/plugin.cpp b/src/imports/nfc/plugin.cpp
index 0a423495..8694e185 100644
--- a/src/imports/nfc/plugin.cpp
+++ b/src/imports/nfc/plugin.cpp
@@ -84,6 +84,11 @@ public:
qmlRegisterType<QDeclarativeNdefTextRecord>(uri, major, minor, "NdefTextRecord");
qmlRegisterType<QDeclarativeNdefUriRecord>(uri, major, minor, "NdefUriRecord");
qmlRegisterType<QDeclarativeNdefMimeRecord>(uri, major, minor, "NdefMimeRecord");
+
+ // Register the 5.3 types
+ // introduces 5.3 version, other existing 5.2 exports automatically become availabe under 5.3 as well
+ minor = 3;
+ qmlRegisterType<QDeclarativeNearField>(uri, major, minor, "NearField");
}
};
diff --git a/src/imports/nfc/plugins.qmltypes b/src/imports/nfc/plugins.qmltypes
index 346c0bfa..fff2834f 100644
--- a/src/imports/nfc/plugins.qmltypes
+++ b/src/imports/nfc/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.1
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -notrelocatable QtNfc 5.2'
+// 'qmlplugindump -notrelocatable QtNfc 5.3'
Module {
Component {
@@ -52,8 +52,12 @@ Module {
Component {
name: "QDeclarativeNearField"
prototype: "QObject"
- exports: ["QtNfc/NearField 5.0", "QtNfc/NearField 5.2"]
- exportMetaObjectRevisions: [0, 0]
+ exports: [
+ "QtNfc/NearField 5.0",
+ "QtNfc/NearField 5.2",
+ "QtNfc/NearField 5.3"
+ ]
+ exportMetaObjectRevisions: [0, 0, 0]
Property { name: "messageRecords"; type: "QQmlNdefRecord"; isList: true; isReadonly: true }
Property { name: "filter"; type: "QDeclarativeNdefFilter"; isList: true; isReadonly: true }
Property { name: "orderMatch"; type: "bool" }
diff --git a/src/nfc/doc/qtnfc.qdocconf b/src/nfc/doc/qtnfc.qdocconf
index e136ddf7..2d5b0ef5 100644
--- a/src/nfc/doc/qtnfc.qdocconf
+++ b/src/nfc/doc/qtnfc.qdocconf
@@ -2,7 +2,7 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
project = QtNfc
description = Qt NFC Reference Documentation
-url = http://qt-project.org/doc/qt-$QT_VER/qtnfc
+url = http://qt-project.org/doc/qt-$QT_VER
version = $QT_VERSION
examplesinstallpath = nfc
diff --git a/src/nfc/doc/src/examples.qdoc b/src/nfc/doc/src/examples.qdoc
index 64cc0982..9bdbd880 100644
--- a/src/nfc/doc/src/examples.qdoc
+++ b/src/nfc/doc/src/examples.qdoc
@@ -55,6 +55,9 @@ in their own documentation, but they are also accessible from here.
\li Example
\li Description
\row
+ \li \l{corkboard} {CorkBoard}
+ \li Displays NDEF text tags on a corkboard.
+ \row
\li \l{poster}{QML Poster}
\li Displays URLs stored on NFC Forum Tags.
\endtable
diff --git a/src/nfc/doc/src/nfc-index.qdoc b/src/nfc/doc/src/nfc-index.qdoc
index 7309e4cc..2ec40891 100644
--- a/src/nfc/doc/src/nfc-index.qdoc
+++ b/src/nfc/doc/src/nfc-index.qdoc
@@ -67,6 +67,7 @@ import statement in your \c .qml file:
\list
\li QML
\list
+ \li \l {corkboard}{CorkBoard}
\li \l {poster}{QML Poster}
\endlist
\li C++
diff --git a/src/nfc/nfc.pro b/src/nfc/nfc.pro
index dfa1d3ef..7b88d4f0 100644
--- a/src/nfc/nfc.pro
+++ b/src/nfc/nfc.pro
@@ -16,7 +16,9 @@ PUBLIC_HEADERS += \
qndeffilter.h \
qndefnfcurirecord.h \
qqmlndefrecord.h \
- qndefnfcsmartposterrecord.h
+ qndefnfcsmartposterrecord.h \
+ qnearfieldsharemanager.h \
+ qnearfieldsharetarget.h
PRIVATE_HEADERS += \
qllcpsocket_p.h \
@@ -29,7 +31,9 @@ PRIVATE_HEADERS += \
qnearfieldtagtype3_p.h \
qnearfieldtagtype4_p.h \
qtlv_p.h \
- qndefnfcsmartposterrecord_p.h
+ qndefnfcsmartposterrecord_p.h \
+ qnearfieldsharemanager_p.h \
+ qnearfieldsharetarget_p.h
SOURCES += \
qnearfieldmanager.cpp \
@@ -47,9 +51,11 @@ SOURCES += \
qtlv.cpp \
qllcpserver.cpp \
qqmlndefrecord.cpp \
- qndefnfcsmartposterrecord.cpp
+ qndefnfcsmartposterrecord.cpp \
+ qnearfieldsharemanager.cpp \
+ qnearfieldsharetarget.cpp
-qnx {
+CONFIG(blackberry) {
NFC_BACKEND_AVAILABLE = yes
DEFINES += QNX_NFC #QQNXNFC_DEBUG
@@ -69,6 +75,28 @@ qnx {
qnearfieldmanager_qnx.cpp \
qnx/qnxnfcmanager.cpp \
qnx/qnxnfceventfilter.cpp
+
+ config_libbb2 {
+ SOURCES += \
+ qnearfieldsharemanager_qnx_p.cpp \
+ qnearfieldsharetarget_qnx_p.cpp \
+ qnx/qnxnfcsharemanager_p.cpp
+
+ PRIVATE_HEADERS += \
+ qnearfieldsharemanager_qnx_p.h \
+ qnearfieldsharetarget_qnx_p.h \
+ qnx/qnxnfcsharemanager_p.h
+
+ LIBS += -l:libbbsystem.so.2
+ } else {
+ SOURCES += \
+ qnearfieldsharemanagerimpl_p.cpp \
+ qnearfieldsharetargetimpl_p.cpp
+
+ PRIVATE_HEADERS += \
+ qnearfieldsharemanagerimpl_p.h \
+ qnearfieldsharetargetimpl_p.h
+ }
}
simulator {
@@ -80,13 +108,18 @@ simulator {
qnearfieldmanagervirtualbase_p.h \
qnearfieldmanager_simulator_p.h \
qllcpsocket_simulator_p.h \
- qllcpserver_simulator_p.h
+ qllcpserver_simulator_p.h \
+ qnearfieldsharemanagerimpl_p.h \
+ qnearfieldsharetargetimpl_p.h
+
SOURCES += \
qnearfieldmanagervirtualbase.cpp \
qnearfieldmanager_simulator.cpp \
qllcpsocket_simulator_p.cpp \
- qllcpserver_simulator_p.cpp
+ qllcpserver_simulator_p.cpp \
+ qnearfieldsharemanagerimpl_p.cpp \
+ qnearfieldsharetargetimpl_p.cpp
}
isEmpty(NFC_BACKEND_AVAILABLE) {
@@ -95,12 +128,16 @@ isEmpty(NFC_BACKEND_AVAILABLE) {
PRIVATE_HEADERS += \
qllcpsocket_p_p.h \
qllcpserver_p_p.h \
- qnearfieldmanagerimpl_p.h
+ qnearfieldmanagerimpl_p.h \
+ qnearfieldsharemanagerimpl_p.h \
+ qnearfieldsharetargetimpl_p.h
SOURCES += \
qllcpsocket_p.cpp \
qllcpserver_p.cpp \
- qnearfieldmanagerimpl_p.cpp
+ qnearfieldmanagerimpl_p.cpp \
+ qnearfieldsharemanagerimpl_p.cpp \
+ qnearfieldsharetargetimpl_p.cpp
}
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
diff --git a/src/nfc/qllcpserver_p.cpp b/src/nfc/qllcpserver_p.cpp
index 55d2a866..c22c868a 100644
--- a/src/nfc/qllcpserver_p.cpp
+++ b/src/nfc/qllcpserver_p.cpp
@@ -49,7 +49,7 @@ QLlcpServerPrivate::QLlcpServerPrivate(QLlcpServer *q)
}
QLlcpServerPrivate::~QLlcpServerPrivate()
-{
+{
}
bool QLlcpServerPrivate::listen(const QString &serviceUri)
diff --git a/src/nfc/qllcpsocket.cpp b/src/nfc/qllcpsocket.cpp
index 2bf3e2c3..79cb1284 100644
--- a/src/nfc/qllcpsocket.cpp
+++ b/src/nfc/qllcpsocket.cpp
@@ -231,7 +231,7 @@ qint64 QLlcpSocket::writeDatagram(const char *data, qint64 size)
*/
bool QLlcpSocket::isSequential() const
{
- return true;
+ return true;
}
/*!
diff --git a/src/nfc/qllcpsocket_p.cpp b/src/nfc/qllcpsocket_p.cpp
index 4d076b9c..b1af336f 100644
--- a/src/nfc/qllcpsocket_p.cpp
+++ b/src/nfc/qllcpsocket_p.cpp
@@ -50,7 +50,7 @@ QLlcpSocketPrivate::QLlcpSocketPrivate(QLlcpSocket *q)
QLlcpSocketPrivate::~QLlcpSocketPrivate()
{
-
+
}
void QLlcpSocketPrivate::connectToService(QNearFieldTarget *target, const QString &serviceUri)
diff --git a/src/nfc/qnearfieldmanager_qnx.cpp b/src/nfc/qnearfieldmanager_qnx.cpp
index e405ecc0..b09a6ed4 100644
--- a/src/nfc/qnearfieldmanager_qnx.cpp
+++ b/src/nfc/qnearfieldmanager_qnx.cpp
@@ -52,7 +52,7 @@ QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() :
m_handlerID(0)
{
QNXNFCManager::instance()->registerForNewInstance();
- connect(QNXNFCManager::instance(), SIGNAL(ndefMessage(const QNdefMessage&, QNearFieldTarget *)), this, SLOT(handleMessage(const QNdefMessage&, QNearFieldTarget *)));
+ connect(QNXNFCManager::instance(), SIGNAL(ndefMessage(QNdefMessage,QNearFieldTarget*)), this, SLOT(handleMessage(QNdefMessage,QNearFieldTarget*)));
m_requestedModes = QNearFieldManager::NdefWriteTargetAccess;
qQNXNFCDebug() << "Nearfieldmanager created";
@@ -74,8 +74,8 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection()
{
qQNXNFCDebug() << "Starting targetdetection in nearfieldmanager";
if (QNXNFCManager::instance()->startTargetDetection()) {
- connect(QNXNFCManager::instance(), SIGNAL(targetDetected(QNearFieldTarget *, const QList<QNdefMessage>&)),
- this, SLOT(newTarget(QNearFieldTarget *, const QList<QNdefMessage>&)));
+ connect(QNXNFCManager::instance(), SIGNAL(targetDetected(QNearFieldTarget*,QList<QNdefMessage>)),
+ this, SLOT(newTarget(QNearFieldTarget*,QList<QNdefMessage>)));
return true;
} else {
qWarning()<<Q_FUNC_INFO<<"Could not start Target detection";
@@ -85,8 +85,8 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection()
void QNearFieldManagerPrivateImpl::stopTargetDetection()
{
- disconnect(QNXNFCManager::instance(), SIGNAL(targetDetected(NearFieldTarget *, const QList<QNdefMessage> &)),
- this, SLOT(newTarget(NearFieldTarget *, const QList<QNdefMessage> &)));
+ disconnect(QNXNFCManager::instance(), SIGNAL(targetDetected(NearFieldTarget*,QList<QNdefMessage>)),
+ this, SLOT(newTarget(NearFieldTarget*,QList<QNdefMessage>)));
QNXNFCManager::instance()->unregisterTargetDetection(this);
}
diff --git a/src/nfc/qnearfieldsharemanager.cpp b/src/nfc/qnearfieldsharemanager.cpp
new file mode 100644
index 00000000..b3e736b6
--- /dev/null
+++ b/src/nfc/qnearfieldsharemanager.cpp
@@ -0,0 +1,186 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 "qnearfieldsharemanager.h"
+#include "qnearfieldsharemanager_p.h"
+
+#if defined(QNX_NFC)
+#include "qnearfieldsharemanager_qnx_p.h"
+#else
+#include "qnearfieldsharemanagerimpl_p.h"
+#endif
+
+#include "qnearfieldsharetarget.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QNearFieldShareManager
+ \brief The QNearFieldShareManager class manages all interactions related to sharing files and data over NFC.
+
+ \ingroup connectivity-nfc
+ \inmodule QtNfc
+
+ Applications can share NDEF data or file content using NFC technology by tapping two NFC-enabled devices
+ together. The QNearFieldShareManager provides a high level entry point to access this functionality.
+
+ The class allows both NDEF data and/or files to be shared between two devices by calling the setShareModes()
+ method. This method specifies either an NDEF Data and/or a File transfer. The targetDetected() signal is emitted
+ each time a share target is detected. A QNearFieldShareTarget pointer is passed with the signal, which can
+ be used to share either an NDEF message or one or more files.
+
+ The process of sharing files via NFC involves other underlying communication transports such as Bluetooth or Wi-Fi Direct.
+ It is implementation specific how and what type of transports are used to perform file transfer. The overall time taken to
+ transfer content depends on the maximum speed of the transport used. Note that the process of sharing NDEF message/data
+ does not require the use of other transports outside NFC.
+
+ If an error occurs, shareError() returns the error type.
+
+ Platforms that do not support both NDEF data and file content sharing modes can return the supported subset in the
+ supportedShareModes() method. Applications that call setShareModes() with an unsupported mode will receive an error
+ signal with a UnsupportedShareModeError.
+
+ Since sharing data over NFC is effectively a data pipe between two processes (one on the sender and one of
+ the receiver), the application developer should only create a single instance of QNearFieldShareManager per
+ application. This avoids the possibility that different parts of the same application attempt to all consume
+ data transferred over NFC.
+*/
+
+/*!
+ \enum QNearFieldShareManager::ShareError
+
+ This enum specifies the share error type.
+
+ \value NoError No error.
+ \value UnknownError Unknown or internal error occurred.
+ \value InvalidShareContentError Invalid content was provided for sharing.
+ \value ShareCanceledError Data or file sharing is canceled on the local or remote device.
+ \value ShareInterruptedError Data or file sharing is interrupted due to an I/O error.
+ \value ShareRejectedError Data or file sharing is rejected by the remote device.
+ \value UnsupportedShareModeError Data or file sharing is not supported by the share target.
+ \value ShareAlreadyInProgressError Data or file sharing is already in progress.
+ \value SharePermissionDeniedError File sharing is denied due to insufficient permission.
+*/
+
+/*!
+ \enum QNearFieldShareManager::ShareMode
+
+ This enum specifies the content type to be shared.
+
+ \value NoShare No content is currently set to be shared.
+ \value NdefShare Share NDEF message with target.
+ \value FileShare Share file with target.
+*/
+
+/*!
+ \fn void QNearFieldShareManager::targetDetected(QNearFieldShareTarget* shareTarget)
+
+ This signal is emitted whenever a \a shareTarget is detected. The \a shareTarget
+ instance is owned by QNearFieldShareManager and must not be deleted by the application.
+*/
+
+/*!
+ \fn void QNearFieldShareManager::shareModesChanged(ShareModes modes)
+
+ This signal is emitted whenever the share \a modes are changed.
+*/
+
+/*!
+ \fn void QNearFieldShareManager::error(ShareError error)
+
+ This signal is emitted whenever an \a error occurs related to a share request.
+*/
+
+/*!
+ Constructs a new near field share manager with \a parent.
+*/
+QNearFieldShareManager::QNearFieldShareManager(QObject *parent)
+: QObject(parent), d_ptr(new QNearFieldShareManagerPrivateImpl(this))
+{
+}
+
+/*!
+ Destroys the near field share manager.
+*/
+QNearFieldShareManager::~QNearFieldShareManager()
+{
+}
+
+/*!
+ Initializes the NFC share \a mode to detect a QNearFieldShareTarget for data and/or file sharing.
+ Calls to this method will overwrite previous share modes.
+
+ A shareModesChanged() signal will be emitted when share modes are different from previous modes.
+ A targetDetected() signal will be emitted if a share target is detected.
+*/
+void QNearFieldShareManager::setShareModes(ShareModes mode)
+{
+ Q_D(QNearFieldShareManager);
+ return d->setShareModes(mode);
+}
+
+/*!
+ Returns the shared modes supported by NFC.
+*/
+QNearFieldShareManager::ShareModes QNearFieldShareManager::supportedShareModes()
+{
+ return QNearFieldShareManagerPrivateImpl::supportedShareModes();
+}
+
+/*!
+ Returns which shared modes are set.
+*/
+QNearFieldShareManager::ShareModes QNearFieldShareManager::shareModes() const
+{
+ Q_D(const QNearFieldShareManager);
+ return d->shareModes();
+}
+
+/*!
+ Returns the error code of the error that occurred.
+ */
+QNearFieldShareManager::ShareError QNearFieldShareManager::shareError() const
+{
+ Q_D(const QNearFieldShareManager);
+ return d->shareError();
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldsharemanager.h b/src/nfc/qnearfieldsharemanager.h
new file mode 100644
index 00000000..00879d24
--- /dev/null
+++ b/src/nfc/qnearfieldsharemanager.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 QNEARFIELDSHAREMANAGER_H
+#define QNEARFIELDSHAREMANAGER_H
+
+#include <QtCore/QObject>
+#include <QtNfc/qnfcglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldShareManagerPrivate;
+class QNearFieldShareTarget;
+
+class Q_NFC_EXPORT QNearFieldShareManager : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(ShareError)
+ Q_ENUMS(ShareMode)
+
+public:
+ explicit QNearFieldShareManager(QObject *parent = 0);
+ ~QNearFieldShareManager();
+
+ enum ShareError {
+ NoError,
+ UnknownError,
+ InvalidShareContentError,
+ ShareCanceledError,
+ ShareInterruptedError,
+ ShareRejectedError,
+ UnsupportedShareModeError,
+ ShareAlreadyInProgressError,
+ SharePermissionDeniedError
+ };
+
+ enum ShareMode {
+ NoShare = 0x00,
+ NdefShare = 0x01,
+ FileShare = 0x02
+ };
+ Q_DECLARE_FLAGS(ShareModes, ShareMode)
+
+public:
+ static QNearFieldShareManager::ShareModes supportedShareModes();
+ void setShareModes(ShareModes modes);
+ QNearFieldShareManager::ShareModes shareModes() const;
+ QNearFieldShareManager::ShareError shareError() const;
+
+Q_SIGNALS:
+ void targetDetected(QNearFieldShareTarget* shareTarget);
+ void shareModesChanged(QNearFieldShareManager::ShareModes modes);
+ void error(QNearFieldShareManager::ShareError error);
+
+private:
+ QScopedPointer<QNearFieldShareManagerPrivate> const d_ptr;
+ Q_DECLARE_PRIVATE(QNearFieldShareManager)
+ Q_DISABLE_COPY(QNearFieldShareManager)
+
+ friend class QNearFieldShareManagerPrivateImpl;
+ friend class QNearFieldShareTargetPrivateImpl;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QNearFieldShareManager::ShareModes)
+
+QT_END_NAMESPACE
+
+#endif /* QNEARFIELDSHAREMANAGER_H */
diff --git a/src/nfc/qnearfieldsharemanager_p.h b/src/nfc/qnearfieldsharemanager_p.h
new file mode 100644
index 00000000..42e3adfe
--- /dev/null
+++ b/src/nfc/qnearfieldsharemanager_p.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 QNEARFIELDSHAREMANAGER_P_H_
+#define QNEARFIELDSHAREMANAGER_P_H_
+
+#include "qnearfieldsharemanager.h"
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldShareManagerPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ QNearFieldShareManagerPrivate(QNearFieldShareManager* q)
+ : QObject(q)
+ {
+ }
+
+ ~QNearFieldShareManagerPrivate()
+ {
+ }
+
+ virtual void setShareModes(QNearFieldShareManager::ShareModes modes)
+ {
+ Q_UNUSED(modes)
+ }
+
+ virtual QNearFieldShareManager::ShareModes shareModes() const
+ {
+ return QNearFieldShareManager::NoShare;
+ }
+
+ virtual QNearFieldShareManager::ShareError shareError() const
+ {
+ return QNearFieldShareManager::NoError;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif /* QNEARFIELDSHAREMANAGER_P_H_ */
diff --git a/src/nfc/qnearfieldsharemanager_qnx_p.cpp b/src/nfc/qnearfieldsharemanager_qnx_p.cpp
new file mode 100644
index 00000000..41700afe
--- /dev/null
+++ b/src/nfc/qnearfieldsharemanager_qnx_p.cpp
@@ -0,0 +1,151 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 "qnearfieldsharemanager_qnx_p.h"
+#include "qnearfieldsharetarget.h"
+#include "qnx/qnxnfcsharemanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace bb::system;
+
+QNearFieldShareManagerPrivateImpl::QNearFieldShareManagerPrivateImpl(QNearFieldShareManager* q)
+ : QNearFieldShareManagerPrivate(q), q_ptr(q), _manager(0), _target(0), _shareError(QNearFieldShareManager::NoError)
+{
+ _manager = QNXNFCShareManager::instance();
+ _manager->connect(this);
+}
+
+QNearFieldShareManagerPrivateImpl::~QNearFieldShareManagerPrivateImpl()
+{
+ if (_target) {
+ delete _target;
+ }
+
+ _manager->disconnect(this);
+}
+
+void QNearFieldShareManagerPrivateImpl::onShareModeChanged(NfcShareMode::Type mode)
+{
+ switch (mode) {
+ case NfcShareMode::DataSnep: {
+ emit q_ptr->shareModesChanged(QNearFieldShareManager::NdefShare);
+ break;
+ }
+
+ case NfcShareMode::File: {
+ emit q_ptr->shareModesChanged(QNearFieldShareManager::FileShare);
+ break;
+ }
+
+ case NfcShareMode::Disabled: {
+ emit q_ptr->shareModesChanged(QNearFieldShareManager::NoShare);
+ break;
+ }
+
+ default: {
+ }
+ }
+}
+
+void QNearFieldShareManagerPrivateImpl::onError(NfcShareError::Type error)
+{
+ _shareError = QNXNFCShareManager::toShareError(error);
+
+ if (_shareError != QNearFieldShareManager::NoError)
+ emit q_ptr->error(_shareError);
+}
+
+void QNearFieldShareManagerPrivateImpl::onFinished(NfcShareSuccess::Type result)
+{
+ Q_UNUSED(result)
+}
+
+void QNearFieldShareManagerPrivateImpl::onTargetAcquired()
+{
+ if (_target) {
+ delete _target;
+ _target = 0;
+ }
+
+ _target = new QNearFieldShareTarget(shareModes(), this);
+ emit q_ptr->targetDetected(_target);
+}
+
+void QNearFieldShareManagerPrivateImpl::onTargetCancelled()
+{
+}
+
+QNearFieldShareManager::ShareModes QNearFieldShareManagerPrivateImpl::supportedShareModes()
+{
+ return QNearFieldShareManager::NdefShare | QNearFieldShareManager::FileShare;
+}
+
+void QNearFieldShareManagerPrivateImpl::setShareModes(QNearFieldShareManager::ShareModes modes)
+{
+ _shareError = QNearFieldShareManager::NoError;
+
+ if (modes == QNearFieldShareManager::NoShare) {
+ _manager->setShareMode(NfcShareMode::Disabled);
+ _manager->reset();
+ }
+
+ else {
+ // TODO: Fix NfcShareManager to handle multiple share modes simultaneously
+ if (modes.testFlag(QNearFieldShareManager::NdefShare))
+ _manager->setShareMode(NfcShareMode::DataSnep);
+
+ if (modes.testFlag(QNearFieldShareManager::FileShare))
+ _manager->setShareMode(NfcShareMode::File);
+ }
+}
+
+QNearFieldShareManager::ShareModes QNearFieldShareManagerPrivateImpl::shareModes() const
+{
+ return QNXNFCShareManager::toShareModes(_manager->shareMode());
+}
+
+QNearFieldShareManager::ShareError QNearFieldShareManagerPrivateImpl::shareError() const
+{
+ return _shareError;
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldsharemanager_qnx_p.h b/src/nfc/qnearfieldsharemanager_qnx_p.h
new file mode 100644
index 00000000..5d973bcf
--- /dev/null
+++ b/src/nfc/qnearfieldsharemanager_qnx_p.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 QNEARFIELDSHAREMANAGER_QNX_P_H_
+#define QNEARFIELDSHAREMANAGER_QNX_P_H_
+
+#include "qnearfieldsharemanager_p.h"
+#include <bb/system/NfcShareManager>
+
+QT_BEGIN_NAMESPACE
+
+class QNXNFCShareManager;
+
+class QNearFieldShareManagerPrivateImpl : public QNearFieldShareManagerPrivate
+{
+ Q_OBJECT
+
+public:
+ QNearFieldShareManagerPrivateImpl(QNearFieldShareManager* q);
+ ~QNearFieldShareManagerPrivateImpl();
+
+ static QNearFieldShareManager::ShareModes supportedShareModes();
+ void setShareModes(QNearFieldShareManager::ShareModes modes);
+ QNearFieldShareManager::ShareModes shareModes() const;
+ QNearFieldShareManager::ShareError shareError() const;
+
+private Q_SLOTS:
+ void onShareModeChanged(bb::system::NfcShareMode::Type mode);
+ void onError(bb::system::NfcShareError::Type error);
+ void onFinished(bb::system::NfcShareSuccess::Type result);
+ void onTargetAcquired();
+ void onTargetCancelled();
+
+private:
+ QNearFieldShareManager * const q_ptr;
+ Q_DECLARE_PUBLIC(QNearFieldShareManager)
+
+ QNXNFCShareManager *_manager;
+ QNearFieldShareTarget *_target;
+ QNearFieldShareManager::ShareError _shareError;
+};
+
+QT_END_NAMESPACE
+
+#endif /* QNEARFIELDSHAREMANAGER_QNX_P_H_ */
diff --git a/src/nfc/qnearfieldsharemanagerimpl_p.cpp b/src/nfc/qnearfieldsharemanagerimpl_p.cpp
new file mode 100644
index 00000000..d9cd2f45
--- /dev/null
+++ b/src/nfc/qnearfieldsharemanagerimpl_p.cpp
@@ -0,0 +1,60 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 "qnearfieldsharemanagerimpl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QNearFieldShareManagerPrivateImpl::QNearFieldShareManagerPrivateImpl(QNearFieldShareManager* q)
+ : QNearFieldShareManagerPrivate(q)
+{
+}
+
+QNearFieldShareManagerPrivateImpl::~QNearFieldShareManagerPrivateImpl()
+{
+}
+
+QNearFieldShareManager::ShareModes QNearFieldShareManagerPrivateImpl::supportedShareModes()
+{
+ return QNearFieldShareManager::NoShare;
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldsharemanagerimpl_p.h b/src/nfc/qnearfieldsharemanagerimpl_p.h
new file mode 100644
index 00000000..0c7d9ac5
--- /dev/null
+++ b/src/nfc/qnearfieldsharemanagerimpl_p.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 QNEARFIELDSHAREMANAGERIMPL_P_H_
+#define QNEARFIELDSHAREMANAGERIMPL_P_H_
+
+#include "qnearfieldsharemanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldShareManagerPrivateImpl : public QNearFieldShareManagerPrivate
+{
+public:
+ QNearFieldShareManagerPrivateImpl(QNearFieldShareManager* q);
+ ~QNearFieldShareManagerPrivateImpl();
+
+ static QNearFieldShareManager::ShareModes supportedShareModes();
+};
+
+QT_END_NAMESPACE
+
+#endif /* QNEARFIELDSHAREMANAGERIMPL_P_H_ */
diff --git a/src/nfc/qnearfieldsharetarget.cpp b/src/nfc/qnearfieldsharetarget.cpp
new file mode 100644
index 00000000..9ac66c5c
--- /dev/null
+++ b/src/nfc/qnearfieldsharetarget.cpp
@@ -0,0 +1,151 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 "qnearfieldsharetarget.h"
+#include "qnearfieldsharetarget_p.h"
+
+#if defined(QNX_NFC)
+#include "qnearfieldsharetarget_qnx_p.h"
+#else
+#include "qnearfieldsharetargetimpl_p.h"
+#endif
+
+#include "qnearfieldsharemanager.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QNearFieldShareTarget
+ \brief The QNearFieldShareTarget class transfers data to remote device over NFC.
+
+ \ingroup connectivity-nfc
+ \inmodule QtNfc
+
+ The QNearFieldShareTarget class can be used for sharing NDEF message or files to a remote
+ NFC enabled device supporting the same protocol.
+*/
+
+/*!
+ \fn void QNearFieldShareTarget::error(QNearFieldShareManager::ShareError error)
+
+ This signal is emitted whenever an \a error occurs during transfer.
+*/
+
+/*!
+ \fn void QNearFieldShareTarget::shareFinished()
+
+ This signal is emitted whenever a data or file transfer has completed successfully.
+*/
+
+/*!
+ Constructs a new near field share target with \a parent.
+*/
+QNearFieldShareTarget::QNearFieldShareTarget(QNearFieldShareManager::ShareModes modes, QObject *parent)
+: QObject(parent), d_ptr(new QNearFieldShareTargetPrivateImpl(modes, this))
+{
+}
+
+/*!
+ Destroys the near field share target.
+*/
+QNearFieldShareTarget::~QNearFieldShareTarget()
+{
+}
+
+/*!
+ Returns the share mode supported by the share target.
+*/
+QNearFieldShareManager::ShareModes QNearFieldShareTarget::shareModes() const
+{
+ Q_D(const QNearFieldShareTarget);
+ return d->shareModes();
+}
+
+/*!
+ Share the NDEF \a message via the share target. This method starts sharing asynchronously and returns immediately.
+ The method returns true if the request is accepted, otherwise returns false. Sharing is completed when the shareFinished()
+ signal is emitted.
+*/
+bool QNearFieldShareTarget::share(const QNdefMessage &message)
+{
+ Q_D(QNearFieldShareTarget);
+ return d->share(message);
+}
+
+/*!
+ Share the \a files via the share target. This method starts sharing asynchronously and returns immediately.
+ The method returns true if the request is accepted, otherwise returns false. Sharing is completed when the shareFinished()
+ signal is emitted.
+*/
+bool QNearFieldShareTarget::share(const QList<QFileInfo> &files)
+{
+ Q_D(QNearFieldShareTarget);
+ return d->share(files);
+}
+
+/*!
+ Cancel the data or file sharing in progress.
+*/
+void QNearFieldShareTarget::cancel()
+{
+ Q_D(QNearFieldShareTarget);
+ d->cancel();
+}
+
+/*!
+ Returns true if data or file sharing is in progress, otherwise returns false.
+*/
+bool QNearFieldShareTarget::isShareInProgress() const
+{
+ Q_D(const QNearFieldShareTarget);
+ return d->isShareInProgress();
+}
+
+/*!
+ Returns the error code of the error that occurred.
+ */
+QNearFieldShareManager::ShareError QNearFieldShareTarget::shareError() const
+{
+ Q_D(const QNearFieldShareTarget);
+ return d->shareError();
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldsharetarget.h b/src/nfc/qnearfieldsharetarget.h
new file mode 100644
index 00000000..96a4a312
--- /dev/null
+++ b/src/nfc/qnearfieldsharetarget.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 QNEARFIELDSHARETARGET_H
+#define QNEARFIELDSHARETARGET_H
+
+#include <QtCore/QObject>
+#include <QFileInfo>
+#include <QtNfc/QNdefMessage>
+#include <QtNfc/QNearFieldShareManager>
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldShareTargetPrivate;
+
+class Q_NFC_EXPORT QNearFieldShareTarget : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~QNearFieldShareTarget();
+
+ QNearFieldShareManager::ShareModes shareModes() const;
+ bool share(const QNdefMessage &message);
+ bool share(const QList<QFileInfo> &files);
+ void cancel();
+ bool isShareInProgress() const;
+ QNearFieldShareManager::ShareError shareError() const;
+
+Q_SIGNALS:
+ void error(QNearFieldShareManager::ShareError error);
+ void shareFinished();
+
+private:
+ explicit QNearFieldShareTarget(QNearFieldShareManager::ShareModes modes, QObject *parent = 0);
+
+ QNearFieldShareTargetPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(QNearFieldShareTarget)
+ Q_DISABLE_COPY(QNearFieldShareTarget)
+
+ friend class QNearFieldShareManagerPrivateImpl;
+ friend class QNearFieldShareTargetPrivateImpl;
+};
+
+QT_END_NAMESPACE
+
+#endif /* QNEARFIELDSHARETARGET_H */
diff --git a/src/nfc/qnearfieldsharetarget_p.h b/src/nfc/qnearfieldsharetarget_p.h
new file mode 100644
index 00000000..729acb0e
--- /dev/null
+++ b/src/nfc/qnearfieldsharetarget_p.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 QNEARFIELDSHARETARGET_P_H
+#define QNEARFIELDSHARETARGET_P_H
+
+#include "qnearfieldsharetarget.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldShareTargetPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ QNearFieldShareTargetPrivate(QNearFieldShareManager::ShareModes modes, QNearFieldShareTarget *q)
+ : QObject(q)
+ {
+ Q_UNUSED(modes)
+ }
+
+ ~QNearFieldShareTargetPrivate()
+ {
+ }
+
+ virtual QNearFieldShareManager::ShareModes shareModes() const
+ {
+ return QNearFieldShareManager::NoShare;
+ }
+
+ virtual bool share(const QNdefMessage &message)
+ {
+ Q_UNUSED(message)
+ return false;
+ }
+
+ virtual bool share(const QList<QFileInfo> &files)
+ {
+ Q_UNUSED(files)
+ return false;
+ }
+
+ virtual void cancel()
+ {
+ }
+
+ virtual bool isShareInProgress() const
+ {
+ return false;
+ }
+
+ virtual QNearFieldShareManager::ShareError shareError() const
+ {
+ return QNearFieldShareManager::NoError;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif /* QNEARFIELDSHARETARGET_P_H */
diff --git a/src/nfc/qnearfieldsharetarget_qnx_p.cpp b/src/nfc/qnearfieldsharetarget_qnx_p.cpp
new file mode 100644
index 00000000..01445641
--- /dev/null
+++ b/src/nfc/qnearfieldsharetarget_qnx_p.cpp
@@ -0,0 +1,120 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 "qnearfieldsharetarget_qnx_p.h"
+#include "qnearfieldsharemanager_p.h"
+#include "qnx/qnxnfcsharemanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace bb::system;
+
+QNearFieldShareTargetPrivateImpl::QNearFieldShareTargetPrivateImpl(QNearFieldShareManager::ShareModes modes, QNearFieldShareTarget *q)
+: QNearFieldShareTargetPrivate(modes, q), q_ptr(q), _error(QNearFieldShareManager::NoError)
+{
+ _manager = QNXNFCShareManager::instance();
+ _manager->connect(this);
+}
+
+QNearFieldShareTargetPrivateImpl::~QNearFieldShareTargetPrivateImpl()
+{
+ _manager->disconnect(this);
+}
+
+QNearFieldShareManager::ShareModes QNearFieldShareTargetPrivateImpl::shareModes() const
+{
+ return QNXNFCShareManager::toShareModes(_manager->shareMode());
+}
+
+bool QNearFieldShareTargetPrivateImpl::share(const QNdefMessage &message)
+{
+ return _manager->shareNdef(message);
+}
+
+bool QNearFieldShareTargetPrivateImpl::share(const QList<QFileInfo> &files)
+{
+ return _manager->shareFiles(files);
+}
+
+void QNearFieldShareTargetPrivateImpl::cancel()
+{
+ _manager->cancel();
+}
+
+bool QNearFieldShareTargetPrivateImpl::isShareInProgress() const
+{
+ return QNXNFCShareManager::toShareModes(_manager->shareMode()) != QNearFieldShareManager::NoShare;
+}
+
+QNearFieldShareManager::ShareError QNearFieldShareTargetPrivateImpl::shareError() const
+{
+ return _error;
+}
+
+void QNearFieldShareTargetPrivateImpl::onShareModeChanged(NfcShareMode::Type mode)
+{
+ Q_UNUSED(mode)
+}
+
+void QNearFieldShareTargetPrivateImpl::onError(NfcShareError::Type error)
+{
+ _error = QNXNFCShareManager::toShareError(error);
+
+ if (_error != QNearFieldShareManager::NoError) {
+ emit q_ptr->error(_error);
+ }
+}
+
+void QNearFieldShareTargetPrivateImpl::onFinished(NfcShareSuccess::Type result)
+{
+ Q_UNUSED(result)
+ emit q_ptr->shareFinished();
+}
+
+void QNearFieldShareTargetPrivateImpl::onTargetAcquired()
+{
+}
+
+void QNearFieldShareTargetPrivateImpl::onTargetCancelled()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldsharetarget_qnx_p.h b/src/nfc/qnearfieldsharetarget_qnx_p.h
new file mode 100644
index 00000000..16bf429f
--- /dev/null
+++ b/src/nfc/qnearfieldsharetarget_qnx_p.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 QNEARFIELDSHARETARGET_QNX_P_H
+#define QNEARFIELDSHARETARGET_QNX_P_H
+
+#include "qnearfieldsharetarget_p.h"
+#include <bb/system/NfcShareManager>
+
+QT_BEGIN_NAMESPACE
+
+class QNXNFCShareManager;
+
+class QNearFieldShareTargetPrivateImpl : public QNearFieldShareTargetPrivate
+{
+ Q_OBJECT
+
+public:
+ QNearFieldShareTargetPrivateImpl(QNearFieldShareManager::ShareModes modes, QNearFieldShareTarget *q);
+ ~QNearFieldShareTargetPrivateImpl();
+
+ QNearFieldShareManager::ShareModes shareModes() const;
+ bool share(const QNdefMessage &message);
+ bool share(const QList<QFileInfo> &files);
+ void cancel();
+ bool isShareInProgress() const;
+ QNearFieldShareManager::ShareError shareError() const;
+
+private Q_SLOTS:
+ void onShareModeChanged(bb::system::NfcShareMode::Type mode);
+ void onError(bb::system::NfcShareError::Type error);
+ void onFinished(bb::system::NfcShareSuccess::Type result);
+ void onTargetAcquired();
+ void onTargetCancelled();
+
+private:
+ QNearFieldShareTarget * const q_ptr;
+ Q_DECLARE_PUBLIC(QNearFieldShareTarget)
+
+ QNXNFCShareManager *_manager;
+ QNearFieldShareManager::ShareError _error;
+};
+
+QT_END_NAMESPACE
+
+#endif /* QNEARFIELDSHARETARGET_QNX_P_H */
diff --git a/src/nfc/qnearfieldsharetargetimpl_p.cpp b/src/nfc/qnearfieldsharetargetimpl_p.cpp
new file mode 100644
index 00000000..f5d86cf6
--- /dev/null
+++ b/src/nfc/qnearfieldsharetargetimpl_p.cpp
@@ -0,0 +1,55 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 "qnearfieldsharetargetimpl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QNearFieldShareTargetPrivateImpl::QNearFieldShareTargetPrivateImpl(QNearFieldShareManager::ShareModes /*modes*/, QNearFieldShareTarget *q)
+ : QNearFieldShareTargetPrivate(QNearFieldShareManager::NoShare, q)
+{
+}
+
+QNearFieldShareTargetPrivateImpl::~QNearFieldShareTargetPrivateImpl()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldsharetargetimpl_p.h b/src/nfc/qnearfieldsharetargetimpl_p.h
new file mode 100644
index 00000000..93b6f81d
--- /dev/null
+++ b/src/nfc/qnearfieldsharetargetimpl_p.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 QNEARFIELDSHARETARGETIMPL_P_H
+#define QNEARFIELDSHARETARGETIMPL_P_H
+
+#include "qnearfieldsharetarget_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldShareTargetPrivateImpl : public QNearFieldShareTargetPrivate
+{
+public:
+ QNearFieldShareTargetPrivateImpl(QNearFieldShareManager::ShareModes modes, QNearFieldShareTarget *q);
+ ~QNearFieldShareTargetPrivateImpl();
+};
+
+QT_END_NAMESPACE
+
+#endif /* QNEARFIELDSHARETARGETIMPL_P_H */
diff --git a/src/nfc/qnx/qnxnfcmanager.cpp b/src/nfc/qnx/qnxnfcmanager.cpp
index 3fde4d18..92152c26 100644
--- a/src/nfc/qnx/qnxnfcmanager.cpp
+++ b/src/nfc/qnx/qnxnfcmanager.cpp
@@ -155,7 +155,7 @@ QNXNFCManager::QNXNFCManager()
ndefEventFilter = new QNXNFCEventFilter();
ndefEventFilter->installOnEventDispatcher(QAbstractEventDispatcher::instance());
- connect(ndefEventFilter, SIGNAL(ndefEvent(const QNdefMessage&)), this, SLOT(invokeNdefMessage(const QNdefMessage&)));
+ connect(ndefEventFilter, SIGNAL(ndefEvent(QNdefMessage)), this, SLOT(invokeNdefMessage(QNdefMessage)));
}
QNXNFCManager::~QNXNFCManager()
@@ -364,7 +364,7 @@ void QNXNFCManager::setupInvokeTarget() {
//Get the correct target-id
QString targetId = QCoreApplication::instance()->arguments().first();
- targetId = targetId.left(targetId.lastIndexOf("."));
+ targetId = targetId.left(targetId.lastIndexOf(QLatin1Char('.')));
if (BPS_SUCCESS != navigator_invoke_set_filters("20", targetId.toLatin1().constData(), filters, 1)) {
qWarning() << "NFC Error setting share target filter";
diff --git a/src/nfc/qnx/qnxnfcsharemanager_p.cpp b/src/nfc/qnx/qnxnfcsharemanager_p.cpp
new file mode 100644
index 00000000..684a1a46
--- /dev/null
+++ b/src/nfc/qnx/qnxnfcsharemanager_p.cpp
@@ -0,0 +1,280 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 "qnxnfcsharemanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace bb::system;
+
+const char *QNXNFCShareManager::RECORD_NDEF = "application/vnd.rim.nfc.ndef";
+Q_GLOBAL_STATIC(QNXNFCShareManager, shareStatic)
+
+QNXNFCShareManager *QNXNFCShareManager::instance()
+{
+ return shareStatic();
+}
+
+bool QNXNFCShareManager::shareNdef(const QNdefMessage &message)
+{
+ bool ok = false;
+ NfcShareDataContent content;
+ content.setMimeType(RECORD_NDEF);
+ content.setData(message.toByteArray());
+
+ NfcShareSetContentError::Type err = _manager->setShareContent(content);
+
+ switch (err) {
+ case NfcShareSetContentError::None: {
+ ok = true;
+ break;
+ }
+
+ case NfcShareSetContentError::TransferInProgress: {
+ emit error(NfcShareError::TransferInProgress);
+ break;
+ }
+
+ case NfcShareSetContentError::InvalidShareMode:
+ case NfcShareSetContentError::InvalidShareRequest: {
+ emit error(NfcShareError::UnsupportedShareMode);
+ break;
+ }
+
+ case NfcShareSetContentError::Unknown: {
+ emit error(NfcShareError::Unknown);
+ break;
+ }
+ }
+
+ if (ok)
+ _manager->startTransfer();
+
+ return ok;
+}
+
+bool QNXNFCShareManager::shareFiles(const QList<QFileInfo> &files)
+{
+ bool ok = false;
+ NfcShareFilesContent content;
+ QList<QUrl> urls;
+
+ for (int i=0; i<files.size(); i++) {
+ urls.append(QUrl::fromLocalFile(files[i].filePath()));
+ }
+
+ content.setFileUrls(urls);
+
+ NfcShareSetContentError::Type err = _manager->setShareContent(content);
+
+ switch (err) {
+ case NfcShareSetContentError::None: {
+ ok = true;
+ break;
+ }
+
+ case NfcShareSetContentError::TransferInProgress: {
+ emit error(NfcShareError::TransferInProgress);
+ break;
+ }
+
+ case NfcShareSetContentError::InvalidShareMode:
+ case NfcShareSetContentError::InvalidShareRequest: {
+ emit error(NfcShareError::UnsupportedShareMode);
+ break;
+ }
+
+ case NfcShareSetContentError::Unknown: {
+ emit error(NfcShareError::Unknown);
+ break;
+ }
+ }
+
+ if (ok)
+ _manager->startTransfer();
+
+ return ok;
+}
+
+void QNXNFCShareManager::cancel()
+{
+ _manager->cancelTarget();
+}
+
+void QNXNFCShareManager::setShareMode(NfcShareMode::Type type)
+{
+ _manager->setShareMode(type, NfcShareStartTransferMode::OnDemand);
+}
+
+NfcShareMode::Type QNXNFCShareManager::shareMode() const
+{
+ return _manager->shareMode();
+}
+
+void QNXNFCShareManager::connect(QObject *obj)
+{
+ QObject::connect(this, SIGNAL(shareModeChanged(bb::system::NfcShareMode::Type)),
+ obj, SLOT(onShareModeChanged(bb::system::NfcShareMode::Type)));
+ QObject::connect(this, SIGNAL(error(bb::system::NfcShareError::Type)),
+ obj, SLOT(onError(bb::system::NfcShareError::Type)));
+ QObject::connect(this, SIGNAL(finished(bb::system::NfcShareSuccess::Type)),
+ obj, SLOT(onFinished(bb::system::NfcShareSuccess::Type)));
+ QObject::connect(this, SIGNAL(targetAcquired()),
+ obj, SLOT(onTargetAcquired()));
+ QObject::connect(this, SIGNAL(targetCancelled()),
+ obj, SLOT(onTargetCancelled()));
+}
+
+void QNXNFCShareManager::disconnect(QObject *obj)
+{
+ QObject::disconnect(this, SIGNAL(shareModeChanged(bb::system::NfcShareMode::Type)),
+ obj, SLOT(onShareModeChanged(bb::system::NfcShareMode::Type)));
+ QObject::disconnect(this, SIGNAL(error(bb::system::NfcShareError::Type)),
+ obj, SLOT(onError(bb::system::NfcShareError::Type)));
+ QObject::disconnect(this, SIGNAL(finished(bb::system::NfcShareSuccess::Type)),
+ obj, SLOT(onFinished(bb::system::NfcShareSuccess::Type)));
+ QObject::disconnect(this, SIGNAL(targetAcquired()),
+ obj, SLOT(onTargetAcquired()));
+ QObject::disconnect(this, SIGNAL(targetCancelled()),
+ obj, SLOT(onTargetCancelled()));
+}
+
+void QNXNFCShareManager::reset()
+{
+ _manager->reset();
+}
+
+QNXNFCShareManager::QNXNFCShareManager()
+ : QObject()
+{
+ _manager = new NfcShareManager(this);
+ QObject::connect(_manager, SIGNAL(shareModeChanged(bb::system::NfcShareMode::Type)),
+ this, SIGNAL(shareModeChanged(bb::system::NfcShareMode::Type)));
+ QObject::connect(_manager, SIGNAL(error(bb::system::NfcShareError::Type)),
+ this, SIGNAL(error(bb::system::NfcShareError::Type)));
+ QObject::connect(_manager, SIGNAL(finished(bb::system::NfcShareSuccess::Type)),
+ this, SIGNAL(finished(bb::system::NfcShareSuccess::Type)));
+ QObject::connect(_manager, SIGNAL(targetAcquired()),
+ this, SIGNAL(targetAcquired()));
+ QObject::connect(_manager, SIGNAL(targetCancelled()),
+ this, SIGNAL(targetCancelled()));
+}
+
+QNXNFCShareManager::~QNXNFCShareManager()
+{
+ delete _manager;
+}
+
+QNearFieldShareManager::ShareError QNXNFCShareManager::toShareError(NfcShareError::Type nfcShareError)
+{
+ QNearFieldShareManager::ShareError shareError = QNearFieldShareManager::NoError;
+
+ switch (nfcShareError) {
+ case NfcShareError::Unknown: {
+ shareError = QNearFieldShareManager::UnknownError;
+ break;
+ }
+
+ case NfcShareError::NoContentToShare:
+ case NfcShareError::MessageSize:
+ case NfcShareError::TagLocked:
+ case NfcShareError::UnsupportedTagType: {
+ shareError = QNearFieldShareManager::InvalidShareContentError;
+ break;
+ }
+
+ case NfcShareError::RegisterFileSharing:
+ case NfcShareError::RegisterDataSharing: {
+ shareError = QNearFieldShareManager::InvalidShareContentError;
+ break;
+ }
+
+ case NfcShareError::DataTransferFailed:
+ case NfcShareError::BluetoothFileTransferFailed:
+ case NfcShareError::WiFiDirectFileTransferFailed:
+ case NfcShareError::HandoverFailed: {
+ shareError = QNearFieldShareManager::ShareInterruptedError;
+ break;
+ }
+
+ case NfcShareError::BluetoothFileTransferCancelled:
+ case NfcShareError::WiFiDirectFileTransferCancelled: {
+ shareError = QNearFieldShareManager::ShareCanceledError;
+ break;
+ }
+
+ case NfcShareError::TransferInProgress: {
+ shareError = QNearFieldShareManager::ShareAlreadyInProgressError;
+ break;
+ }
+
+ case NfcShareError::UnsupportedShareMode: {
+ shareError = QNearFieldShareManager::UnsupportedShareModeError;
+ break;
+ }
+
+ case NfcShareError::NoTransferTarget: {
+ shareError = QNearFieldShareManager::ShareRejectedError;
+ break;
+ }
+
+ default: {
+ shareError = QNearFieldShareManager::UnknownError;
+ }
+ }
+
+ return shareError;
+}
+
+QNearFieldShareManager::ShareModes QNXNFCShareManager::toShareModes(NfcShareMode::Type nfcShareMode)
+{
+ QNearFieldShareManager::ShareModes modes = QNearFieldShareManager::NoShare;
+
+ if (nfcShareMode == NfcShareMode::DataSnep)
+ modes |= QNearFieldShareManager::NdefShare;
+
+ else if (nfcShareMode == NfcShareMode::File)
+ modes |= QNearFieldShareManager::FileShare;
+
+ return modes;
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnx/qnxnfcsharemanager_p.h b/src/nfc/qnx/qnxnfcsharemanager_p.h
new file mode 100644
index 00000000..ae6511eb
--- /dev/null
+++ b/src/nfc/qnx/qnxnfcsharemanager_p.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ **
+ ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtNfc 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 QNXNFCSHAREMANAGER_P_H
+#define QNXNFCSHAREMANAGER_P_H
+
+#include "qnearfieldsharemanager.h"
+#include <bb/system/NfcShareManager>
+#include <QFileInfo>
+#include <QNdefMessage>
+
+QT_BEGIN_NAMESPACE
+
+class Q_DECL_EXPORT QNXNFCShareManager : public QObject
+{
+ Q_OBJECT
+public:
+ static QNXNFCShareManager *instance();
+
+ QNXNFCShareManager();
+ ~QNXNFCShareManager();
+
+ bool shareNdef(const QNdefMessage &message);
+ bool shareFiles(const QList<QFileInfo> &files);
+ void cancel();
+
+ void setShareMode(bb::system::NfcShareMode::Type type);
+ bb::system::NfcShareMode::Type shareMode() const;
+
+ void connect(QObject *obj);
+ void disconnect(QObject *obj);
+
+ void reset();
+
+ static QNearFieldShareManager::ShareError toShareError(bb::system::NfcShareError::Type nfcShareError);
+ static QNearFieldShareManager::ShareModes toShareModes(bb::system::NfcShareMode::Type nfcShareMode);
+
+private:
+ bb::system::NfcShareManager *_manager;
+ static const char *RECORD_NDEF;
+
+Q_SIGNALS:
+ void shareModeChanged(bb::system::NfcShareMode::Type);
+ void error(bb::system::NfcShareError::Type);
+ void finished(bb::system::NfcShareSuccess::Type);
+ void targetAcquired();
+ void targetCancelled();
+};
+
+QT_END_NAMESPACE
+
+#endif /* QNXNFCSHAREMANAGER_P_H */
diff --git a/src/nfc/qqmlndefrecord.cpp b/src/nfc/qqmlndefrecord.cpp
index 8a3f24d7..c94578eb 100644
--- a/src/nfc/qqmlndefrecord.cpp
+++ b/src/nfc/qqmlndefrecord.cpp
@@ -262,6 +262,7 @@ QQmlNdefRecord::QQmlNdefRecord(const QNdefRecord &record, QObject *parent)
\value Uri The NDEF record type follows the construct described in RFC 3986.
\value ExternalRtd The NDEF record type follows the construct for external type names
described the NFC RTD Specification.
+ \value Unknown The NDEF record type is unknown.
*/
/*!
diff --git a/src/src.pro b/src/src.pro
index 6a16cd3d..47ab514a 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -2,4 +2,5 @@ TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += bluetooth nfc
+android: SUBDIRS += android
qtHaveModule(quick): SUBDIRS += imports
diff --git a/sync.profile b/sync.profile
index 34518c9a..1204b458 100644
--- a/sync.profile
+++ b/sync.profile
@@ -15,4 +15,5 @@
"qtbase" => "",
"qtdeclarative" => "",
"qtxmlpatterns" => "",
+ "qtandroidextras" => "",
);
diff --git a/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp b/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp
index fd923f0e..d20458fd 100644
--- a/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp
+++ b/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp
@@ -86,6 +86,8 @@ private slots:
void tst_properties();
+ void tst_invalidBtAddress();
+
void tst_startStopDeviceDiscoveries();
void tst_deviceDiscovery_data();
@@ -143,6 +145,24 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_properties()
QCOMPARE(discoveryAgent.inquiryType(), QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry);
}
+void tst_QBluetoothDeviceDiscoveryAgent::tst_invalidBtAddress()
+{
+ QBluetoothDeviceDiscoveryAgent *discoveryAgent = new QBluetoothDeviceDiscoveryAgent(QBluetoothAddress("11:11:11:11:11:11"));
+
+ QCOMPARE(discoveryAgent->error(), QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError);
+ discoveryAgent->start();
+ QCOMPARE(discoveryAgent->isActive(), false);
+ delete discoveryAgent;
+
+ discoveryAgent = new QBluetoothDeviceDiscoveryAgent(QBluetoothAddress());
+ QCOMPARE(discoveryAgent->error(), QBluetoothDeviceDiscoveryAgent::NoError);
+ if (QBluetoothLocalDevice::allDevices().count() > 0) {
+ discoveryAgent->start();
+ QCOMPARE(discoveryAgent->isActive(), true);
+ }
+ delete discoveryAgent;
+}
+
void tst_QBluetoothDeviceDiscoveryAgent::deviceDiscoveryDebug(const QBluetoothDeviceInfo &info)
{
qDebug() << "Discovered device:" << info.address().toString() << info.name();
diff --git a/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp b/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp
index dc065096..cd5b1166 100644
--- a/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp
+++ b/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp
@@ -81,6 +81,7 @@ public slots:
private slots:
void initTestCase();
+ void tst_invalidBtAddress();
void tst_serviceDiscovery_data();
void tst_serviceDiscovery();
void tst_serviceDiscoveryAdapters();
@@ -155,6 +156,24 @@ void tst_QBluetoothServiceDiscoveryAgent::initTestCase()
}
}
+void tst_QBluetoothServiceDiscoveryAgent::tst_invalidBtAddress()
+{
+ QBluetoothServiceDiscoveryAgent *discoveryAgent = new QBluetoothServiceDiscoveryAgent(QBluetoothAddress("11:11:11:11:11:11"));
+
+ QCOMPARE(discoveryAgent->error(), QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError);
+ discoveryAgent->start();
+ QCOMPARE(discoveryAgent->isActive(), false);
+ delete discoveryAgent;
+
+ discoveryAgent = new QBluetoothServiceDiscoveryAgent(QBluetoothAddress());
+ QCOMPARE(discoveryAgent->error(), QBluetoothServiceDiscoveryAgent::NoError);
+ if (QBluetoothLocalDevice::allDevices().count() > 0) {
+ discoveryAgent->start();
+ QCOMPARE(discoveryAgent->isActive(), true);
+ }
+ delete discoveryAgent;
+}
+
void tst_QBluetoothServiceDiscoveryAgent::serviceDiscoveryDebug(const QBluetoothServiceInfo &info)
{
qDebug() << "Discovered service on"
diff --git a/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp b/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp
index 62550622..2195bc0e 100644
--- a/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp
+++ b/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp
@@ -71,6 +71,8 @@ private slots:
void tst_assignment_data();
void tst_assignment();
+
+ void tst_serviceClassUuids();
};
tst_QBluetoothServiceInfo::tst_QBluetoothServiceInfo()
@@ -329,6 +331,27 @@ void tst_QBluetoothServiceInfo::tst_assignment()
}
}
+void tst_QBluetoothServiceInfo::tst_serviceClassUuids()
+{
+ QBluetoothServiceInfo info;
+ QCOMPARE(info.serviceClassUuids().count(), 0);
+
+ QBluetoothServiceInfo::Sequence classIds;
+ classIds << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ QCOMPARE(classIds.count(), 1);
+
+ QBluetoothUuid uuid(QString("e8e10f95-1a70-4b27-9ccf-02010264e9c8"));
+ classIds.prepend(QVariant::fromValue(uuid));
+ QCOMPARE(classIds.count(), 2);
+ QCOMPARE(classIds.at(0).value<QBluetoothUuid>(), uuid);
+
+ info.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classIds);
+ QList<QBluetoothUuid> svclids = info.serviceClassUuids();
+ QCOMPARE(svclids.count(), 2);
+ QCOMPARE(svclids.at(0), uuid);
+ QCOMPARE(svclids.at(1), QBluetoothUuid(QBluetoothUuid::SerialPort));
+}
+
QTEST_MAIN(tst_QBluetoothServiceInfo)
#include "tst_qbluetoothserviceinfo.moc"
diff --git a/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp b/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp
index 87e6a41d..6fac6571 100644
--- a/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp
+++ b/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp
@@ -163,14 +163,14 @@ void tst_QNearFieldTagType2::staticMemoryModel()
QCOMPARE(readBlock, QByteArray(4, 0x55) + initialBlock.mid(4));
// Write 0xaa
- id = target->writeBlock(i, QByteArray(4, 0xaa));
+ id = target->writeBlock(i, QByteArray(4, char(0xaa)));
QVERIFY(target->waitForRequestCompleted(id));
QVERIFY(target->requestResponse(id).toBool());
id = target->readBlock(i);
QVERIFY(target->waitForRequestCompleted(id));
readBlock = target->requestResponse(id).toByteArray();
- QCOMPARE(readBlock, QByteArray(4, 0xaa) + initialBlock.mid(4));
+ QCOMPARE(readBlock, QByteArray(4, char(0xaa)) + initialBlock.mid(4));
}
}
}
@@ -240,14 +240,14 @@ void tst_QNearFieldTagType2::dynamicMemoryModel()
QCOMPARE(readBlock, QByteArray(4, 0x55) + initialBlock.mid(4));
// Write 0xaa
- id = target->writeBlock(i, QByteArray(4, 0xaa));
+ id = target->writeBlock(i, QByteArray(4, char(0xaa)));
QVERIFY(target->waitForRequestCompleted(id));
QVERIFY(target->requestResponse(id).toBool());
id = target->readBlock(i);
QVERIFY(target->waitForRequestCompleted(id));
readBlock = target->requestResponse(id).toByteArray();
- QCOMPARE(readBlock, QByteArray(4, 0xaa) + initialBlock.mid(4));
+ QCOMPARE(readBlock, QByteArray(4, char(0xaa)) + initialBlock.mid(4));
}
// change to sector 0
diff --git a/tests/btclient/btclient.c b/tests/btclient/btclient.c
index 17c220b0..e6f6f0b0 100644
--- a/tests/btclient/btclient.c
+++ b/tests/btclient/btclient.c
@@ -118,11 +118,11 @@ struct fdlist {
struct fdlist *head = 0;
-void removefd(struct fdlist *fdl, int fd){
+void removefd(struct fdlist *fdl, int fd) {
struct fdlist *prev = fdl;
while(fdl && fdl->fd != fd) {
prev = fdl;
- fdl = fdl->next;
+ fdl = fdl->next;
}
assert(fdl);
@@ -482,7 +482,7 @@ void registerService()
// change path to use any
strcpy(rindex(path, '/'), "/any");
- printf("Using path: %s\n", path);
+ printf("Using path: %s\n", path);
dbus_message_unref(msg);
@@ -538,9 +538,9 @@ void registerService()
int main(int argc, char **argv)
{
- int socket;
+ int socket;
#define MAX_POLL 256
- struct pollfd fds[MAX_POLL];
+ struct pollfd fds[MAX_POLL];
UNUSED(argc);
UNUSED(argv);
@@ -558,7 +558,7 @@ int main(int argc, char **argv)
while(1){
int n = mkpoll(head, fds, MAX_POLL);
- if(poll(fds, n, -1)){
+ if (poll(fds, n, -1)) {
struct fdlist *fdl = head;
int i;
diff --git a/tests/bttestui/Button.qml b/tests/bttestui/Button.qml
new file mode 100644
index 00000000..25cffb43
--- /dev/null
+++ b/tests/bttestui/Button.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle
+{
+ id: button
+ signal clicked()
+ property string buttonText
+ width: powerOn.width + 10
+ height: powerOn.height + 10
+ border.color: "black"
+ border.width: 2
+ radius: 4
+
+
+ Text {
+ id: powerOn
+ text: buttonText
+ font.pointSize: 16
+ anchors.centerIn: parent
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: button.clicked()
+ }
+}
diff --git a/tests/bttestui/README b/tests/bttestui/README
new file mode 100644
index 00000000..e76ea90e
--- /dev/null
+++ b/tests/bttestui/README
@@ -0,0 +1,21 @@
+This application is a graphical test application for Bluetooth.
+It is able to invoke close to all API features offered by the QtBluetooth API.
+It includes features like:
+
+1.) Turning Bluetooth on/off
+2.) Pairing with remote devices
+3.) Discovery of services and devices
+4.) Connecting to a remote SPP profile using RFCOMM
+5.) Start of a SPP Bluetooth server
+
+Some features require interaction with remote devices. In particular this involves
+pairing and the direct connecting to remote SPP servers. The remote test device address
+is hardcoded via BTCHAT_DEVICE_ADDR.
+
+Also, the test application reuses the service uuid employed by the btchat example
+(see examples/bluetooth/btchat). It can either directly connect to the remote
+btchat app server or create its own btchat server.
+
+Note that the application is purposely very liberal with regards to the amount of its
+debug output. This is done to be able to confirm proper working of the tested
+APIs.
diff --git a/tests/bttestui/btlocaldevice.cpp b/tests/bttestui/btlocaldevice.cpp
new file mode 100644
index 00000000..b73a2a73
--- /dev/null
+++ b/tests/bttestui/btlocaldevice.cpp
@@ -0,0 +1,710 @@
+/****************************************************************************
+**
+** 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 "btlocaldevice.h"
+#include <QDebug>
+#include <QTimer>
+#include <QtBluetooth/QBluetoothServiceInfo>
+
+#define BTCHAT_DEVICE_ADDR "00:15:83:38:17:C3"
+
+//same uuid as examples/bluetooth/btchat
+#define TEST_SERVICE_UUID "e8e10f95-1a70-4b27-9ccf-02010264e9c8"
+
+BtLocalDevice::BtLocalDevice(QObject *parent) :
+ QObject(parent)
+{
+ localDevice = new QBluetoothLocalDevice(this);
+ connect(localDevice, SIGNAL(error(QBluetoothLocalDevice::Error)),
+ this, SIGNAL(error(QBluetoothLocalDevice::Error)));
+ connect(localDevice, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)),
+ this, SIGNAL(hostModeStateChanged()));
+ connect(localDevice, SIGNAL(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::Pairing)),
+ this, SLOT(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::Pairing)));
+ connect(localDevice, SIGNAL(deviceConnected(QBluetoothAddress)),
+ this, SLOT(connected(QBluetoothAddress)));
+ connect(localDevice, SIGNAL(deviceDisconnected(QBluetoothAddress)),
+ this, SLOT(disconnected(QBluetoothAddress)));
+ connect(localDevice, SIGNAL(pairingDisplayConfirmation(QBluetoothAddress,QString)),
+ this, SLOT(pairingDisplayConfirmation(QBluetoothAddress,QString)));
+
+ if (localDevice->isValid()) {
+ deviceAgent = new QBluetoothDeviceDiscoveryAgent(this);
+ connect(deviceAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
+ this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
+ connect(deviceAgent, SIGNAL(finished()),
+ this, SLOT(discoveryFinished()));
+ connect(deviceAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)),
+ this, SLOT(discoveryError(QBluetoothDeviceDiscoveryAgent::Error)));
+ connect(deviceAgent, SIGNAL(canceled()),
+ this, SLOT(discoveryCanceled()));
+
+ serviceAgent = new QBluetoothServiceDiscoveryAgent(this);
+ connect(serviceAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)),
+ this, SLOT(serviceDiscovered(QBluetoothServiceInfo)));
+ connect(serviceAgent, SIGNAL(finished()),
+ this, SLOT(serviceDiscoveryFinished()));
+ connect(serviceAgent, SIGNAL(canceled()),
+ this, SLOT(serviceDiscoveryCanceled()));
+ connect(serviceAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)),
+ this, SLOT(serviceDiscoveryError(QBluetoothServiceDiscoveryAgent::Error)));
+
+ socket = new QBluetoothSocket(this);
+ connect(socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)),
+ this, SLOT(socketStateChanged(QBluetoothSocket::SocketState)));
+ connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)),
+ this, SLOT(socketError(QBluetoothSocket::SocketError)));
+ connect(socket, SIGNAL(connected()), this, SLOT(socketConnected()));
+ connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
+ connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));
+
+ server = new QBluetoothServer(QBluetoothServiceInfo::RfcommProtocol, this);
+ server->setSecurityFlags(QBluetooth::NoSecurity);
+ connect(server, SIGNAL(newConnection()), this, SLOT(serverNewConnection()));
+ connect(server, SIGNAL(error(QBluetoothServer::Error)),
+ this, SLOT(serverError(QBluetoothServer::Error)));
+ } else {
+ deviceAgent = 0;
+ serviceAgent = 0;
+ }
+}
+
+BtLocalDevice::~BtLocalDevice()
+{
+ while (!serverSockets.isEmpty())
+ {
+ QBluetoothSocket* s = serverSockets.takeFirst();
+ s->abort();
+ s->deleteLater();
+ }
+}
+
+QString BtLocalDevice::hostMode() const
+{
+ switch (localDevice->hostMode()) {
+ case QBluetoothLocalDevice::HostDiscoverable:
+ return QStringLiteral("HostMode: Discoverable");
+ case QBluetoothLocalDevice::HostConnectable:
+ return QStringLiteral("HostMode: Connectable");
+ case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry:
+ return QStringLiteral("HostMode: DiscoverableLimit");
+ case QBluetoothLocalDevice::HostPoweredOff:
+ return QStringLiteral("HostMode: Powered Off");
+ }
+
+ return QStringLiteral("HostMode: <None>");
+}
+
+void BtLocalDevice::setHostMode(int newMode)
+{
+ localDevice->setHostMode((QBluetoothLocalDevice::HostMode)newMode);
+}
+
+void BtLocalDevice::requestPairingUpdate(bool isPairing)
+{
+ QBluetoothAddress baddr(BTCHAT_DEVICE_ADDR);
+ if (baddr.isNull())
+ return;
+
+ if (isPairing)
+ localDevice->requestPairing(baddr, QBluetoothLocalDevice::Paired);
+ else
+ localDevice->requestPairing(baddr, QBluetoothLocalDevice::Unpaired);
+
+ for (int i = 0; i < foundTestServers.count(); i++) {
+ if (isPairing)
+ localDevice->requestPairing(foundTestServers.at(i).device().address(),
+ QBluetoothLocalDevice::Paired);
+ else
+ localDevice->requestPairing(foundTestServers.at(i).device().address(),
+ QBluetoothLocalDevice::Unpaired);
+ }
+}
+
+void BtLocalDevice::pairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing)
+{
+ qDebug() << "(Un)Pairing finished" << address.toString() << pairing;
+}
+
+void BtLocalDevice::connected(const QBluetoothAddress &addr)
+{
+ qDebug() << "Newly connected device" << addr.toString();
+}
+
+void BtLocalDevice::disconnected(const QBluetoothAddress &addr)
+{
+ qDebug() << "Newly disconnected device" << addr.toString();
+}
+
+void BtLocalDevice::pairingDisplayConfirmation(const QBluetoothAddress &address, const QString &pin)
+{
+ Q_UNUSED(pin);
+ Q_UNUSED(address);
+ QTimer::singleShot(3000, this, SLOT(confirmPairing()));
+}
+
+void BtLocalDevice::confirmPairing()
+{
+ static bool confirm = false;
+ confirm = !confirm; //toggle
+ qDebug() << "######" << "Sending pairing confirmation: " << confirm;
+ localDevice->pairingConfirmation(confirm);
+}
+
+void BtLocalDevice::deviceDiscovered(const QBluetoothDeviceInfo &info)
+{
+ QString services;
+ if (info.serviceClasses() & QBluetoothDeviceInfo::PositioningService)
+ services += "Position|";
+ if (info.serviceClasses() & QBluetoothDeviceInfo::NetworkingService)
+ services += "Network|";
+ if (info.serviceClasses() & QBluetoothDeviceInfo::RenderingService)
+ services += "Rendering|";
+ if (info.serviceClasses() & QBluetoothDeviceInfo::CapturingService)
+ services += "Capturing|";
+ if (info.serviceClasses() & QBluetoothDeviceInfo::ObjectTransferService)
+ services += "ObjectTra|";
+ if (info.serviceClasses() & QBluetoothDeviceInfo::AudioService)
+ services += "Audio|";
+ if (info.serviceClasses() & QBluetoothDeviceInfo::TelephonyService)
+ services += "Telephony|";
+ if (info.serviceClasses() & QBluetoothDeviceInfo::InformationService)
+ services += "Information|";
+
+ services.truncate(services.length()-1); //cut last '/'
+
+ qDebug() << "Found new device: " << info.name() << info.isValid() << info.address().toString()
+ << info.rssi() << info.majorDeviceClass()
+ << info.minorDeviceClass() << services;
+
+}
+
+void BtLocalDevice::discoveryFinished()
+{
+ qDebug() << "###### Device Discovery Finished";
+}
+
+void BtLocalDevice::discoveryCanceled()
+{
+ qDebug() << "###### Device Discovery Canceled";
+}
+
+void BtLocalDevice::discoveryError(QBluetoothDeviceDiscoveryAgent::Error error)
+{
+ QBluetoothDeviceDiscoveryAgent *client = qobject_cast<QBluetoothDeviceDiscoveryAgent *>(sender());
+ if (!client)
+ return;
+ qDebug() << "###### Device Discovery Error:" << error << (client ? client->errorString() : QString());
+}
+
+void BtLocalDevice::startDiscovery()
+{
+ if (deviceAgent) {
+ qDebug() << "###### Starting device discovery process";
+ deviceAgent->start();
+ }
+}
+
+void BtLocalDevice::stopDiscovery()
+{
+ if (deviceAgent) {
+ qDebug() << "Stopping device discovery process";
+ deviceAgent->stop();
+ }
+}
+
+void BtLocalDevice::startServiceDiscovery(bool isMinimalDiscovery)
+{
+ if (serviceAgent) {
+ qDebug() << "###### Starting service discovery process";
+ serviceAgent->start(isMinimalDiscovery
+ ? QBluetoothServiceDiscoveryAgent::MinimalDiscovery
+ : QBluetoothServiceDiscoveryAgent::FullDiscovery);
+ }
+}
+
+void BtLocalDevice::stopServiceDiscovery()
+{
+ if (serviceAgent) {
+ qDebug() << "Stopping service discovery process";
+ serviceAgent->stop();
+ }
+}
+
+void BtLocalDevice::serviceDiscovered(const QBluetoothServiceInfo &info)
+{
+
+ qDebug() << "$$ Found new service" << info.device().address().toString()
+ << info.serviceUuid() << info.serviceName() << info.serviceDescription();
+
+ if (info.serviceUuid() == QBluetoothUuid(QString(TEST_SERVICE_UUID))
+ || info.serviceClassUuids().contains(QBluetoothUuid(QString(TEST_SERVICE_UUID))))
+ {
+ //This is here to detect the test server for SPP testing later on
+ bool alreadyKnown = false;
+ foreach (const QBluetoothServiceInfo& found, foundTestServers) {
+ if (found.device().address() == info.device().address()) {
+ alreadyKnown = true;
+ break;
+ }
+ }
+
+ if (!alreadyKnown) {
+ foundTestServers.append(info);
+ qDebug() << "@@@@@@@@ Adding:" << info.device().address().toString();
+ }
+ }
+}
+
+void BtLocalDevice::serviceDiscoveryFinished()
+{
+ qDebug() << "###### Service Discovery Finished";
+}
+
+void BtLocalDevice::serviceDiscoveryCanceled()
+{
+ qDebug() << "###### Service Discovery Canceled";
+}
+
+void BtLocalDevice::serviceDiscoveryError(QBluetoothServiceDiscoveryAgent::Error error)
+{
+ QBluetoothServiceDiscoveryAgent *client = qobject_cast<QBluetoothServiceDiscoveryAgent *>(sender());
+ if (!client)
+ return;
+ qDebug() << "###### Service Discovery Error:" << error << (client ? client->errorString() : QString());
+}
+
+void BtLocalDevice::dumpServiceDiscovery()
+{
+ if (serviceAgent) {
+ qDebug() << "Service Discovery active:" << serviceAgent->isActive();
+ qDebug() << "Error:" << serviceAgent->error() << serviceAgent->errorString();
+ QList<QBluetoothServiceInfo> list = serviceAgent->discoveredServices();
+ qDebug() << "Discovered Services:" << list.count();
+
+ foreach (const QBluetoothServiceInfo &i, list) {
+ qDebug() << i.device().address().toString() << i.device().name() << i.serviceName();
+ }
+
+ qDebug() << "###### TestServer offered by:";
+ foreach (const QBluetoothServiceInfo& found, foundTestServers) {
+ qDebug() << found.device().name() << found.device().address().toString();
+ }
+ }
+}
+
+void BtLocalDevice::connectToService()
+{
+ if (socket)
+ socket->connectToService(QBluetoothAddress(BTCHAT_DEVICE_ADDR),QBluetoothUuid(QString(TEST_SERVICE_UUID)));
+}
+
+void BtLocalDevice::connectToServiceViaSearch()
+{
+ if (socket) {
+ qDebug() << "###### Connecting to service socket";
+ if (!foundTestServers.isEmpty()) {
+ QBluetoothServiceInfo info = foundTestServers.at(0);
+ socket->connectToService(info.device().address(), QBluetoothUuid(QString(TEST_SERVICE_UUID)));
+ } else {
+ qWarning() << "Perform search for test service before triggering this function";
+ }
+ }
+}
+
+void BtLocalDevice::disconnectToService()
+{
+ if (socket) {
+ qDebug() << "###### Disconnecting socket";
+ socket->disconnectFromService();
+ }
+}
+
+void BtLocalDevice::closeSocket()
+{
+ if (socket) {
+ qDebug() << "###### Closing socket";
+ socket->close();
+ }
+
+ if (!serverSockets.isEmpty()) {
+ qDebug() << "###### Closing server sockets";
+ foreach (QBluetoothSocket *s, serverSockets)
+ s->close();
+ }
+}
+
+void BtLocalDevice::abortSocket()
+{
+ if (socket) {
+ qDebug() << "###### Disconnecting socket";
+ socket->abort();
+ }
+}
+
+void BtLocalDevice::socketConnected()
+{
+ qDebug() << "###### Socket connected";
+}
+
+void BtLocalDevice::socketDisconnected()
+{
+ qDebug() << "###### Socket disconnected";
+}
+
+void BtLocalDevice::socketError(QBluetoothSocket::SocketError error)
+{
+ QBluetoothSocket *client = qobject_cast<QBluetoothSocket *>(sender());
+
+ qDebug() << "###### Socket error" << error << (client ? client->errorString() : QString());
+}
+
+void BtLocalDevice::socketStateChanged(QBluetoothSocket::SocketState state)
+{
+ qDebug() << "###### Socket state" << state;
+ emit socketStateUpdate((int) state);
+}
+
+void BtLocalDevice::dumpSocketInformation()
+{
+ if (socket) {
+ qDebug() << "*******************************";
+ qDebug() << "Local info (addr, name, port):" << socket->localAddress().toString()
+ << socket->localName() << socket->localPort();
+ qDebug() << "Peer Info (adr, name, port):" << socket->peerAddress().toString()
+ << socket->peerName() << socket->peerPort();
+ qDebug() << "socket type:" << socket->socketType();
+ qDebug() << "socket state:" << socket->state();
+ QString tmp;
+ switch (socket->error()) {
+ case QBluetoothSocket::NoSocketError: tmp += "NoSocketError"; break;
+ case QBluetoothSocket::UnknownSocketError: tmp += "UnknownSocketError"; break;
+ case QBluetoothSocket::HostNotFoundError: tmp += "HostNotFoundError"; break;
+ case QBluetoothSocket::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
+ case QBluetoothSocket::NetworkError: tmp += "NetworkError"; break;
+ //case QBluetoothSocket::OperationError: tmp+= "OperationError"; break;
+ case QBluetoothSocket::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
+ default: tmp+= "Undefined"; break;
+ }
+
+ qDebug() << "socket error:" << tmp << socket->errorString();
+ } else {
+ qDebug() << "No valid socket existing";
+ }
+}
+
+void BtLocalDevice::writeData()
+{
+ const char * testData = "ABCABC\n";
+ if (socket && socket->state() == QBluetoothSocket::ConnectedState) {
+ socket->write(testData);
+ }
+ foreach (QBluetoothSocket* client, serverSockets) {
+ client->write(testData);
+ }
+}
+
+void BtLocalDevice::readData()
+{
+ if (socket) {
+ while (socket->canReadLine()) {
+ QByteArray line = socket->readLine().trimmed();
+ qDebug() << ">>>>" << QString::fromUtf8(line.constData(), line.length());
+ }
+ }
+}
+
+void BtLocalDevice::serverError(QBluetoothServer::Error error)
+{
+ qDebug() << "###### Server socket error" << error;
+}
+
+void BtLocalDevice::serverListenPort()
+{
+ if (server && localDevice) {
+ if (server->isListening() || serviceInfo.isRegistered()) {
+ qDebug() << "###### Already listening" << serviceInfo.isRegistered();
+ return;
+ }
+ qDebug() << "###### Start listening via port";
+ bool ret = server->listen(localDevice->address());
+ qDebug() << "###### Listening(Expecting TRUE):" << ret;
+
+ if (!ret)
+ return;
+
+ QBluetoothServiceInfo::Sequence classId;
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,
+ classId);
+
+ classId.prepend(QVariant::fromValue(QBluetoothUuid(QString(TEST_SERVICE_UUID))));
+ serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
+
+ // Service name, description and provider
+ serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, tr("Bt Chat Server"));
+ serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceDescription,
+ tr("Example bluetooth chat server"));
+ serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceProvider, tr("qt-project.org"));
+
+ // Service UUID set
+ serviceInfo.setServiceUuid(QBluetoothUuid(QString(TEST_SERVICE_UUID)));
+
+
+ // Service Discoverability
+ serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList,
+ QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup));
+
+ // Protocol descriptor list
+ QBluetoothServiceInfo::Sequence protocolDescriptorList;
+ QBluetoothServiceInfo::Sequence protocol;
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocolDescriptorList.append(QVariant::fromValue(protocol));
+ protocol.clear();
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ << QVariant::fromValue(quint8(server->serverPort()));
+ protocolDescriptorList.append(QVariant::fromValue(protocol));
+ serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList,
+ protocolDescriptorList);
+
+ //Register service
+ qDebug() << "###### Registering service on" << localDevice->address().toString();
+ bool result = serviceInfo.registerService(localDevice->address());
+ if (!result) {
+ server->close();
+ qDebug() << "###### Reverting registration due to SDP failure.";
+ }
+ }
+
+}
+
+void BtLocalDevice::serverListenUuid()
+{
+ if (server) {
+ if (server->isListening() || serviceInfo.isRegistered()) {
+ qDebug() << "###### Already listening" << serviceInfo.isRegistered();
+ return;
+ }
+ qDebug() << "###### Start listening via UUID";
+ serviceInfo = server->listen(QBluetoothUuid(QString(TEST_SERVICE_UUID)), tr("Bt Chat Server"));
+ qDebug() << "###### Listening(Expecting TRUE, TRUE):" << serviceInfo.isRegistered() << serviceInfo.isValid();
+ }
+}
+
+void BtLocalDevice::serverClose()
+{
+ if (server) {
+ qDebug() << "###### Closing Server socket";
+ if (serviceInfo.isRegistered())
+ serviceInfo.unregisterService();
+ server->close();
+ }
+}
+
+void BtLocalDevice::serverNewConnection()
+{
+ qDebug() << "###### New incoming server connection, pending:" << server->hasPendingConnections();
+ if (!server->hasPendingConnections()) {
+ qDebug() << "FAIL: expected pending server connection";
+ return;
+ }
+ QBluetoothSocket *client = server->nextPendingConnection();
+ if (!client) {
+ qDebug() << "FAIL: Cannot obtain pending server connection";
+ return;
+ }
+
+ client->setParent(this);
+ connect(client, SIGNAL(disconnected()), this, SLOT(clientSocketDisconnected()));
+ connect(client, SIGNAL(readyRead()), this, SLOT(clientSocketReadyRead()));
+ connect(client, SIGNAL(stateChanged(QBluetoothSocket::SocketState)),
+ this, SLOT(socketStateChanged(QBluetoothSocket::SocketState)));
+ connect(client, SIGNAL(error(QBluetoothSocket::SocketError)),
+ this, SLOT(socketError(QBluetoothSocket::SocketError)));
+ connect(client, SIGNAL(connected()), this, SLOT(socketConnected()));
+ serverSockets.append(client);
+}
+
+void BtLocalDevice::clientSocketDisconnected()
+{
+ QBluetoothSocket *client = qobject_cast<QBluetoothSocket *>(sender());
+ if (!client)
+ return;
+
+ qDebug() << "######" << "Removing server socket connection";
+
+ serverSockets.removeOne(client);
+ client->deleteLater();
+}
+
+
+void BtLocalDevice::clientSocketReadyRead()
+{
+ QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender());
+ if (!socket)
+ return;
+
+ while (socket->canReadLine()) {
+ QByteArray line = socket->readLine().trimmed();
+ qDebug() << ">>(" << socket->peerName() << ")>>"
+ << QString::fromUtf8(line.constData(), line.length());
+ }
+}
+
+
+void BtLocalDevice::dumpServerInformation()
+{
+ static QBluetooth::SecurityFlags secFlag = QBluetooth::Authentication;
+ if (server) {
+ qDebug() << "*******************************";
+ qDebug() << "server port:" <<server->serverPort()
+ << "type:" << server->serverType()
+ << "address:" << server->serverAddress().toString();
+ qDebug() << "error:" << server->error();
+ qDebug() << "listening:" << server->isListening()
+ << "hasPending:" << server->hasPendingConnections()
+ << "maxPending:" << server->maxPendingConnections();
+ qDebug() << "security:" << server->securityFlags() << "Togling security flag";
+ if (secFlag == QBluetooth::Authentication)
+ secFlag = QBluetooth::Encryption;
+ else
+ secFlag = QBluetooth::Authentication;
+
+ //server->setSecurityFlags(secFlag);
+
+ foreach (const QBluetoothSocket *client, serverSockets) {
+ qDebug() << "##" << client->localAddress().toString()
+ << client->localName() << client->localPort();
+ qDebug() << "##" << client->peerAddress().toString()
+ << client->peerName() << client->peerPort();
+ qDebug() << client->socketType() << client->state();
+ QString tmp;
+ switch (client->error()) {
+ case QBluetoothSocket::NoSocketError: tmp += "NoSocketError"; break;
+ case QBluetoothSocket::UnknownSocketError: tmp += "UnknownSocketError"; break;
+ case QBluetoothSocket::HostNotFoundError: tmp += "HostNotFoundError"; break;
+ case QBluetoothSocket::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
+ case QBluetoothSocket::NetworkError: tmp += "NetworkError"; break;
+ case QBluetoothSocket::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
+ //case QBluetoothSocket::OperationError: tmp+= "OperationError"; break;
+ default: tmp += QString::number((int)client->error()); break;
+ }
+
+ qDebug() << "socket error:" << tmp << client->errorString();
+ }
+ }
+}
+
+void BtLocalDevice::dumpInformation()
+{
+ qDebug() << "###### default local device";
+ dumpLocalDevice(localDevice);
+ QList<QBluetoothHostInfo> list = QBluetoothLocalDevice::allDevices();
+ qDebug() << "Found local devices: " << list.count();
+ foreach (const QBluetoothHostInfo &info, list) {
+ qDebug() << " " << info.address().toString() << " " <<info.name();
+ }
+
+ QBluetoothAddress address(QStringLiteral("11:22:33:44:55:66"));
+ QBluetoothLocalDevice temp(address);
+ qDebug() << "###### 11:22:33:44:55:66 address valid:" << !address.isNull();
+ dumpLocalDevice(&temp);
+
+ QBluetoothAddress address2;
+ QBluetoothLocalDevice temp2(address2);
+ qDebug() << "###### 00:00:00:00:00:00 address valid:" << !address2.isNull();
+ dumpLocalDevice(&temp2);
+
+ const QBluetoothAddress BB(BTCHAT_DEVICE_ADDR);
+ qDebug() << "###### Bonding state with" << QString(BTCHAT_DEVICE_ADDR) << ":" << localDevice->pairingStatus(BB);
+ qDebug() << "###### Bonding state with" << address2.toString() << ": " << localDevice->pairingStatus(address2);
+ qDebug() << "###### Bonding state with" << address.toString() << ": " << localDevice->pairingStatus(address);
+
+ qDebug() << "###### Connected Devices";
+ foreach (const QBluetoothAddress &addr, localDevice->connectedDevices())
+ qDebug() << " " << addr.toString();
+
+ qDebug() << "###### Discovered Devices";
+ if (deviceAgent)
+ foreach (const QBluetoothDeviceInfo &info, deviceAgent->discoveredDevices())
+ deviceDiscovered(info);
+
+ QBluetoothDeviceDiscoveryAgent invalidAgent(QBluetoothAddress("11:22:33:44:55:66"));
+ invalidAgent.start();
+ qDebug() << "######" << "Testing device discovery agent constructor with invalid address";
+ qDebug() << "######" << (invalidAgent.error() == QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError)
+ << "(Expected: true)";
+ QBluetoothDeviceDiscoveryAgent validAgent(localDevice->address());
+ validAgent.start();
+ qDebug() << "######" << (validAgent.error() == QBluetoothDeviceDiscoveryAgent::NoError) << "(Expected: true)";
+
+ QBluetoothServiceDiscoveryAgent invalidSAgent(QBluetoothAddress("11:22:33:44:55:66"));
+ invalidSAgent.start();
+ qDebug() << "######" << "Testing service discovery agent constructor with invalid address";
+ qDebug() << "######" << (invalidSAgent.error() == QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError)
+ << "(Expected: true)";
+ QBluetoothServiceDiscoveryAgent validSAgent(localDevice->address());
+ validSAgent.start();
+ qDebug() << "######" << (validSAgent.error() == QBluetoothServiceDiscoveryAgent::NoError) << "(Expected: true)";
+}
+
+void BtLocalDevice::powerOn()
+{
+ qDebug() << "Powering on";
+ localDevice->powerOn();
+}
+
+void BtLocalDevice::reset()
+{
+ emit error((QBluetoothLocalDevice::Error)1000);
+ if (serviceAgent) {
+ serviceAgent->clear();
+ }
+ foundTestServers.clear();
+}
+
+void BtLocalDevice::dumpLocalDevice(QBluetoothLocalDevice *dev)
+{
+ qDebug() << " Valid: " << dev->isValid();
+ qDebug() << " Name" << dev->name();
+ qDebug() << " Address" << dev->address().toString();
+ qDebug() << " HostMode" << dev->hostMode();
+}
diff --git a/tests/bttestui/btlocaldevice.h b/tests/bttestui/btlocaldevice.h
new file mode 100644
index 00000000..759599b7
--- /dev/null
+++ b/tests/bttestui/btlocaldevice.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** 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 BTLOCALDEVICE_H
+#define BTLOCALDEVICE_H
+
+#include <QtCore/QObject>
+#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
+#include <QtBluetooth/QBluetoothLocalDevice>
+#include <QtBluetooth/QBluetoothServer>
+#include <QtBluetooth/QBluetoothServiceDiscoveryAgent>
+#include <QtBluetooth/QBluetoothSocket>
+
+class BtLocalDevice : public QObject
+{
+ Q_OBJECT
+public:
+ explicit BtLocalDevice(QObject *parent = 0);
+ ~BtLocalDevice();
+ Q_PROPERTY(QString hostMode READ hostMode NOTIFY hostModeStateChanged)
+
+ QString hostMode() const;
+
+signals:
+ void error(QBluetoothLocalDevice::Error error);
+ void hostModeStateChanged();
+ void socketStateUpdate(int foobar);
+
+public slots:
+ //QBluetoothLocalDevice
+ void dumpInformation();
+ void powerOn();
+ void reset();
+ void setHostMode(int newMode);
+ void requestPairingUpdate(bool isPairing);
+ void pairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
+ void connected(const QBluetoothAddress &addr);
+ void disconnected(const QBluetoothAddress &addr);
+ void pairingDisplayConfirmation(const QBluetoothAddress &address, const QString &pin);
+ void confirmPairing();
+
+ //QBluetoothDeviceDiscoveryAgent
+ void deviceDiscovered(const QBluetoothDeviceInfo &info);
+ void discoveryFinished();
+ void discoveryCanceled();
+ void discoveryError(QBluetoothDeviceDiscoveryAgent::Error error);
+ void startDiscovery();
+ void stopDiscovery();
+
+ //QBluetoothServiceDiscoveryAgent
+ void startServiceDiscovery(bool isMinimalDiscovery);
+ void stopServiceDiscovery();
+ void serviceDiscovered(const QBluetoothServiceInfo &info);
+ void serviceDiscoveryFinished();
+ void serviceDiscoveryCanceled();
+ void serviceDiscoveryError(QBluetoothServiceDiscoveryAgent::Error error);
+ void dumpServiceDiscovery();
+
+ //QBluetoothSocket
+ void connectToService();
+ void connectToServiceViaSearch();
+ void disconnectToService();
+ void closeSocket();
+ void abortSocket();
+ void socketConnected();
+ void socketDisconnected();
+ void socketError(QBluetoothSocket::SocketError error);
+ void socketStateChanged(QBluetoothSocket::SocketState);
+ void dumpSocketInformation();
+ void writeData();
+ void readData();
+
+ //QBluetoothServer
+ void serverError(QBluetoothServer::Error error);
+ void serverListenPort();
+ void serverListenUuid();
+ void serverClose();
+ void serverNewConnection();
+ void clientSocketDisconnected();
+ void clientSocketReadyRead();
+ void dumpServerInformation();
+
+private:
+ void dumpLocalDevice(QBluetoothLocalDevice *dev);
+
+ QBluetoothLocalDevice *localDevice;
+ QBluetoothDeviceDiscoveryAgent *deviceAgent;
+ QBluetoothServiceDiscoveryAgent *serviceAgent;
+ QBluetoothSocket *socket;
+ QBluetoothServer *server;
+ QList<QBluetoothSocket *> serverSockets;
+ QBluetoothServiceInfo serviceInfo;
+
+ QList<QBluetoothServiceInfo> foundTestServers;
+};
+
+#endif // BTLOCALDEVICE_H
diff --git a/tests/bttestui/bttest.qrc b/tests/bttestui/bttest.qrc
new file mode 100644
index 00000000..bb3a7ad6
--- /dev/null
+++ b/tests/bttestui/bttest.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>Button.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/bttestui/bttestui.pro b/tests/bttestui/bttestui.pro
new file mode 100644
index 00000000..06248691
--- /dev/null
+++ b/tests/bttestui/bttestui.pro
@@ -0,0 +1,16 @@
+TARGET = bttestui
+TEMPLATE = app
+
+SOURCES += main.cpp \
+ btlocaldevice.cpp
+
+QT += quick bluetooth
+
+OTHER_FILES += main.qml \
+ Button.qml
+
+RESOURCES += \
+ bttest.qrc
+
+HEADERS += \
+ btlocaldevice.h
diff --git a/tests/bttestui/main.cpp b/tests/bttestui/main.cpp
new file mode 100644
index 00000000..964eec59
--- /dev/null
+++ b/tests/bttestui/main.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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 <QtGui/QGuiApplication>
+#include <QtQml/QQmlEngine>
+#include <QtQuick/QQuickView>
+#include <QtQml/qqml.h>
+
+#include <QtCore/QLoggingCategory>
+
+#include "btlocaldevice.h"
+
+int main(int argc, char *argv[])
+{
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
+ QGuiApplication app(argc, argv);
+ qmlRegisterType<BtLocalDevice>("Local", 5, 2, "BluetoothDevice");
+
+ QQuickView view;
+ view.setSource(QStringLiteral("qrc:///main.qml"));
+ view.setWidth(550);
+ view.setHeight(550);
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+
+ QObject::connect(view.engine(), SIGNAL(quit()), qApp, SLOT(quit()));
+ view.show();
+
+ return app.exec();
+}
diff --git a/tests/bttestui/main.qml b/tests/bttestui/main.qml
new file mode 100644
index 00000000..d53aa4e1
--- /dev/null
+++ b/tests/bttestui/main.qml
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import Local 5.2
+
+Rectangle {
+ width: 360
+ height: 360
+
+ BluetoothDevice {
+ id: device
+ function evaluateError(error)
+ {
+ switch (error) {
+ case 0: return "Last Error: NoError"
+ case 1: return "Last Error: Pairing Error"
+ case 100: return "Last Error: Unknown Error"
+ case 1000: return "Last Error: <None>"
+ }
+ }
+
+ function evaluateSocketState(s) {
+ switch (s) {
+ case 0: return "Socket: Unconnected";
+ case 1: return "Socket: HostLookup";
+ case 2: return "Socket: Connecting";
+ case 3: return "Socket: Connected";
+ case 4: return "Socket: Bound";
+ case 5: return "Socket: Listening";
+ case 6: return "Socket: Closing";
+ }
+ return "Socket: <None>";
+ }
+
+
+ onError: errorText.text = evaluateError(error)
+ onHostModeStateChanged: hostModeText.text = device.hostMode;
+ onSocketStateUpdate : socketStateText.text = evaluateSocketState(foobar);
+ }
+
+ Text {
+ id: errorText
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 3
+ text: "Last Error: <None>"
+ }
+ Text {
+ id: hostModeText
+ anchors.left: parent.left
+ anchors.bottom: socketStateText.top
+ anchors.bottomMargin: 3
+ text: device.hostMode
+ }
+ Text {
+ id: socketStateText
+ anchors.left: parent.left
+ anchors.bottom: errorText.top
+ anchors.bottomMargin: 3
+ text: device.evaluateSocketState(0)
+ }
+
+ Row {
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.margins: 4
+
+ spacing: 8
+ Column {
+ spacing: 8
+ Text{
+ width: connectBtn.width
+ horizontalAlignment: Text.AlignLeft
+ font.pointSize: 12
+ wrapMode: Text.WordWrap
+ text: "Device Management"
+ }
+ Button {
+
+ buttonText: "PowerOn"
+ onClicked: device.powerOn()
+ }
+ Button {
+ buttonText: "PowerOff"
+ onClicked: device.setHostMode(0)
+ }
+ Button {
+ id: connectBtn
+ buttonText: "Connectable"
+ onClicked: device.setHostMode(1)
+ }
+ Button {
+ buttonText: "Discover"
+ onClicked: device.setHostMode(2)
+ }
+ Button {
+ buttonText: "Pair"
+ onClicked: device.requestPairingUpdate(true)
+ }
+ Button {
+ buttonText: "Unpair"
+ onClicked: device.requestPairingUpdate(false)
+ }
+ }
+ Column {
+ spacing: 8
+ Text{
+ width: startFullSDiscBtn.width
+ horizontalAlignment: Text.AlignLeft
+ font.pointSize: 12
+ wrapMode: Text.WordWrap
+ text: "Device & Service Discovery"
+ }
+ Button {
+ buttonText: "StartDDisc"
+ onClicked: device.startDiscovery()
+ }
+ Button {
+ buttonText: "StopDDisc"
+ onClicked: device.stopDiscovery()
+ }
+ Button {
+ buttonText: "StartMinSDisc"
+ onClicked: device.startServiceDiscovery(true)
+ }
+ Button {
+ id: startFullSDiscBtn
+ buttonText: "StartFullSDisc"
+ onClicked: device.startServiceDiscovery(false)
+ }
+ Button {
+ buttonText: "StopSDisc"
+ onClicked: device.stopServiceDiscovery();
+ }
+ Button {
+ buttonText: "DumpSDisc"
+ onClicked: device.dumpServiceDiscovery();
+ }
+
+ }
+
+ Column {
+ spacing: 8
+ Text{
+ width: connectSearchBtn.width
+ horizontalAlignment: Text.AlignLeft
+ font.pointSize: 12
+ wrapMode: Text.WordWrap
+ text: "Client & Server Socket"
+ }
+ Button {
+ buttonText: "SocketDump"
+ onClicked: device.dumpSocketInformation()
+ }
+ Button {
+ buttonText: "CConnect"
+ onClicked: device.connectToService()
+ }
+ Button {
+ id: connectSearchBtn
+ buttonText: "ConnectSearch"
+ onClicked: device.connectToServiceViaSearch()
+ }
+ Button {
+ buttonText: "CDisconnect"
+ onClicked: device.disconnectToService()
+ }
+
+ Button {
+ buttonText: "CClose"
+ onClicked: device.closeSocket()
+ }
+
+ Button {
+ buttonText: "CAbort"
+ onClicked: device.abortSocket()
+ }
+ Button {
+ //Write to all open sockets ABCABC\n
+ buttonText: "CSWrite"
+ onClicked: device.writeData()
+ }
+ Button {
+ buttonText: "ServerDump"
+ onClicked: device.dumpServerInformation()
+ }
+ Button {
+ //Listen on server via port
+ buttonText: "SListenPort"
+ onClicked: device.serverListenPort()
+ }
+ Button {
+ //Listen on server via uuid
+ buttonText: "SListenUuid"
+ onClicked: device.serverListenUuid()
+ }
+ Button {
+ //Close Bluetooth server
+ buttonText: "SClose"
+ onClicked: device.serverClose()
+ }
+ }
+ Column {
+ spacing: 8
+ Text{
+ width: resetBtn.width
+ horizontalAlignment: Text.AlignLeft
+ font.pointSize: 12
+ wrapMode: Text.WordWrap
+ text: "Misc Controls"
+ }
+ Button {
+ buttonText: "Dump"
+ onClicked: device.dumpInformation()
+ }
+ Button {
+ id: resetBtn
+ buttonText: "Reset"
+ onClicked: device.reset()
+ }
+ }
+ }
+}
diff --git a/tests/tests.pro b/tests/tests.pro
index 9bf70104..f9e886ec 100644
--- a/tests/tests.pro
+++ b/tests/tests.pro
@@ -5,4 +5,6 @@ linux*:!linux-armcc:contains(bluez_enabled, yes):qtHaveModule(dbus) {
SUBDIRS += btclient
}
+qtHaveModule(bluetooth):qtHaveModule(quick): SUBDIRS += bttestui
+
qtHaveModule(nfc): SUBDIRS += nfctestserver