summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/android
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@digia.com>2014-02-10 15:37:17 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-13 09:47:27 +0100
commit173d16efb54ccc152f19afb9b1c2a87915fb414b (patch)
treef07ce85ba2cb973e3c08f3ed84252d92ee1c16de /src/bluetooth/android
parentdd75b1f776695006ca96fd43f995c3ba0549b968 (diff)
Port QtBluetooth to Android
This is a feature merge to dev targeting Qt 5.3. Known issues: -QTBUG-36754: QBluetoothServer::close() crashes -QTBUG-36763: QBluetothTransferManager port to Android not possible -QTBUG-36764: Improve QBluetoothLocalDevice::connectedDevices() -QTBUG-36810: Remove direct use of Android action strings The above issues and some other minor TODO's will be addressed until final release time. Task-number: QTBUG-33792 [ChangeLog][QtBluetooth][Android] QtBluetooth has been ported to Android. Change-Id: I31ba83e3b7d6aa68e7258b7e43235de7d1a6e68a Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com> Reviewed-by: Alex Blasche <alexander.blasche@digia.com>
Diffstat (limited to 'src/bluetooth/android')
-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
14 files changed, 1533 insertions, 0 deletions
diff --git a/src/bluetooth/android/android.pri b/src/bluetooth/android/android.pri
new file mode 100644
index 00000000..3c8a0380
--- /dev/null
+++ b/src/bluetooth/android/android.pri
@@ -0,0 +1,17 @@
+PRIVATE_HEADERS += \
+ android/inputstreamthread_p.h \
+ android/devicediscoverybroadcastreceiver_p.h \
+ android/servicediscoverybroadcastreceiver_p.h \
+ android/androidbroadcastreceiver_p.h \
+ android/localdevicebroadcastreceiver_p.h \
+ android/serveracceptancethread_p.h
+
+
+SOURCES += \
+ android/inputstreamthread.cpp \
+ android/devicediscoverybroadcastreceiver.cpp \
+ android/servicediscoverybroadcastreceiver.cpp \
+ android/jni_android.cpp \
+ android/androidbroadcastreceiver.cpp \
+ android/localdevicebroadcastreceiver.cpp \
+ android/serveracceptancethread.cpp
diff --git a/src/bluetooth/android/androidbroadcastreceiver.cpp b/src/bluetooth/android/androidbroadcastreceiver.cpp
new file mode 100644
index 00000000..affa7683
--- /dev/null
+++ b/src/bluetooth/android/androidbroadcastreceiver.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <android/log.h>
+#include "android/androidbroadcastreceiver_p.h"
+#include <QtCore/QLoggingCategory>
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtGui/QGuiApplication>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+
+AndroidBroadcastReceiver::AndroidBroadcastReceiver(QObject* parent)
+ : QObject(parent), valid(false)
+{
+ //get QtActivity
+ activityObject = QAndroidJniObject(QtAndroidPrivate::activity());
+
+ broadcastReceiverObject = QAndroidJniObject("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver");
+ if (!broadcastReceiverObject.isValid())
+ return;
+ broadcastReceiverObject.setField<jlong>("qtObject", reinterpret_cast<long>(this));
+
+ intentFilterObject = QAndroidJniObject("android/content/IntentFilter");
+ if (!intentFilterObject.isValid())
+ return;
+
+ valid = true;
+}
+
+AndroidBroadcastReceiver::~AndroidBroadcastReceiver()
+{
+ unregisterReceiver();
+}
+
+bool AndroidBroadcastReceiver::isValid() const
+{
+ return valid;
+}
+
+void AndroidBroadcastReceiver::unregisterReceiver()
+{
+ if (!valid)
+ return;
+
+ activityObject.callObjectMethod(
+ "unregisterReceiver",
+ "(Landroid/content/BroadcastReceiver;)V",
+ broadcastReceiverObject.object<jobject>());
+}
+
+void AndroidBroadcastReceiver::addAction(const QString &action)
+{
+ if (!valid)
+ return;
+
+ QAndroidJniObject actionString = QAndroidJniObject::fromString(action);
+ intentFilterObject.callMethod<void>("addAction", "(Ljava/lang/String;)V", actionString.object<jstring>());
+
+ activityObject.callObjectMethod(
+ "registerReceiver",
+ "(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;",
+ broadcastReceiverObject.object<jobject>(),
+ intentFilterObject.object<jobject>());
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/android/androidbroadcastreceiver_p.h b/src/bluetooth/android/androidbroadcastreceiver_p.h
new file mode 100644
index 00000000..baae6798
--- /dev/null
+++ b/src/bluetooth/android/androidbroadcastreceiver_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JNIBROADCASTRECEIVER_H
+#define JNIBROADCASTRECEIVER_H
+#include <jni.h>
+#include <QtCore/QObject>
+#include <android/log.h>
+#include <QtAndroidExtras/QAndroidJniObject>
+
+QT_BEGIN_NAMESPACE
+
+void QtBroadcastReceiver_jniOnReceive(JNIEnv *, jobject, jlong, jobject, jobject);
+
+class AndroidBroadcastReceiver: public QObject
+{
+ Q_OBJECT
+public:
+ AndroidBroadcastReceiver(QObject* parent = 0);
+ virtual ~AndroidBroadcastReceiver();
+
+ void addAction(const QString &filter);
+ bool isValid() const;
+
+protected:
+ friend void QtBroadcastReceiver_jniOnReceive(JNIEnv *, jobject, jlong, jobject, jobject);
+ virtual void onReceive(JNIEnv *env, jobject context, jobject intent) = 0;
+
+ void unregisterReceiver();
+
+ QAndroidJniObject activityObject;
+ QAndroidJniObject intentFilterObject;
+ QAndroidJniObject broadcastReceiverObject;
+ bool valid;
+};
+
+QT_END_NAMESPACE
+#endif // JNIBROADCASTRECEIVER_H
diff --git a/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp
new file mode 100644
index 00000000..16a6afe4
--- /dev/null
+++ b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "android/devicediscoverybroadcastreceiver_p.h"
+#include <QtCore/QLoggingCategory>
+#include <QtBluetooth/QBluetoothAddress>
+#include <QtBluetooth/QBluetoothDeviceInfo>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+DeviceDiscoveryBroadcastReceiver::DeviceDiscoveryBroadcastReceiver(QObject* parent): AndroidBroadcastReceiver(parent)
+{
+ addAction(QStringLiteral("android.bluetooth.device.action.FOUND"));
+ addAction(QStringLiteral("android.bluetooth.adapter.action.DISCOVERY_STARTED"));
+ addAction(QStringLiteral("android.bluetooth.adapter.action.DISCOVERY_FINISHED"));
+}
+
+void DeviceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(env);
+
+ QAndroidJniObject intentObject(intent);
+ const QString action = intentObject.callObjectMethod("getAction", "()Ljava/lang/String;").toString();
+
+ qCDebug(QT_BT_ANDROID) << "DeviceDiscoveryBroadcastReceiver::onReceive() - event:" << action;
+
+ if (action == QStringLiteral("android.bluetooth.adapter.action.DISCOVERY_FINISHED") ) {
+ emit finished();
+ } else if (action == QStringLiteral("android.bluetooth.adapter.action.DISCOVERY_STARTED") ) {
+
+ } else if (action == QStringLiteral("android.bluetooth.device.action.FOUND")) {
+ //get BluetoothDevice
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.DEVICE"));
+ QAndroidJniObject bluetoothDevice =
+ intentObject.callObjectMethod("getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+
+ if (!bluetoothDevice.isValid())
+ return;
+
+ const QString deviceName = bluetoothDevice.callObjectMethod<jstring>("getName").toString();
+ const QBluetoothAddress deviceAddress(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.RSSI"));
+ int rssi = intentObject.callMethod<jshort>("getShortExtra",
+ "(Ljava/lang/String;S)S",
+ keyExtra.object<jstring>(),
+ 0);
+ QAndroidJniObject bluetoothClass = bluetoothDevice.callObjectMethod("getBluetoothClass",
+ "()Landroid/bluetooth/BluetoothClass;");
+ if (!bluetoothClass.isValid())
+ return;
+ int classType = bluetoothClass.callMethod<jint>("getDeviceClass");
+
+
+ static QList<qint32> services;
+ if (services.count() == 0)
+ services << QBluetoothDeviceInfo::PositioningService
+ << QBluetoothDeviceInfo::NetworkingService
+ << QBluetoothDeviceInfo::RenderingService
+ << QBluetoothDeviceInfo::CapturingService
+ << QBluetoothDeviceInfo::ObjectTransferService
+ << QBluetoothDeviceInfo::AudioService
+ << QBluetoothDeviceInfo::TelephonyService
+ << QBluetoothDeviceInfo::InformationService;
+
+ //Matching BluetoothClass.Service values
+ qint32 result = 0;
+ qint32 current = 0;
+ for (int i = 0; i < services.count(); i++) {
+ current = services.at(i);
+ int id = (current << 16);
+ if (bluetoothClass.callMethod<jboolean>("hasService", "(I)Z", id))
+ result |= current;
+ }
+
+ result = result << 13;
+ classType |= result;
+
+ QBluetoothDeviceInfo info(deviceAddress, deviceName, classType);
+ info.setRssi(rssi);
+
+ emit deviceDiscovered(info);
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h b/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h
new file mode 100644
index 00000000..6c08b22e
--- /dev/null
+++ b/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEVICEDISCOVERYBROADCASTRECEIVER_H
+#define DEVICEDISCOVERYBROADCASTRECEIVER_H
+
+#include "android/androidbroadcastreceiver_p.h"
+#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
+
+QT_BEGIN_NAMESPACE
+
+class QBluetoothDeviceInfo;
+
+class DeviceDiscoveryBroadcastReceiver : public AndroidBroadcastReceiver
+{
+ Q_OBJECT
+public:
+ DeviceDiscoveryBroadcastReceiver(QObject* parent = 0);
+ virtual void onReceive(JNIEnv *env, jobject context, jobject intent);
+
+signals:
+ void deviceDiscovered(const QBluetoothDeviceInfo &info);
+ void finished();
+};
+
+QT_END_NAMESPACE
+#endif // DEVICEDISCOVERYBROADCASTRECEIVER_H
diff --git a/src/bluetooth/android/inputstreamthread.cpp b/src/bluetooth/android/inputstreamthread.cpp
new file mode 100644
index 00000000..df32ee62
--- /dev/null
+++ b/src/bluetooth/android/inputstreamthread.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+
+#include "android/inputstreamthread_p.h"
+#include "qbluetoothsocket_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+InputStreamThread::InputStreamThread(QBluetoothSocketPrivate *socket)
+ : QThread(), m_stop(false)
+{
+ m_socket_p = socket;
+}
+
+void InputStreamThread::run()
+{
+ qint32 byte;
+ Q_UNUSED(byte)
+ while (1) {
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_stop)
+ break;
+ }
+ readFromInputStream();
+ }
+
+ QAndroidJniEnvironment env;
+ if (m_socket_p->inputStream.isValid())
+ m_socket_p->inputStream.callMethod<void>("close");
+
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+}
+
+bool InputStreamThread::bytesAvailable() const
+{
+ QMutexLocker locker(&m_mutex);
+ return m_socket_p->buffer.size();
+}
+
+//This runs inside the thread.
+void InputStreamThread::readFromInputStream()
+{
+ QAndroidJniEnvironment env;
+
+ int bufLen = 1000; // Seems to magical number that also low-end products can survive.
+ jbyteArray nativeArray = env->NewByteArray(bufLen);
+
+
+ jint ret = m_socket_p->inputStream.callMethod<jint>("read", "([BII)I", nativeArray, 0, bufLen);
+
+ if (env->ExceptionCheck() || ret < 0) {
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ env->DeleteLocalRef(nativeArray);
+ QMutexLocker lock(&m_mutex);
+ m_stop = true;
+
+ /*
+ * We cannot distinguish IOException due to valid closure or due to other error
+ * Therefore we always have to throw an error and a disconnect signal
+ * A genuine disconnect wouldn't need the error signal.
+ * For now we always signal error which implicitly emits disconnect() too.
+ */
+
+ emit error();
+ return;
+ }
+
+ if (ret == 0) {
+ qDebug() << "Nothing to read";
+ env->DeleteLocalRef(nativeArray);
+ return;
+ }
+
+ QMutexLocker lock(&m_mutex);
+ char *writePtr = m_socket_p->buffer.reserve(bufLen);
+ env->GetByteArrayRegion(nativeArray, 0, ret, reinterpret_cast<jbyte*>(writePtr));
+ env->DeleteLocalRef(nativeArray);
+ m_socket_p->buffer.chop(bufLen - ret);
+ emit dataAvailable();
+}
+
+void InputStreamThread::stop()
+{
+ QMutexLocker locker(&m_mutex);
+ m_stop = true;
+}
+
+qint64 InputStreamThread::readData(char *data, qint64 maxSize)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_stop)
+ return -1;
+
+ if (!m_socket_p->buffer.isEmpty())
+ return m_socket_p->buffer.read(data, maxSize);
+
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/android/inputstreamthread_p.h b/src/bluetooth/android/inputstreamthread_p.h
new file mode 100644
index 00000000..85852534
--- /dev/null
+++ b/src/bluetooth/android/inputstreamthread_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INPUTSTREAMTHREAD_H
+#define INPUTSTREAMTHREAD_H
+
+#include <QtCore/QThread>
+#include <QtCore/QMutex>
+
+QT_BEGIN_NAMESPACE
+
+class QBluetoothSocketPrivate;
+
+class InputStreamThread : public QThread
+{
+ Q_OBJECT
+public:
+ explicit InputStreamThread(QBluetoothSocketPrivate *socket_p);
+ virtual void run();
+
+ bool bytesAvailable() const;
+ void stop();
+
+ qint64 readData(char *data, qint64 maxSize);
+signals:
+ void dataAvailable();
+ void error();
+
+private:
+ void readFromInputStream();
+
+ QBluetoothSocketPrivate *m_socket_p;
+ mutable QMutex m_mutex;
+ bool m_stop;
+};
+
+QT_END_NAMESPACE
+
+#endif // INPUTSTREAMTHREAD_H
diff --git a/src/bluetooth/android/jni_android.cpp b/src/bluetooth/android/jni_android.cpp
new file mode 100644
index 00000000..eb1fc2dd
--- /dev/null
+++ b/src/bluetooth/android/jni_android.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <jni.h>
+#include <android/log.h>
+#include <QtCore/QLoggingCategory>
+#include <QtBluetooth/qbluetoothglobal.h>
+#include <QtAndroidExtras/QAndroidJniObject>
+#include "android/androidbroadcastreceiver_p.h"
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+void QtBroadcastReceiver_jniOnReceive(JNIEnv *env, jobject /*javaObject*/,
+ jlong qtObject, jobject context, jobject intent)
+{
+ reinterpret_cast<AndroidBroadcastReceiver*>(qtObject)->onReceive(env, context, intent);
+}
+
+static JNINativeMethod methods[] = {
+ {"jniOnReceive", "(JLandroid/content/Context;Landroid/content/Intent;)V",
+ (void *) QtBroadcastReceiver_jniOnReceive},
+};
+
+static const char logTag[] = "QtBluetooth";
+static const char classErrorMsg[] = "Can't find class \"%s\"";
+
+#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
+clazz = env->FindClass(CLASS_NAME); \
+if (!clazz) { \
+ __android_log_print(ANDROID_LOG_FATAL, logTag, classErrorMsg, CLASS_NAME); \
+ return JNI_FALSE; \
+}
+
+static bool registerNatives(JNIEnv *env)
+{
+ jclass clazz;
+ FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver");
+
+ if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives failed");
+ return false;
+ }
+
+ return true;
+}
+
+Q_BLUETOOTH_EXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
+{
+ typedef union {
+ JNIEnv *nativeEnvironment;
+ void *venv;
+ } UnionJNIEnvToVoid;
+
+ UnionJNIEnvToVoid uenv;
+ uenv.venv = 0;
+
+ if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "GetEnv failed");
+ return -1;
+ }
+
+ JNIEnv *env = uenv.nativeEnvironment;
+ if (!registerNatives(env)) {
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "registerNatives failed");
+ return -1;
+ }
+
+ if (QT_BT_ANDROID().isDebugEnabled())
+ __android_log_print(ANDROID_LOG_INFO, logTag, "Bluetooth start");
+
+ return JNI_VERSION_1_4;
+}
diff --git a/src/bluetooth/android/localdevicebroadcastreceiver.cpp b/src/bluetooth/android/localdevicebroadcastreceiver.cpp
new file mode 100644
index 00000000..0e81ef22
--- /dev/null
+++ b/src/bluetooth/android/localdevicebroadcastreceiver.cpp
@@ -0,0 +1,211 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QLoggingCategory>
+#include "localdevicebroadcastreceiver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+LocalDeviceBroadcastReceiver::LocalDeviceBroadcastReceiver(QObject *parent) :
+ AndroidBroadcastReceiver(parent), previousScanMode(0)
+{
+ addAction(QStringLiteral("android.bluetooth.device.action.BOND_STATE_CHANGED"));
+ addAction(QStringLiteral("android.bluetooth.adapter.action.SCAN_MODE_CHANGED"));
+ addAction(QStringLiteral("android.bluetooth.device.action.ACL_CONNECTED"));
+ addAction(QStringLiteral("android.bluetooth.device.action.ACL_DISCONNECTED"));
+ addAction(QStringLiteral("android.bluetooth.device.action.PAIRING_REQUEST")); //API 19
+
+}
+
+void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(env);
+
+ QAndroidJniObject intentObject(intent);
+ const QString action = intentObject.callObjectMethod("getAction", "()Ljava/lang/String;").toString();
+ qCDebug(QT_BT_ANDROID) << QStringLiteral("LocalDeviceBroadcastReceiver::onReceive() - event: %1").arg(action);
+
+ if (action == QStringLiteral("android.bluetooth.adapter.action.SCAN_MODE_CHANGED")) {
+ QAndroidJniObject extrasBundle =
+ intentObject.callObjectMethod("getExtras","()Landroid/os/Bundle;");
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.adapter.extra.SCAN_MODE"));
+
+ int extra = extrasBundle.callMethod<jint>("getInt",
+ "(Ljava/lang/String;)I",
+ keyExtra.object<jstring>());
+
+ if (previousScanMode != extra) {
+ previousScanMode = extra;
+
+ switch (extra) {
+ case 20: //BluetoothAdapter.SCAN_MODE_NONE
+ emit hostModeStateChanged(QBluetoothLocalDevice::HostPoweredOff);
+ break;
+ case 21: //BluetoothAdapter.SCAN_MODE_CONNECTABLE
+ emit hostModeStateChanged(QBluetoothLocalDevice::HostConnectable);
+ break;
+ case 23: //BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
+ emit hostModeStateChanged(QBluetoothLocalDevice::HostDiscoverable);
+ break;
+ default:
+ qCWarning(QT_BT_ANDROID) << "Unknown Host State";
+ break;
+ }
+ }
+ } else if (action == QStringLiteral("android.bluetooth.device.action.BOND_STATE_CHANGED")) {
+ //get BluetoothDevice
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.DEVICE"));
+ QAndroidJniObject bluetoothDevice =
+ intentObject.callObjectMethod("getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+
+ //get new bond state
+ keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.BOND_STATE"));
+ QAndroidJniObject extrasBundle =
+ intentObject.callObjectMethod("getExtras","()Landroid/os/Bundle;");
+ int bondState = extrasBundle.callMethod<jint>("getInt",
+ "(Ljava/lang/String;)I",
+ keyExtra.object<jstring>());
+
+ QBluetoothAddress address(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ if (address.isNull())
+ return;
+
+ switch (bondState) {
+ case 10: //BluetoothDevice.BOND_NONE
+ emit pairingStateChanged(address, QBluetoothLocalDevice::Unpaired);
+ break;
+ case 11: //BluetoothDevice.BOND_BONDING
+ //we ignore this as Qt doesn't have equivalent API.
+ break;
+ case 12: //BluetoothDevice.BOND_BONDED
+ emit pairingStateChanged(address, QBluetoothLocalDevice::Paired);
+ break;
+ default:
+ qCWarning(QT_BT_ANDROID) << "Unknown BOND_STATE_CHANGED value:" << bondState;
+ break;
+ }
+ } else if (action == QStringLiteral("android.bluetooth.device.action.ACL_DISCONNECTED") ||
+ action == QStringLiteral("android.bluetooth.device.action.ACL_CONNECTED")) {
+
+ const bool isConnectEvent =
+ action == QStringLiteral("android.bluetooth.device.action.ACL_CONNECTED") ? true : false;
+
+ //get BluetoothDevice
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.DEVICE"));
+ QAndroidJniObject bluetoothDevice =
+ intentObject.callObjectMethod("getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+
+ QBluetoothAddress address(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ if (address.isNull())
+ return;
+
+ emit connectDeviceChanges(address, isConnectEvent);
+ } else if (action == QStringLiteral("android.bluetooth.device.action.PAIRING_REQUEST")) {
+
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.PAIRING_VARIANT"));
+ int variant = intentObject.callMethod<jint>("getIntExtra",
+ "(Ljava/lang/String;I)I",
+ keyExtra.object<jstring>(),
+ -1);
+
+ int key = -1;
+ switch (variant) {
+ case -1: //ignore -> no pairing variant set
+ return;
+ case 2: //BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION
+ {
+ keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.PAIRING_KEY"));
+ key = intentObject.callMethod<jint>("getIntExtra",
+ "(Ljava/lang/String;I)I",
+ keyExtra.object<jstring>(),
+ -1);
+ if (key == -1)
+ return;
+
+ keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.DEVICE"));
+ QAndroidJniObject bluetoothDevice =
+ intentObject.callObjectMethod("getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+
+ //we need to keep a reference around in case the user confirms later on
+ pairingDevice = bluetoothDevice;
+
+ QBluetoothAddress address(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+
+ //User has choice to confirm or not. If no confirmation is happening
+ //the OS default pairing dialog can be used or timeout occurs.
+ emit pairingDisplayConfirmation(address, QString::number(key));
+ break;
+ }
+ default:
+ qCWarning(QT_BT_ANDROID) << "Unknown pairing variant: " << variant;
+ return;
+ }
+ }
+}
+
+bool LocalDeviceBroadcastReceiver::pairingConfirmation(bool accept)
+{
+ if (!pairingDevice.isValid())
+ return false;
+
+ bool success = pairingDevice.callMethod<jboolean>("setPairingConfirmation",
+ "(Z)Z", accept);
+ pairingDevice = QAndroidJniObject();
+ return success;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/android/localdevicebroadcastreceiver_p.h b/src/bluetooth/android/localdevicebroadcastreceiver_p.h
new file mode 100644
index 00000000..ddd65d92
--- /dev/null
+++ b/src/bluetooth/android/localdevicebroadcastreceiver_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "android/androidbroadcastreceiver_p.h"
+#include <QtBluetooth/QBluetoothAddress>
+#include <QtBluetooth/QBluetoothLocalDevice>
+
+#ifndef LOCALDEVICEBROADCASTRECEIVER_H
+#define LOCALDEVICEBROADCASTRECEIVER_H
+
+QT_BEGIN_NAMESPACE
+
+class LocalDeviceBroadcastReceiver : public AndroidBroadcastReceiver
+{
+ Q_OBJECT
+public:
+ explicit LocalDeviceBroadcastReceiver(QObject *parent = 0);
+ virtual ~LocalDeviceBroadcastReceiver() {}
+ virtual void onReceive(JNIEnv *env, jobject context, jobject intent);
+ bool pairingConfirmation(bool accept);
+
+signals:
+ void hostModeStateChanged(QBluetoothLocalDevice::HostMode state);
+ void pairingStateChanged(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
+ void connectDeviceChanges(const QBluetoothAddress &address, bool isConnectEvent);
+ void pairingDisplayConfirmation(const QBluetoothAddress &address, const QString& pin);
+private:
+ int previousScanMode;
+ QAndroidJniObject pairingDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif // LOCALDEVICEBROADCASTRECEIVER_H
diff --git a/src/bluetooth/android/serveracceptancethread.cpp b/src/bluetooth/android/serveracceptancethread.cpp
new file mode 100644
index 00000000..88a92478
--- /dev/null
+++ b/src/bluetooth/android/serveracceptancethread.cpp
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QLoggingCategory>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+
+#include "android/serveracceptancethread_p.h"
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+ServerAcceptanceThread::ServerAcceptanceThread(QObject *parent) :
+ QThread(parent), m_stop(false), maxPendingConnections(1)
+{
+ btAdapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
+ "getDefaultAdapter",
+ "()Landroid/bluetooth/BluetoothAdapter;");
+}
+
+ServerAcceptanceThread::~ServerAcceptanceThread()
+{
+ Q_ASSERT(!isRunning());
+ QMutexLocker lock(&m_mutex);
+ shutdownPendingConnections();
+}
+
+void ServerAcceptanceThread::setServiceDetails(const QBluetoothUuid &uuid,
+ const QString &serviceName,
+ QBluetooth::SecurityFlags securityFlags)
+{
+ QMutexLocker lock(&m_mutex);
+ m_uuid = uuid;
+ m_serviceName = serviceName;
+ secFlags = securityFlags;
+}
+
+void ServerAcceptanceThread::run()
+{
+ m_mutex.lock();
+
+ qCDebug(QT_BT_ANDROID) << "Starting ServerSocketAccept thread";
+ if (!validSetup()) {
+ qCWarning(QT_BT_ANDROID) << "Invalid Server Socket setup";
+ m_mutex.unlock();
+ return;
+ }
+
+ shutdownPendingConnections();
+
+ m_stop = false;
+
+ QString tempUuid = m_uuid.toString();
+ tempUuid.chop(1); //remove trailing '}'
+ tempUuid.remove(0,1); //remove first '{'
+
+ QAndroidJniEnvironment env;
+ QAndroidJniObject inputString = QAndroidJniObject::fromString(tempUuid);
+ QAndroidJniObject uuidObject = QAndroidJniObject::callStaticObjectMethod(
+ "java/util/UUID", "fromString",
+ "(Ljava/lang/String;)Ljava/util/UUID;",
+ inputString.object<jstring>());
+ inputString = QAndroidJniObject::fromString(m_serviceName);
+ if (((int)secFlags) == 0) { //no form of security flag set
+ qCDebug(QT_BT_ANDROID) << "InSecure listening";
+ btServerSocket = btAdapter.callObjectMethod("listenUsingInsecureRfcommWithServiceRecord",
+ "(Ljava/lang/String;Ljava/util/UUID;)Landroid/bluetooth/BluetoothServerSocket;",
+ inputString.object<jstring>(),
+ uuidObject.object<jobject>());
+ } else {
+ qCDebug(QT_BT_ANDROID) << "Secure listening";
+ btServerSocket = btAdapter.callObjectMethod("listenUsingRfcommWithServiceRecord",
+ "(Ljava/lang/String;Ljava/util/UUID;)Landroid/bluetooth/BluetoothServerSocket;",
+ inputString.object<jstring>(),
+ uuidObject.object<jobject>());
+ }
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ qCWarning(QT_BT_ANDROID) << "Cannot setup rfcomm socket listener";
+ m_mutex.unlock();
+ return;
+ }
+
+ if (!btServerSocket.isValid()) {
+ qCWarning(QT_BT_ANDROID) << "Invalid BluetoothServerSocket";
+ m_mutex.unlock();
+ return;
+ }
+
+ while (!m_stop) {
+ m_mutex.unlock();
+
+ qCDebug(QT_BT_ANDROID) << "Waiting for new incoming socket";
+ QAndroidJniEnvironment env;
+
+ //this call blocks until we see an incoming connection
+ QAndroidJniObject socket = btServerSocket.callObjectMethod("accept",
+ "()Landroid/bluetooth/BluetoothSocket;");
+
+ qCDebug(QT_BT_ANDROID) << "New socket accepted: ->" << socket.isValid();
+ bool exceptionOccurred = false;
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ exceptionOccurred = true;
+ }
+
+ m_mutex.lock();
+
+ if (exceptionOccurred || m_stop) {
+ //if m_stop is true there is nothing really to be done but exit
+ m_stop = true;
+ } else if (socket.isValid()){
+ if (pendingSockets.count() < maxPendingConnections) {
+ pendingSockets.append(socket);
+ emit newConnection();
+ } else {
+ qCWarning(QT_BT_ANDROID) << "Refusing connection due to limited pending socket queue";
+ socket.callMethod<void>("close");
+ if (env->ExceptionCheck()) {
+ qCWarning(QT_BT_ANDROID) << "Error during refusal of new socket";
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+
+ }
+ } else {
+ //should never happen as invalid socket should cause exception
+ qCWarning(QT_BT_ANDROID) << "Invalid state during server socket accept";
+ }
+ }
+
+ m_uuid = QBluetoothUuid();
+ m_serviceName = QString();
+ btServerSocket = QAndroidJniObject();
+ m_mutex.unlock();
+}
+
+void ServerAcceptanceThread::stop()
+{
+ QMutexLocker lock(&m_mutex);
+ m_stop = true;
+
+ QAndroidJniEnvironment env;
+ if (btServerSocket.isValid()) {
+ qCDebug(QT_BT_ANDROID) << "Closing server socket";
+ btServerSocket.callMethod<void>("close");
+ if (env->ExceptionCheck()) {
+ qCWarning(QT_BT_ANDROID) << "Exception during closure of server socket";
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ qCDebug(QT_BT_ANDROID) << "Closing server socket111";
+ }
+}
+
+bool ServerAcceptanceThread::hasPendingConnections() const
+{
+ QMutexLocker lock(&m_mutex);
+ return (pendingSockets.count() > 0);
+}
+
+/*
+ * Returns the next pending connection or an invalid JNI object.
+ * Note that even a stopped thread may still have pending
+ * connections. Pending connections are only terminated upon
+ * thread restart or destruction.
+ */
+QAndroidJniObject ServerAcceptanceThread::nextPendingConnection()
+{
+ QMutexLocker lock(&m_mutex);
+ if (pendingSockets.isEmpty())
+ return QAndroidJniObject();
+ else
+ return pendingSockets.takeFirst();
+}
+
+void ServerAcceptanceThread::setMaxPendingConnections(int maximumCount)
+{
+ QMutexLocker lock(&m_mutex);
+ maxPendingConnections = maximumCount;
+}
+
+//must be run inside the lock but doesn't lock by itself
+bool ServerAcceptanceThread::validSetup() const
+{
+ return (!m_uuid.isNull() && !m_serviceName.isEmpty());
+}
+
+//must be run inside the lock but doesn't lock by itself
+void ServerAcceptanceThread::shutdownPendingConnections()
+{
+ while (!pendingSockets.isEmpty()) {
+ QAndroidJniObject socket = pendingSockets.takeFirst();
+ socket.callMethod<void>("close");
+ }
+}
diff --git a/src/bluetooth/android/serveracceptancethread_p.h b/src/bluetooth/android/serveracceptancethread_p.h
new file mode 100644
index 00000000..1297e48f
--- /dev/null
+++ b/src/bluetooth/android/serveracceptancethread_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERVERACCEPTANCETHREAD_H
+#define SERVERACCEPTANCETHREAD_H
+
+#include <QtCore/QMutex>
+#include <QtCore/QThread>
+#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtBluetooth/QBluetoothUuid>
+#include "qbluetooth.h"
+
+
+class ServerAcceptanceThread : public QThread
+{
+ Q_OBJECT
+public:
+ enum AndroidError {
+ AndroidNoError
+ };
+
+ explicit ServerAcceptanceThread(QObject *parent = 0);
+ ~ServerAcceptanceThread();
+ void setServiceDetails(const QBluetoothUuid &uuid, const QString &serviceName,
+ QBluetooth::SecurityFlags securityFlags);
+ virtual void run();
+
+ void stop();
+ bool hasPendingConnections() const;
+ QAndroidJniObject nextPendingConnection();
+ void setMaxPendingConnections(int maximumCount);
+
+signals:
+ void newConnection();
+ void error(ServerAcceptanceThread::AndroidError);
+
+private:
+ bool validSetup() const;
+ void shutdownPendingConnections();
+
+ QList<QAndroidJniObject> pendingSockets;
+ QAndroidJniObject btAdapter;
+ QAndroidJniObject btServerSocket;
+ mutable QMutex m_mutex;
+ QString m_serviceName;
+ QBluetoothUuid m_uuid;
+ bool m_stop;
+ AndroidError lastError;
+ int maxPendingConnections;
+ QBluetooth::SecurityFlags secFlags;
+
+};
+
+#endif // SERVERACCEPTANCETHREAD_H
diff --git a/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp b/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp
new file mode 100644
index 00000000..341617bc
--- /dev/null
+++ b/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "android/servicediscoverybroadcastreceiver_p.h"
+#include <QtCore/QLoggingCategory>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtBluetooth/QBluetoothAddress>
+#include <QtBluetooth/QBluetoothDeviceInfo>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+ServiceDiscoveryBroadcastReceiver::ServiceDiscoveryBroadcastReceiver(QObject* parent): AndroidBroadcastReceiver(parent)
+{
+ addAction(QStringLiteral("android.bluetooth.device.action.UUID"));
+}
+
+void ServiceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(env);
+
+ QAndroidJniObject intentObject(intent);
+ const QString action = intentObject.callObjectMethod("getAction", "()Ljava/lang/String;").toString();
+
+ qCDebug(QT_BT_ANDROID) << "ServiceDiscoveryBroadcastReceiver::onReceive() - event:" << action;
+
+ if (action == QStringLiteral("android.bluetooth.device.action.UUID")) {
+ QAndroidJniObject keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.UUID"));
+ QAndroidJniObject parcelableUuids = intentObject.callObjectMethod(
+ "getParcelableArrayExtra",
+ "(Ljava/lang/String;)[Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+ if (!parcelableUuids.isValid())
+ return;
+ QList<QBluetoothUuid> result = ServiceDiscoveryBroadcastReceiver::convertParcelableArray(parcelableUuids);
+
+ keyExtra = QAndroidJniObject::fromString(
+ QStringLiteral("android.bluetooth.device.extra.DEVICE"));
+ QAndroidJniObject bluetoothDevice =
+ intentObject.callObjectMethod("getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra.object<jstring>());
+ QBluetoothAddress address;
+ if (bluetoothDevice.isValid()) {
+ address = QBluetoothAddress(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ emit uuidFetchFinished(address, result);
+ }
+ }
+}
+
+QList<QBluetoothUuid> ServiceDiscoveryBroadcastReceiver::convertParcelableArray(const QAndroidJniObject &parcelUuidArray)
+{
+ QList<QBluetoothUuid> result;
+ QAndroidJniEnvironment env;
+ QAndroidJniObject p;
+
+ jobjectArray parcels = parcelUuidArray.object<jobjectArray>();
+ if (!parcels)
+ return result;
+
+ jint size = env->GetArrayLength(parcels);
+ for (int i = 0; i < size; i++) {
+ p = env->GetObjectArrayElement(parcels, i);
+
+ QBluetoothUuid uuid(p.callObjectMethod<jstring>("toString").toString());
+ //qCDebug(QT_BT_ANDROID) << uuid.toString();
+ result.append(uuid);
+ }
+
+ return result;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h b/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h
new file mode 100644
index 00000000..e75095e8
--- /dev/null
+++ b/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERVICEDISCOVERYBROADCASTRECEIVER_H
+#define SERVICEDISCOVERYBROADCASTRECEIVER_H
+
+#include "android/androidbroadcastreceiver_p.h"
+#include <QtCore/QList>
+#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
+#include <QtBluetooth/QBluetoothUuid>
+
+QT_BEGIN_NAMESPACE
+
+class QBluetoothDeviceInfo;
+
+class ServiceDiscoveryBroadcastReceiver : public AndroidBroadcastReceiver
+{
+ Q_OBJECT
+public:
+ ServiceDiscoveryBroadcastReceiver(QObject* parent = 0);
+ virtual void onReceive(JNIEnv *env, jobject context, jobject intent);
+
+ static QList<QBluetoothUuid> convertParcelableArray(const QAndroidJniObject &obj);
+
+signals:
+ void uuidFetchFinished(const QBluetoothAddress &addr, const QList<QBluetoothUuid> &serviceUuid);
+};
+
+QT_END_NAMESPACE
+#endif // SERVICEDISCOVERYBROADCASTRECEIVER_H