diff options
author | Alex Blasche <alexander.blasche@digia.com> | 2014-03-13 09:25:37 +0100 |
---|---|---|
committer | Alex Blasche <alexander.blasche@digia.com> | 2014-03-13 09:26:02 +0100 |
commit | 40ac14e13b0aa07124c6ae9ef8eacfe6d8550684 (patch) | |
tree | feb2ac5da95042fb34d3a6ab57f7586e797f8dd4 | |
parent | c03d4f3472ee41c697332ccc95c7db358368b81d (diff) | |
parent | 61f2f050a750d286791e8848bcba2e990311ba29 (diff) |
Merge branch 'stable' into dev
Change-Id: I1c528ed03bf592bcd762fa0cb7710217fbf37eba
35 files changed, 549 insertions, 186 deletions
@@ -28,28 +28,32 @@ examples/bluetooth/btchat/btchat examples/bluetooth/btfiletransfer/btfiletransfer examples/bluetooth/btscanner/btscanner examples/bluetooth/bttennis/bttennis +examples/bluetooth/picturetransfer/qml_picturetransfer examples/bluetooth/scanner/qml_scanner examples/nfc/annotatedurl/annotatedurl examples/nfc/ndefeditor/ndefeditor examples/nfc/poster/qml_poster examples/nfc/corkboard/qml_corkboard +src/bluetooth/doc/snippets/bluetooth_cppsnippet +src/nfc/doc/snippets/nfc_cppsnippet tests/auto/cmake/build tests/auto/qbluetoothaddress/tst_qbluetoothaddress tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo tests/auto/qbluetoothhostinfo/tst_qbluetoothhostinfo tests/auto/qbluetoothlocaldevice/tst_qbluetoothlocaldevice +tests/auto/qbluetoothserver/tst_qbluetoothserver tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo tests/auto/qbluetoothsocket/tst_qbluetoothsocket tests/auto/qbluetoothtransfermanager/tst_qbluetoothtransfermanager tests/auto/qbluetoothtransferrequest/tst_qbluetoothtransferrequest tests/auto/qbluetoothuuid/tst_qbluetoothuuid -tests/auto/ql2capserver/tst_ql2capserver tests/auto/qndefmessage/tst_qndefmessage +tests/auto/qndefnfcsmartposterrecord/tst_qndefnfcsmartposterrecord tests/auto/qndefrecord/tst_qndefrecord tests/auto/qnearfieldmanager/tst_qnearfieldmanager tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1 tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2 -tests/auto/qrfcommserver/tst_qrfcommserver +tests/bttestui/bttestui tests/nfctestserver/nfctestserver diff --git a/examples/nfc/annotatedurl/annotatedurl.cpp b/examples/nfc/annotatedurl/annotatedurl.cpp index 293decf7..f29045b6 100644 --- a/examples/nfc/annotatedurl/annotatedurl.cpp +++ b/examples/nfc/annotatedurl/annotatedurl.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). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtNfc module. @@ -63,8 +63,10 @@ AnnotatedUrl::~AnnotatedUrl() { } +//! [handleMessage 1] void AnnotatedUrl::handleMessage(const QNdefMessage &message, QNearFieldTarget *target) { +//! [handleMessage 1] Q_UNUSED(target); enum { @@ -81,39 +83,40 @@ void AnnotatedUrl::handleMessage(const QNdefMessage &message, QNearFieldTarget * QUrl url; QPixmap pixmap; +//! [handleMessage 2] foreach (const QNdefRecord &record, message) { if (record.isRecordType<QNdefNfcTextRecord>()) { QNdefNfcTextRecord textRecord(record); + title = textRecord.text(); QLocale locale(textRecord.locale()); - +//! [handleMessage 2] // already found best match if (bestMatch == MatchedLanguageAndCountry) { // do nothing } else if (bestMatch <= MatchedLanguage && locale == defaultLocale) { - title = textRecord.text(); bestMatch = MatchedLanguageAndCountry; } else if (bestMatch <= MatchedEnglish && locale.language() == defaultLocale.language()) { - title = textRecord.text(); bestMatch = MatchedLanguage; } else if (bestMatch <= MatchedFirst && locale.language() == QLocale::English) { - title = textRecord.text(); bestMatch = MatchedEnglish; } else if (bestMatch == MatchedNone) { - title = textRecord.text(); bestMatch = MatchedFirst; } +//! [handleMessage 3] } else if (record.isRecordType<QNdefNfcUriRecord>()) { QNdefNfcUriRecord uriRecord(record); url = uriRecord.uri(); +//! [handleMessage 3] } else if (record.typeNameFormat() == QNdefRecord::Mime && record.type().startsWith("image/")) { pixmap = QPixmap::fromImage(QImage::fromData(record.payload())); +//! [handleMessage 4] } } emit annotatedUrl(url, title, pixmap); } - +//! [handleMessage 4] diff --git a/examples/nfc/annotatedurl/main.cpp b/examples/nfc/annotatedurl/main.cpp index c669e57b..351f33bf 100644 --- a/examples/nfc/annotatedurl/main.cpp +++ b/examples/nfc/annotatedurl/main.cpp @@ -57,6 +57,7 @@ int main(int argc, char *argv[]) QApplication a(argc, argv); MainWindow mainWindow; + //! [QNearFieldManager register handler] QNearFieldManager manager; AnnotatedUrl annotatedUrl; @@ -66,6 +67,7 @@ int main(int argc, char *argv[]) filter.appendRecord<QNdefNfcUriRecord>(); manager.registerNdefMessageHandler(filter, &annotatedUrl, SLOT(handleMessage(QNdefMessage,QNearFieldTarget*))); + //! [QNearFieldManager register handler] QObject::connect(&annotatedUrl, SIGNAL(annotatedUrl(QUrl,QString,QPixmap)), &mainWindow, SLOT(displayAnnotatedUrl(QUrl,QString,QPixmap))); diff --git a/examples/nfc/ndefeditor/mainwindow.cpp b/examples/nfc/ndefeditor/mainwindow.cpp index df8f758c..fedb0866 100644 --- a/examples/nfc/ndefeditor/mainwindow.cpp +++ b/examples/nfc/ndefeditor/mainwindow.cpp @@ -120,8 +120,7 @@ void addRecord(Ui::MainWindow *ui, const QNdefRecord &record = QNdefRecord()) } MainWindow::MainWindow(QWidget *parent) -: QMainWindow(parent), ui(new Ui::MainWindow), m_manager(new QNearFieldManager(this)), - m_touchAction(NoAction) +: QMainWindow(parent), ui(new Ui::MainWindow), m_touchAction(NoAction) { ui->setupUi(this); @@ -135,10 +134,13 @@ MainWindow::MainWindow(QWidget *parent) QVBoxLayout *vbox = new QVBoxLayout; ui->scrollAreaWidgetContents->setLayout(vbox); + //! [QNearFieldManager init] + m_manager = new QNearFieldManager(this); connect(m_manager, SIGNAL(targetDetected(QNearFieldTarget*)), this, SLOT(targetDetected(QNearFieldTarget*))); connect(m_manager, SIGNAL(targetLost(QNearFieldTarget*)), this, SLOT(targetLost(QNearFieldTarget*))); + //! [QNearFieldManager init] } MainWindow::~MainWindow() @@ -205,7 +207,9 @@ void MainWindow::touchReceive() m_touchAction = ReadNdef; m_manager->setTargetAccessModes(QNearFieldManager::NdefReadTargetAccess); + //! [QNearFieldManager start detection] m_manager->startTargetDetection(); + //! [QNearFieldManager start detection] } void MainWindow::touchStore() @@ -218,6 +222,7 @@ void MainWindow::touchStore() m_manager->startTargetDetection(); } +//! [QNearFieldTarget detected] void MainWindow::targetDetected(QNearFieldTarget *target) { switch (m_touchAction) { @@ -240,11 +245,14 @@ void MainWindow::targetDetected(QNearFieldTarget *target) break; } } +//! [QNearFieldTarget detected] +//! [QNearFieldTarget lost] void MainWindow::targetLost(QNearFieldTarget *target) { target->deleteLater(); } +//! [QNearFieldTarget lost] void MainWindow::ndefMessageRead(const QNdefMessage &message) { @@ -267,7 +275,9 @@ void MainWindow::ndefMessageRead(const QNdefMessage &message) ui->status->setStyleSheet(QString()); m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess); + //! [QNearFieldManager stop detection] m_manager->stopTargetDetection(); + //! [QNearFieldManager stop detection] m_request = QNearFieldTarget::RequestId(); ui->statusBar->clearMessage(); } 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 index 1f0049ef..ba96c0cf 100644 --- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java +++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java @@ -62,7 +62,20 @@ public class QtBluetoothBroadcastReceiver extends BroadcastReceiver public void onReceive(Context context, Intent intent) { - jniOnReceive(qtObject, context, intent); + synchronized (qtactivity) { + if (qtObject == 0) + return; + + jniOnReceive(qtObject, context, intent); + } + } + + public void unregisterReceiver() + { + synchronized (qtactivity) { + qtObject = 0; + qtactivity.unregisterReceiver(this); + } } public native void jniOnReceive(long qtObject, Context context, Intent intent); diff --git a/src/bluetooth/android/android.pri b/src/bluetooth/android/android.pri index 3c8a0380..0507894f 100644 --- a/src/bluetooth/android/android.pri +++ b/src/bluetooth/android/android.pri @@ -4,7 +4,8 @@ PRIVATE_HEADERS += \ android/servicediscoverybroadcastreceiver_p.h \ android/androidbroadcastreceiver_p.h \ android/localdevicebroadcastreceiver_p.h \ - android/serveracceptancethread_p.h + android/serveracceptancethread_p.h \ + android/jni_android_p.h SOURCES += \ diff --git a/src/bluetooth/android/androidbroadcastreceiver.cpp b/src/bluetooth/android/androidbroadcastreceiver.cpp index affa7683..c17502ba 100644 --- a/src/bluetooth/android/androidbroadcastreceiver.cpp +++ b/src/bluetooth/android/androidbroadcastreceiver.cpp @@ -72,7 +72,6 @@ AndroidBroadcastReceiver::AndroidBroadcastReceiver(QObject* parent) AndroidBroadcastReceiver::~AndroidBroadcastReceiver() { - unregisterReceiver(); } bool AndroidBroadcastReceiver::isValid() const @@ -85,19 +84,15 @@ void AndroidBroadcastReceiver::unregisterReceiver() if (!valid) return; - activityObject.callObjectMethod( - "unregisterReceiver", - "(Landroid/content/BroadcastReceiver;)V", - broadcastReceiverObject.object<jobject>()); + broadcastReceiverObject.callMethod<void>("unregisterReceiver"); } -void AndroidBroadcastReceiver::addAction(const QString &action) +void AndroidBroadcastReceiver::addAction(const QAndroidJniObject &action) { - if (!valid) + if (!valid || !action.isValid()) return; - QAndroidJniObject actionString = QAndroidJniObject::fromString(action); - intentFilterObject.callMethod<void>("addAction", "(Ljava/lang/String;)V", actionString.object<jstring>()); + intentFilterObject.callMethod<void>("addAction", "(Ljava/lang/String;)V", action.object<jstring>()); activityObject.callObjectMethod( "registerReceiver", diff --git a/src/bluetooth/android/androidbroadcastreceiver_p.h b/src/bluetooth/android/androidbroadcastreceiver_p.h index baae6798..58c2b40b 100644 --- a/src/bluetooth/android/androidbroadcastreceiver_p.h +++ b/src/bluetooth/android/androidbroadcastreceiver_p.h @@ -58,14 +58,14 @@ public: AndroidBroadcastReceiver(QObject* parent = 0); virtual ~AndroidBroadcastReceiver(); - void addAction(const QString &filter); + void addAction(const QAndroidJniObject &filter); bool isValid() const; + void unregisterReceiver(); 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; diff --git a/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp index 16a6afe4..ca62f013 100644 --- a/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp +++ b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp @@ -44,6 +44,7 @@ #include <QtCore/QLoggingCategory> #include <QtBluetooth/QBluetoothAddress> #include <QtBluetooth/QBluetoothDeviceInfo> +#include "android/jni_android_p.h" QT_BEGIN_NAMESPACE @@ -51,9 +52,9 @@ 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")); + addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionFound)); + addAction(valueForStaticField(JavaNames::BluetoothAdapter, JavaNames::ActionDiscoveryStarted)); + addAction(valueForStaticField(JavaNames::BluetoothAdapter, JavaNames::ActionDiscoveryFinished)); } void DeviceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent) @@ -66,15 +67,18 @@ void DeviceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, j qCDebug(QT_BT_ANDROID) << "DeviceDiscoveryBroadcastReceiver::onReceive() - event:" << action; - if (action == QStringLiteral("android.bluetooth.adapter.action.DISCOVERY_FINISHED") ) { + if (action == valueForStaticField(JavaNames::BluetoothAdapter, + JavaNames::ActionDiscoveryFinished).toString()) { emit finished(); - } else if (action == QStringLiteral("android.bluetooth.adapter.action.DISCOVERY_STARTED") ) { + } else if (action == valueForStaticField(JavaNames::BluetoothAdapter, + JavaNames::ActionDiscoveryStarted).toString()) { - } else if (action == QStringLiteral("android.bluetooth.device.action.FOUND")) { + } else if (action == valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ActionFound).toString()) { //get BluetoothDevice - QAndroidJniObject keyExtra = QAndroidJniObject::fromString( - QStringLiteral("android.bluetooth.device.extra.DEVICE")); - QAndroidJniObject bluetoothDevice = + QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ExtraDevice); + const QAndroidJniObject bluetoothDevice = intentObject.callObjectMethod("getParcelableExtra", "(Ljava/lang/String;)Landroid/os/Parcelable;", keyExtra.object<jstring>()); @@ -84,13 +88,14 @@ void DeviceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, j 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")); + keyExtra = valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ExtraRssi); + int rssi = intentObject.callMethod<jshort>("getShortExtra", "(Ljava/lang/String;S)S", keyExtra.object<jstring>(), 0); - QAndroidJniObject bluetoothClass = bluetoothDevice.callObjectMethod("getBluetoothClass", + const QAndroidJniObject bluetoothClass = bluetoothDevice.callObjectMethod("getBluetoothClass", "()Landroid/bluetooth/BluetoothClass;"); if (!bluetoothClass.isValid()) return; diff --git a/src/bluetooth/android/jni_android.cpp b/src/bluetooth/android/jni_android.cpp index 1e907fdd..ebc46a7c 100644 --- a/src/bluetooth/android/jni_android.cpp +++ b/src/bluetooth/android/jni_android.cpp @@ -44,13 +44,123 @@ #include <android/log.h> #include <QtCore/QLoggingCategory> #include <QtBluetooth/qbluetoothglobal.h> -#include <QtAndroidExtras/QAndroidJniObject> +#include "android/jni_android_p.h" #include "android/androidbroadcastreceiver_p.h" #include "android/serveracceptancethread_p.h" #include "android/inputstreamthread_p.h" Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID) +typedef QHash<QByteArray, QAndroidJniObject> JCachedStringFields; +Q_GLOBAL_STATIC(JCachedStringFields, cachedStringFields) + +//Java class names +static const char * const javaBluetoothAdapterClassName = "android/bluetooth/BluetoothAdapter"; +static const char * const javaBluetoothDeviceClassName = "android/bluetooth/BluetoothDevice" ; + +//Java field names +static const char * const javaActionAclConnected = "ACTION_ACL_CONNECTED"; +static const char * const javaActionAclDisconnected = "ACTION_ACL_DISCONNECTED"; +static const char * const javaActionBondStateChanged = "ACTION_BOND_STATE_CHANGED"; +static const char * const javaActionDiscoveryStarted = "ACTION_DISCOVERY_STARTED"; +static const char * const javaActionDiscoveryFinished = "ACTION_DISCOVERY_FINISHED"; +static const char * const javaActionFound = "ACTION_FOUND"; +static const char * const javaActionPairingRequest = "ACTION_PAIRING_REQUEST"; +static const char * const javaActionScanModeChanged = "ACTION_SCAN_MODE_CHANGED"; +static const char * const javaActionUuid = "ACTION_UUID"; +static const char * const javaExtraBondState = "EXTRA_BOND_STATE"; +static const char * const javaExtraDevice = "EXTRA_DEVICE"; +static const char * const javaExtraPairingKey = "EXTRA_PAIRING_KEY"; +static const char * const javaExtraPairingVariant = "EXTRA_PAIRING_VARIANT"; +static const char * const javaExtraRssi = "EXTRA_RSSI"; +static const char * const javaExtraScanMode = "EXTRA_SCAN_MODE"; +static const char * const javaExtraUuid = "EXTRA_UUID"; + +/* + * This function operates on the assumption that each + * field is of type java/lang/String. + */ +QAndroidJniObject valueForStaticField(JavaNames javaName, JavaNames javaFieldName) +{ + //construct key + //the switch statements are used to reduce the number of duplicated strings + //in the library + + const char* className; + switch (javaName) { + case JavaNames::BluetoothAdapter: + className = javaBluetoothAdapterClassName; break; + case JavaNames::BluetoothDevice: + className = javaBluetoothDeviceClassName; break; + default: + qWarning(QT_BT_ANDROID) << "Unknown java class name passed to valueForStaticField():" << javaName; + return QAndroidJniObject(); + } + + const char *fieldName; + switch (javaFieldName) { + case JavaNames::ActionAclConnected: + fieldName = javaActionAclConnected; break; + case JavaNames::ActionAclDisconnected: + fieldName = javaActionAclDisconnected; break; + case JavaNames::ActionBondStateChanged: + fieldName = javaActionBondStateChanged; break; + case JavaNames::ActionDiscoveryStarted: + fieldName = javaActionDiscoveryStarted; break; + case JavaNames::ActionDiscoveryFinished: + fieldName = javaActionDiscoveryFinished; break; + case JavaNames::ActionFound: + fieldName = javaActionFound; break; + case JavaNames::ActionPairingRequest: + fieldName = javaActionPairingRequest; break; + case JavaNames::ActionScanModeChanged: + fieldName = javaActionScanModeChanged; break; + case JavaNames::ActionUuid: + fieldName = javaActionUuid; break; + case JavaNames::ExtraBondState: + fieldName = javaExtraBondState; break; + case JavaNames::ExtraDevice: + fieldName = javaExtraDevice; break; + case JavaNames::ExtraPairingKey: + fieldName = javaExtraPairingKey; break; + case JavaNames::ExtraPairingVariant: + fieldName = javaExtraPairingVariant; break; + case JavaNames::ExtraRssi: + fieldName = javaExtraRssi; break; + case JavaNames::ExtraScanMode: + fieldName = javaExtraScanMode; break; + case JavaNames::ExtraUuid: + fieldName = javaExtraUuid; break; + default: + qWarning(QT_BT_ANDROID) << "Unknown java field name passed to valueForStaticField():" << javaFieldName; + return QAndroidJniObject(); + } + + int offset_class = qstrlen(className); + int offset_field = qstrlen(fieldName); + QByteArray key(offset_class + offset_field, Qt::Uninitialized); + memcpy(key.data(), className, offset_class); + memcpy(key.data()+offset_class, fieldName, offset_field); + + JCachedStringFields::iterator it = cachedStringFields()->find(key); + if (it == cachedStringFields()->end()) { + QAndroidJniEnvironment env; + QAndroidJniObject fieldValue = QAndroidJniObject::getStaticObjectField( + className, fieldName, "Ljava/lang/String;"); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + cachedStringFields()->insert(key, QAndroidJniObject()); + return QAndroidJniObject(); + } + + cachedStringFields()->insert(key, fieldValue); + return fieldValue; + } else { + return it.value(); + } +} + void QtBroadcastReceiver_jniOnReceive(JNIEnv *env, jobject /*javaObject*/, jlong qtObject, jobject context, jobject intent) { diff --git a/src/bluetooth/android/jni_android_p.h b/src/bluetooth/android/jni_android_p.h new file mode 100644 index 00000000..9cddd2f9 --- /dev/null +++ b/src/bluetooth/android/jni_android_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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 JNI_ANDROID_P_H +#define JNI_ANDROID_P_H + +#include <QtAndroidExtras/QAndroidJniEnvironment> +#include <QtAndroidExtras/QAndroidJniObject> + +QT_BEGIN_NAMESPACE + +enum JavaNames { + BluetoothAdapter = 0, + BluetoothDevice, + ActionAclConnected, + ActionAclDisconnected, + ActionBondStateChanged, + ActionDiscoveryStarted, + ActionDiscoveryFinished, + ActionFound, + ActionPairingRequest, + ActionScanModeChanged, + ActionUuid, + ExtraBondState, + ExtraDevice, + ExtraPairingKey, + ExtraPairingVariant, + ExtraRssi, + ExtraScanMode, + ExtraUuid +}; + +QAndroidJniObject valueForStaticField(JavaNames javaName, JavaNames javaFieldName); + +QT_END_NAMESPACE + +#endif // JNI_ANDROID_P_H diff --git a/src/bluetooth/android/localdevicebroadcastreceiver.cpp b/src/bluetooth/android/localdevicebroadcastreceiver.cpp index 0e81ef22..5b7e4a38 100644 --- a/src/bluetooth/android/localdevicebroadcastreceiver.cpp +++ b/src/bluetooth/android/localdevicebroadcastreceiver.cpp @@ -40,21 +40,51 @@ ****************************************************************************/ #include <QtCore/QLoggingCategory> +#include <QtCore/private/qjnihelpers_p.h> #include "localdevicebroadcastreceiver_p.h" +#include "android/jni_android_p.h" QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID) +const char *scanModes[] = {"SCAN_MODE_NONE", "SCAN_MODE_CONNECTABLE", "SCAN_MODE_CONNECTABLE_DISCOVERABLE"}; +const char *bondModes[] = {"BOND_NONE", "BOND_BONDING", "BOND_BONDED"}; + 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 + addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionBondStateChanged)); + addAction(valueForStaticField(JavaNames::BluetoothAdapter, JavaNames::ActionScanModeChanged)); + addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionAclConnected)); + addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionAclDisconnected)); + if (QtAndroidPrivate::androidSdkVersion() >= 19) + addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionPairingRequest)); //API 19 + + //cache integer values for host & bonding mode + //don't use the java fields directly but refer to them by name + QAndroidJniEnvironment env; + for (uint i = 0; i < (sizeof(hostModePreset)/sizeof(hostModePreset[0])); i++) { + hostModePreset[i] = QAndroidJniObject::getStaticField<jint>( + "android/bluetooth/BluetoothAdapter", + scanModes[i]); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + hostModePreset[i] = 0; + } + } + for (uint i = 0; i < (sizeof(bondingModePreset)/sizeof(bondingModePreset[0])); i++) { + bondingModePreset[i] = QAndroidJniObject::getStaticField<jint>( + "android/bluetooth/BluetoothDevice", + bondModes[i]); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + bondingModePreset[i] = 0; + } + } } void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent) @@ -66,11 +96,13 @@ void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobje 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 = + if (action == valueForStaticField(JavaNames::BluetoothAdapter, + JavaNames::ActionScanModeChanged).toString()) { + + const QAndroidJniObject extrasBundle = intentObject.callObjectMethod("getExtras","()Landroid/os/Bundle;"); - QAndroidJniObject keyExtra = QAndroidJniObject::fromString( - QStringLiteral("android.bluetooth.adapter.extra.SCAN_MODE")); + const QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothAdapter, + JavaNames::ExtraScanMode); int extra = extrasBundle.callMethod<jint>("getInt", "(Ljava/lang/String;)I", @@ -79,34 +111,28 @@ void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobje 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; - } + if (extra == hostModePreset[0]) + emit hostModeStateChanged(QBluetoothLocalDevice::HostPoweredOff); + else if (extra == hostModePreset[1]) + emit hostModeStateChanged(QBluetoothLocalDevice::HostConnectable); + else if (extra == hostModePreset[2]) + emit hostModeStateChanged(QBluetoothLocalDevice::HostDiscoverable); + else + qCWarning(QT_BT_ANDROID) << "Unknown Host State"; } - } else if (action == QStringLiteral("android.bluetooth.device.action.BOND_STATE_CHANGED")) { + } else if (action == valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ActionBondStateChanged).toString()) { //get BluetoothDevice - QAndroidJniObject keyExtra = QAndroidJniObject::fromString( - QStringLiteral("android.bluetooth.device.extra.DEVICE")); - QAndroidJniObject bluetoothDevice = + QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ExtraDevice); + const 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 = + keyExtra = valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ExtraBondState); + const QAndroidJniObject extrasBundle = intentObject.callObjectMethod("getExtras","()Landroid/os/Bundle;"); int bondState = extrasBundle.callMethod<jint>("getInt", "(Ljava/lang/String;)I", @@ -116,29 +142,28 @@ void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobje if (address.isNull()) return; - switch (bondState) { - case 10: //BluetoothDevice.BOND_NONE + if (bondState == bondingModePreset[0]) 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 + else if (bondState == bondingModePreset[1]) + ; //we ignore this as Qt doesn't have equivalent API value + else if (bondState == bondingModePreset[2]) emit pairingStateChanged(address, QBluetoothLocalDevice::Paired); - break; - default: + else 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")) { + } else if (action == valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ActionAclConnected).toString() || + action == valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ActionAclDisconnected).toString()) { + + const QString connectEvent = valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ActionAclConnected).toString(); const bool isConnectEvent = - action == QStringLiteral("android.bluetooth.device.action.ACL_CONNECTED") ? true : false; + action == connectEvent ? true : false; //get BluetoothDevice - QAndroidJniObject keyExtra = QAndroidJniObject::fromString( - QStringLiteral("android.bluetooth.device.extra.DEVICE")); + const QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ExtraDevice); QAndroidJniObject bluetoothDevice = intentObject.callObjectMethod("getParcelableExtra", "(Ljava/lang/String;)Landroid/os/Parcelable;", @@ -149,10 +174,11 @@ void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobje return; emit connectDeviceChanges(address, isConnectEvent); - } else if (action == QStringLiteral("android.bluetooth.device.action.PAIRING_REQUEST")) { + } else if (action == valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ActionPairingRequest).toString()) { - QAndroidJniObject keyExtra = QAndroidJniObject::fromString( - QStringLiteral("android.bluetooth.device.extra.PAIRING_VARIANT")); + QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ExtraPairingVariant); int variant = intentObject.callMethod<jint>("getIntExtra", "(Ljava/lang/String;I)I", keyExtra.object<jstring>(), @@ -164,8 +190,8 @@ void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobje return; case 2: //BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION { - keyExtra = QAndroidJniObject::fromString( - QStringLiteral("android.bluetooth.device.extra.PAIRING_KEY")); + keyExtra = valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ExtraPairingKey); key = intentObject.callMethod<jint>("getIntExtra", "(Ljava/lang/String;I)I", keyExtra.object<jstring>(), @@ -173,8 +199,7 @@ void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobje if (key == -1) return; - keyExtra = QAndroidJniObject::fromString( - QStringLiteral("android.bluetooth.device.extra.DEVICE")); + keyExtra = valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ExtraDevice); QAndroidJniObject bluetoothDevice = intentObject.callObjectMethod("getParcelableExtra", "(Ljava/lang/String;)Landroid/os/Parcelable;", diff --git a/src/bluetooth/android/localdevicebroadcastreceiver_p.h b/src/bluetooth/android/localdevicebroadcastreceiver_p.h index ddd65d92..4059b3bb 100644 --- a/src/bluetooth/android/localdevicebroadcastreceiver_p.h +++ b/src/bluetooth/android/localdevicebroadcastreceiver_p.h @@ -65,6 +65,9 @@ signals: private: int previousScanMode; QAndroidJniObject pairingDevice; + + int bondingModePreset[3]; + int hostModePreset[3]; }; QT_END_NAMESPACE diff --git a/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp b/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp index 341617bc..0a3f97f9 100644 --- a/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp +++ b/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp @@ -41,9 +41,11 @@ #include "android/servicediscoverybroadcastreceiver_p.h" #include <QtCore/QLoggingCategory> +#include <QtCore/private/qjnihelpers_p.h> #include <QtAndroidExtras/QAndroidJniEnvironment> #include <QtBluetooth/QBluetoothAddress> #include <QtBluetooth/QBluetoothDeviceInfo> +#include "android/jni_android_p.h" QT_BEGIN_NAMESPACE @@ -51,7 +53,8 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID) ServiceDiscoveryBroadcastReceiver::ServiceDiscoveryBroadcastReceiver(QObject* parent): AndroidBroadcastReceiver(parent) { - addAction(QStringLiteral("android.bluetooth.device.action.UUID")); + if (QtAndroidPrivate::androidSdkVersion() >= 15) + addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionUuid)); //API 15+ } void ServiceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent) @@ -64,19 +67,20 @@ void ServiceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, 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")); + if (action == valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ActionUuid).toString()) { + + QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothDevice, + JavaNames::ExtraUuid); QAndroidJniObject parcelableUuids = intentObject.callObjectMethod( "getParcelableArrayExtra", "(Ljava/lang/String;)[Landroid/os/Parcelable;", keyExtra.object<jstring>()); if (!parcelableUuids.isValid()) return; - QList<QBluetoothUuid> result = ServiceDiscoveryBroadcastReceiver::convertParcelableArray(parcelableUuids); + const QList<QBluetoothUuid> result = ServiceDiscoveryBroadcastReceiver::convertParcelableArray(parcelableUuids); - keyExtra = QAndroidJniObject::fromString( - QStringLiteral("android.bluetooth.device.extra.DEVICE")); + keyExtra = valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ExtraDevice); QAndroidJniObject bluetoothDevice = intentObject.callObjectMethod("getParcelableExtra", "(Ljava/lang/String;)Landroid/os/Parcelable;", diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp index 320e0fb7..4f8ecdff 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp @@ -70,7 +70,10 @@ QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() if (m_active) stop(); - delete receiver; + if (receiver) { + receiver->unregisterReceiver(); + delete receiver; + } } bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const diff --git a/src/bluetooth/qbluetoothlocaldevice.cpp b/src/bluetooth/qbluetoothlocaldevice.cpp index e299ab71..14140846 100644 --- a/src/bluetooth/qbluetoothlocaldevice.cpp +++ b/src/bluetooth/qbluetoothlocaldevice.cpp @@ -139,9 +139,11 @@ bool QBluetoothLocalDevice::isValid() const \fn void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode) Sets the host mode of this local Bluetooth device to \a mode. - NOTE: Due to security policies of platforms, this method may behave different on different platforms. For example - the system can ask the user for confirmation before turning Bluetooth on or off. Not all host modes may be - supported on all platforms. Please refer to the platform specific Bluetooth documentation for details. + + \note Due to varying security policies on the supported platforms, this method may have + differing behaviors on the various platforms. For example the system may ask the user for + confirmation before turning Bluetooth on or off and not all host modes may be supported. + Please refer to the platform specific Bluetooth documentation for details. */ /*! @@ -172,8 +174,10 @@ bool QBluetoothLocalDevice::isValid() const \fn QBluetoothLocalDevice::powerOn() Powers on the device after returning it to the hostMode() state, if it was powered off. - NOTE: Due to security policies of platforms, this method may behave different on different platforms. For example - the system can ask the user for confirmation before turning Bluetooth on or off. + + \note Due to varying security policies on the supported platforms, this method may have + differing behaviors on the various platforms. For example + the system may ask the user for confirmation before turning Bluetooth on or off. Please refer to the platform specific Bluetooth documentation for details. */ diff --git a/src/bluetooth/qbluetoothlocaldevice_android.cpp b/src/bluetooth/qbluetoothlocaldevice_android.cpp index 4e441bc2..ff36837b 100644 --- a/src/bluetooth/qbluetoothlocaldevice_android.cpp +++ b/src/bluetooth/qbluetoothlocaldevice_android.cpp @@ -74,6 +74,7 @@ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate( QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate() { + receiver->unregisterReceiver(); delete receiver; delete obj; } diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp index e0e17c14..2e55d40e 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp @@ -98,8 +98,14 @@ QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate() { - delete receiver; - delete localDeviceReceiver; + if (receiver) { + receiver->unregisterReceiver(); + delete receiver; + } + if (localDeviceReceiver) { + localDeviceReceiver->unregisterReceiver(); + delete localDeviceReceiver; + } } void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address) @@ -209,6 +215,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr jboolean result = remoteDevice.callMethod<jboolean>("fetchUuidsWithSdp"); if (!result) { //kill receiver to limit load of signals + receiver->unregisterReceiver(); receiver->deleteLater(); receiver = 0; qCWarning(QT_BT_ANDROID) << "Cannot start dynamic fetch."; @@ -223,6 +230,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::stop() discoveredDevices.clear(); //kill receiver to limit load of signals + receiver->unregisterReceiver(); receiver->deleteLater(); receiver = 0; @@ -435,7 +443,6 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB 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 @@ -493,6 +500,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_fetchUuidsTimeout() Q_ASSERT(sdpCache.isEmpty()); //kill receiver to limit load of signals + receiver->unregisterReceiver(); receiver->deleteLater(); receiver = 0; _q_serviceDiscoveryFinished(); @@ -509,6 +517,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_hostModeStateChanged(QBluetoothL errorString = QBluetoothServiceDiscoveryAgent::tr("Device is powered off"); //kill receiver to limit load of signals + receiver->unregisterReceiver(); receiver->deleteLater(); receiver = 0; diff --git a/src/bluetooth/qbluetoothsocket_android.cpp b/src/bluetooth/qbluetoothsocket_android.cpp index 769a5e68..a894fed3 100644 --- a/src/bluetooth/qbluetoothsocket_android.cpp +++ b/src/bluetooth/qbluetoothsocket_android.cpp @@ -324,7 +324,6 @@ quint16 QBluetoothSocketPrivate::peerPort() const 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: " << state << outputStream.isValid(); diff --git a/src/bluetooth/qbluetoothsocket_bluez.cpp b/src/bluetooth/qbluetoothsocket_bluez.cpp index 825c6cd7..6aad6603 100644 --- a/src/bluetooth/qbluetoothsocket_bluez.cpp +++ b/src/bluetooth/qbluetoothsocket_bluez.cpp @@ -453,6 +453,7 @@ qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize) if (::write(socket, data, maxSize) != maxSize) { errorString = QBluetoothSocket::tr("Network Error"); q->setSocketError(QBluetoothSocket::NetworkError); + return -1; } emit q->bytesWritten(maxSize); @@ -462,7 +463,7 @@ qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize) else { if(!connectWriteNotifier) - return 0; + return -1; if(txBuffer.size() == 0) { connectWriteNotifier->setEnabled(true); diff --git a/src/bluetooth/qbluetoothsocket_p.cpp b/src/bluetooth/qbluetoothsocket_p.cpp index d64e7ecf..6e78be9e 100644 --- a/src/bluetooth/qbluetoothsocket_p.cpp +++ b/src/bluetooth/qbluetoothsocket_p.cpp @@ -123,7 +123,7 @@ qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize) q->setSocketError(QBluetoothSocket::OperationError); return -1; } - return 0; + return -1; } qint64 QBluetoothSocketPrivate::readData(char *data, qint64 maxSize) @@ -139,7 +139,7 @@ qint64 QBluetoothSocketPrivate::readData(char *data, qint64 maxSize) return -1; } - return 0; + return -1; } void QBluetoothSocketPrivate::close() diff --git a/src/bluetooth/qbluetoothsocket_qnx.cpp b/src/bluetooth/qbluetoothsocket_qnx.cpp index f60ba97a..4e277e28 100644 --- a/src/bluetooth/qbluetoothsocket_qnx.cpp +++ b/src/bluetooth/qbluetoothsocket_qnx.cpp @@ -226,6 +226,7 @@ qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize) errorString = QBluetoothSocket::tr("Network Error"); q->setSocketError(QBluetoothSocket::NetworkError); qCWarning(QT_BT_QNX) << Q_FUNC_INFO << "Socket error"; + return -1; } Q_EMIT q->bytesWritten(maxSize); @@ -233,7 +234,7 @@ qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize) return maxSize; } else { if (!connectWriteNotifier) - return 0; + return -1; if (txBuffer.size() == 0) { connectWriteNotifier->setEnabled(true); diff --git a/src/bluetooth/qbluetoothuuid.cpp b/src/bluetooth/qbluetoothuuid.cpp index 27215656..85d48d49 100644 --- a/src/bluetooth/qbluetoothuuid.cpp +++ b/src/bluetooth/qbluetoothuuid.cpp @@ -49,7 +49,6 @@ QT_BEGIN_NAMESPACE // Bluetooth base UUID 00000000-0000-1000-8000-00805F9B34FB -// TODO: make more efficient Q_GLOBAL_STATIC_WITH_ARGS(QUuid, baseUuid, ("{00000000-0000-1000-8000-00805F9B34FB}")) /*! diff --git a/src/imports/nfc/qdeclarativenearfield.cpp b/src/imports/nfc/qdeclarativenearfield.cpp index 673c9a0d..b1aeced7 100644 --- a/src/imports/nfc/qdeclarativenearfield.cpp +++ b/src/imports/nfc/qdeclarativenearfield.cpp @@ -69,14 +69,7 @@ and \l orderMatch properties to match the required NDEF messages. Once an NDEF message is successfully read from a tag the \l messageRecords property is updated. - \code - NearField { - filter: [ NdefFilter { type: "U"; typeNameFormat: NdefRecord.NfcRtd; minimum: 1; maximum: 1 } ] - orderMatch: false - - onMessageRecordsChanged: displayMessage() - } - \endcode + \snippet doc_src_qtnfc.qml QML register for messages */ /*! diff --git a/src/nfc/doc/snippets/doc_src_qtnfc.cpp b/src/nfc/doc/snippets/doc_src_qtnfc.cpp index b7b0dfc4..62aa65e2 100644 --- a/src/nfc/doc/snippets/doc_src_qtnfc.cpp +++ b/src/nfc/doc/snippets/doc_src_qtnfc.cpp @@ -38,11 +38,35 @@ ** ****************************************************************************/ +#include <QtCore/QObject> //! [include] #include <QtNfc/QNearFieldManager> //! [include] +#include <QtNfc/QNdefMessage> //! [namespace] QT_USE_NAMESPACE //! [namespace] +class MyClass : public QObject +{ + Q_OBJECT +public: + MyClass() : QObject() + { +//formatting adjusted to improve usage in docs +//! [handleNdefMessage] +QNearFieldManager *manager = new QNearFieldManager(this); +manager->registerNdefMessageHandler(this, + SLOT(handleNdefMessage(QNdefMessage,QNearFieldTarget*))); +//! [handleNdefMessage] + } + +public Q_SLOTS: + void handleNdefMessage(QNdefMessage,QNearFieldTarget*) + { + } +}; + +#include "doc_src_qtnfc.moc" + diff --git a/src/nfc/doc/snippets/doc_src_qtnfc.pro b/src/nfc/doc/snippets/doc_src_qtnfc.pro deleted file mode 100644 index 5730e227..00000000 --- a/src/nfc/doc/snippets/doc_src_qtnfc.pro +++ /dev/null @@ -1,51 +0,0 @@ -#**************************************************************************** -#* -#* Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com> -#* Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -#* Contact: http://www.qt-project.org/legal -#* -#* This file is part of the documentation 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$ -#* -#***************************************************************************/ - -#! [project modification] -QT += nfc -#! [project modification] - -SOURCES += main.cpp \ - doc_src_qtnfc.cpp \ - nfc.cpp \ - foorecord.cpp - -HEADERS += foorecord.h diff --git a/src/nfc/doc/snippets/doc_src_qtnfc.qml b/src/nfc/doc/snippets/doc_src_qtnfc.qml index 6c4d892d..427c24c6 100644 --- a/src/nfc/doc/snippets/doc_src_qtnfc.qml +++ b/src/nfc/doc/snippets/doc_src_qtnfc.qml @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com> +** 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 Qt Toolkit. @@ -42,4 +43,13 @@ import QtNfc 5.2 //! [import] -Item { } +Item { +//! [QML register for messages] + NearField { + filter: [ NdefFilter { type: "U"; typeNameFormat: NdefRecord.NfcRtd; minimum: 1; maximum: 1 } ] + orderMatch: false + + onMessageRecordsChanged: displayMessage() + } +//! [QML register for messages] +} diff --git a/src/nfc/doc/snippets/snippets.pro b/src/nfc/doc/snippets/snippets.pro new file mode 100644 index 00000000..437782e4 --- /dev/null +++ b/src/nfc/doc/snippets/snippets.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +TARGET = nfc_cppsnippet +QT = core +#! [project modification] +QT += nfc +#! [project modification] + +SOURCES += main.cpp \ + doc_src_qtnfc.cpp \ + nfc.cpp \ + foorecord.cpp + +HEADERS += foorecord.h diff --git a/src/nfc/doc/src/nfc-cpp.qdoc b/src/nfc/doc/src/nfc-cpp.qdoc index 4df93e69..cbb07e0c 100644 --- a/src/nfc/doc/src/nfc-cpp.qdoc +++ b/src/nfc/doc/src/nfc-cpp.qdoc @@ -38,6 +38,6 @@ The \l{Qt NFC} C++ API enables an application to access NFC Forum Tags. To use the C++ library in your application, add the following configuration option to your \c .pro file: -\snippet doc_src_qtnfc.pro project modification +\snippet snippets.pro project modification */ diff --git a/src/nfc/doc/src/nfc-index.qdoc b/src/nfc/doc/src/nfc-index.qdoc index 2ec40891..2944a6ab 100644 --- a/src/nfc/doc/src/nfc-index.qdoc +++ b/src/nfc/doc/src/nfc-index.qdoc @@ -38,12 +38,14 @@ The NFC API provides APIs for interacting with NFC Forum Tags and NFC Forum Devi target detection and loss, registering NDEF message handlers, reading and writing NDEF messages on NFC Forum Tags and sending tag specific commands. +Currently the API is supported on BlackBerry 10. + \section1 Getting started To use the C++ library in your application, add the following configuration option to your \c .pro file: -\snippet doc_src_qtnfc.pro project modification +\snippet snippets.pro project modification To use the classes of the module in your application you need the following import statement in your \c .qml file: diff --git a/src/nfc/doc/src/nfc-overview.qdoc b/src/nfc/doc/src/nfc-overview.qdoc index b7d029bb..b068dfb5 100644 --- a/src/nfc/doc/src/nfc-overview.qdoc +++ b/src/nfc/doc/src/nfc-overview.qdoc @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com> +** 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 Qt Toolkit. @@ -36,14 +37,114 @@ With the Qt NFC API typical use cases are: \list - \li Detect NFC tags entering and leaving the communication range. - \li Read and write NDEF message on NFC Forum Tags. - \li Register an NDEF message handler for a particular content type. + \li Detecting NFC tags. + \li Reading and writing NDEF messages. + \li Registering NDEF message handlers. + \li Sharing files and messages. \endlist -The following sections describe how to use Qt NFC C++ classes for the above use cases. +The following sections describe how to use Qt NFC C++ classes and QML types for the above use cases. -\section1 Detect NFC tags entering and leaving communication range. -\section1 Read and write an NDEF message on NFC Forum Tags. -\section1 Register an NDEF message handler for a particular content type. +\section1 C++ Overview + +The C++ API provides access to the full feature set of the Qt NFC API. This section introduces the +major features available to developers. + +\section2 Detecting NFC Tags + +The \l QNearFieldManager class is responsible for the detection of new NFC tags coming +into range of the device. The \l QNearFieldManager::targetDetected() and +\l QNearFieldManager::targetLost() signals are emitted when +a tag comes into or leaves the range. The passed \l QNearFieldTarget parameter acts +as primary interaction point for each detected tag. The detection does not actually start though until +\l QNearFieldManager::startTargetDetection() has been called. + +\snippet ndefeditor/mainwindow.cpp QNearFieldManager init +\snippet ndefeditor/mainwindow.cpp QNearFieldManager start detection + +Finally the detection can be stopped: + +\snippet ndefeditor/mainwindow.cpp QNearFieldManager stop detection + +Although each \l QNearFieldTarget instance is owned by its related \l QNearFieldManager +instance it can be beneficial to manually delete each instance. Otherwise they would continue to +exist until the \l QNearFieldManager instance is deleted. The best way to do that would be in response +to the \l QNearFieldManager::targetLost() signal: + +\snippet ndefeditor/mainwindow.cpp QNearFieldTarget lost + +\note The target object should only be deleted via deleteLater() if it is deleted inside the slot. + +\section2 Reading and Writing NDEF Messages + +The \l QNearFieldTarget instance returned by \l QNearFieldManager::targetDetected() signal +is used to interact with the tag. Reading and writing a message is an asynchronous operation. +The \l QNearFieldTarget::RequestId class associates individual operations and their results. + +\snippet ndefeditor/mainwindow.cpp QNearFieldTarget detected + +Once the \l QNearFieldTarget::readNdefMessages() request was successfully processed, the +\l QNearFieldTarget::ndefMessageRead() signal is emitted. Each returned \l QNdefMessage +may consist of zero or more \l QNdefRecord entries, which can be identified by their type. +For more information about processing of records, see the \l QNdefRecord class documentation. +As the above code demonstrates, writing of NDEF messages is triggered via +\l QNearFieldTarget::writeNdefMessages(). The successful completion of the write operation +is indicated by the emission of the \l QNearFieldTarget::ndefMessagesWritten() signal. Any +type of error during read or write is indicated via \l QNearFieldTarget::error(). + +\section2 Registering NDEF Message Handlers + +The above described method (of reading NDEF messages) directly connects to the platform's NFC infrastructure. +However on some platforms (in particular mobile platforms) this may not actually trigger the target slot +if the application is currently running in the background. This is not desirable in cases where an +application wants to be activated if the platform detects a tag of particular type. +For this purpose the Qt NFC API provides the possibility to register an NDEF message handler. The handler +is called by the operating system, when the detected NDEF message matches the given filter criteria. +Depending on the platform it may even be possible to start the application that registered the handler. + +\note This feature is not available on all platforms and, in addition to the code snippets below, +may require further platform specific setup. + +\snippet annotatedurl/main.cpp QNearFieldManager register handler + +For comparison an application that uses an empty NDEF filter (match all behavior) in combination with +\l QNearFieldManager::registerNdefMessageHandler() would behave similarly to another application that uses +\l QNearFieldTarget::readNdefMessages() while being in the forground. For more information about +registration details of NDEF message handlers, see the +\l {QNearFieldManager#automatically-launching-ndef-message-handlers}{QNearFieldManager} class description. + +The content of \c handleMessage() may look like the snippet below. Any incoming NDEF message of type +\c text or \c uri will be processed: + +\snippet annotatedurl/annotatedurl.cpp handleMessage 1 +\snippet annotatedurl/annotatedurl.cpp handleMessage 2 +\snippet annotatedurl/annotatedurl.cpp handleMessage 3 +\snippet annotatedurl/annotatedurl.cpp handleMessage 4 + +\section2 Sharing Files and Messages + +Since Qt 5.3, Qt NFC provides a generic NFC share feature. If both devices support the same protocol, +the feature can be used to share files or NDEF messages. The advantage is that the two involved partners +can quickly establish a connection via NFC but transfer the data through, for example, Bluetooth or Wifi. +Effectively, this combines the low configuration effort of NFC with high data rate communication bearers +which usually require a much more complex setup. + +\note The API does not make any guarantees about the actual communication bearer used during the transfer. +The bearer is chosen based on the device's capabilities and the properties of the to-be-shared data. + +\l QNearFieldShareManager and \l QNearFieldShareTarget are responsible for accessing the NFC share feature. + +\section1 QML Overview + +The QML API only supports a very small subset of the Qt NFC feature set. This section outlines the available QML features. + +\section2 Reading NDEF Messages + +The user can specify NDEF filters and use those filters to register for the automatic reception of NDEF +messages which match those filters. The \l NearField::messageRecords property contains the list of NDEF records +of the last NDEF message read matching the given filters. + +\snippet doc_src_qtnfc.qml QML register for messages + +If no filter is set, the message handler will match all incoming NDEF messages. */ diff --git a/src/nfc/qnearfieldmanager.cpp b/src/nfc/qnearfieldmanager.cpp index f2fafdce..88656a6e 100644 --- a/src/nfc/qnearfieldmanager.cpp +++ b/src/nfc/qnearfieldmanager.cpp @@ -103,11 +103,7 @@ QT_BEGIN_NAMESPACE If the application has been registered as an NDEF message handler, the application only needs to call the registerNdefMessageHandler() function: - \code - QNearFieldManager *manager = new QNearFieldManager; - manager->registerNdefMessageHandler(this, - SLOT(handleNdefMessage(QNdefMessage,QNearFieldTarget))); - \endcode + \snippet doc_src_qtnfc.cpp handleNdefMessage On BlackBerry the registration for NDEF message handlers is done over the \l{https://developer.blackberry.com/native/documentation/core/invocation_framework.html}{Invocation Framework}. diff --git a/src/nfc/qnearfieldsharemanager.cpp b/src/nfc/qnearfieldsharemanager.cpp index b3e736b6..43b1634b 100644 --- a/src/nfc/qnearfieldsharemanager.cpp +++ b/src/nfc/qnearfieldsharemanager.cpp @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE \ingroup connectivity-nfc \inmodule QtNfc + \since 5.3 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. diff --git a/src/nfc/qnearfieldsharetarget.cpp b/src/nfc/qnearfieldsharetarget.cpp index 9ac66c5c..606090b5 100644 --- a/src/nfc/qnearfieldsharetarget.cpp +++ b/src/nfc/qnearfieldsharetarget.cpp @@ -58,9 +58,12 @@ QT_BEGIN_NAMESPACE \ingroup connectivity-nfc \inmodule QtNfc + \since 5.3 The QNearFieldShareTarget class can be used for sharing NDEF message or files to a remote NFC enabled device supporting the same protocol. + + \sa QNearFieldShareManager */ /*! diff --git a/src/src.pro b/src/src.pro index 7f37867e..e2ed3c88 100644 --- a/src/src.pro +++ b/src/src.pro @@ -7,6 +7,10 @@ bluetooth_doc_snippets.subdir = bluetooth/doc/snippets bluetooth_doc_snippets.depends = bluetooth SUBDIRS += bluetooth_doc_snippets +nfc_doc_snippets.subdir = nfc/doc/snippets +nfc_doc_snippets.depends = nfc +SUBDIRS += nfc_doc_snippets + qtHaveModule(quick) { imports.depends += bluetooth nfc SUBDIRS += imports |