summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2015-12-01 22:50:29 +0100
committerLiang Qi <liang.qi@theqtcompany.com>2015-12-01 22:50:29 +0100
commit4cafd5cac8e920c6decbb974bf548e9c8f935d24 (patch)
treef7bbb167250fcc62fc415d7b01368e75349e18e6
parent1ebd4d02a67a162411af88b26c899bfb8cf871ca (diff)
parentecf8e597a21013936ea4fe195113141bca848f9a (diff)
Merge remote-tracking branch 'origin/5.6' into dev
-rw-r--r--src/bluetooth/bluetooth.pro3
-rw-r--r--src/bluetooth/osx/osxbtledeviceinquiry.mm325
-rw-r--r--src/bluetooth/osx/osxbtledeviceinquiry_p.h73
-rw-r--r--src/bluetooth/osx/osxbtutility.mm41
-rw-r--r--src/bluetooth/osx/osxbtutility_p.h4
-rw-r--r--src/bluetooth/qbluetoothaddress.cpp15
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm231
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm177
-rw-r--r--src/bluetooth/qbluetoothdeviceinfo.cpp6
-rw-r--r--src/bluetooth/qbluetoothlocaldevice.cpp11
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_android.cpp2
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_bluez.cpp2
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_osx.mm2
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.cpp4
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.h2
-rw-r--r--src/bluetooth/qbluetoothuuid.cpp29
-rw-r--r--src/bluetooth/qlowenergycontroller.cpp11
-rw-r--r--src/bluetooth/qlowenergycontroller_android.cpp1
-rw-r--r--src/bluetooth/qlowenergycontroller_bluez.cpp7
-rw-r--r--src/bluetooth/qlowenergycontroller_osx.mm16
-rw-r--r--src/bluetooth/qlowenergycontroller_p.cpp1
-rw-r--r--src/bluetooth/qlowenergycontroller_p.h2
-rw-r--r--src/src.pro5
-rw-r--r--tests/auto/qbluetoothserver/qbluetoothserver.pro1
-rw-r--r--tests/auto/qlowenergycharacteristic/qlowenergycharacteristic.pro1
-rw-r--r--tests/auto/qlowenergycontroller/qlowenergycontroller.pro1
-rw-r--r--tests/auto/qlowenergydescriptor/qlowenergydescriptor.pro2
27 files changed, 533 insertions, 442 deletions
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro
index e37ad7aa..6cf0795c 100644
--- a/src/bluetooth/bluetooth.pro
+++ b/src/bluetooth/bluetooth.pro
@@ -164,7 +164,8 @@ config_bluez:qtHaveModule(dbus) {
qlowenergyservice_osx.mm
PRIVATE_HEADERS += \
- qlowenergycontroller_osx_p.h
+ qlowenergycontroller_osx_p.h \
+ qbluetoothdevicediscoverytimer_osx_p.h
include(osx/osxbt.pri)
SOURCES += \
diff --git a/src/bluetooth/osx/osxbtledeviceinquiry.mm b/src/bluetooth/osx/osxbtledeviceinquiry.mm
index 28bfd1bc..f3a95820 100644
--- a/src/bluetooth/osx/osxbtledeviceinquiry.mm
+++ b/src/bluetooth/osx/osxbtledeviceinquiry.mm
@@ -46,10 +46,6 @@ QT_BEGIN_NAMESPACE
namespace OSXBluetooth {
-LEDeviceInquiryDelegate::~LEDeviceInquiryDelegate()
-{
-}
-
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_6_0)
QBluetoothUuid qt_uuid(NSUUID *nsUuid)
@@ -107,32 +103,19 @@ using namespace QT_NAMESPACE;
#endif
-@interface QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) (PrivateAPI) <CBCentralManagerDelegate, CBPeripheralDelegate>
-// "Timeout" callback to stop a scan.
+@interface QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) (PrivateAPI) <CBCentralManagerDelegate>
- (void)stopScan;
-- (void)handlePoweredOffAfterDelay;
+- (void)handlePoweredOff;
@end
@implementation QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry)
-+ (int)inquiryLength
-{
- // There is no default timeout,
- // scan does not stop if not asked.
- // Return in milliseconds
- return 10 * 1000;
-}
-
-- (id)initWithDelegate:(OSXBluetooth::LEDeviceInquiryDelegate *)aDelegate
+- (id)init
{
- Q_ASSERT_X(aDelegate, Q_FUNC_INFO, "invalid delegate (null)");
-
if (self = [super init]) {
- delegate = aDelegate;
- peripherals = [[NSMutableDictionary alloc] init];
- manager = nil;
- scanPhase = noActivity;
- cancelled = false;
+ uuids.reset([[NSMutableSet alloc] init]);
+ internalState = InquiryStarting;
+ state.store(int(internalState));
}
return self;
@@ -140,150 +123,137 @@ using namespace QT_NAMESPACE;
- (void)dealloc
{
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
-
if (manager) {
[manager setDelegate:nil];
- if (scanPhase == activeScan)
+ if (internalState == InquiryActive)
[manager stopScan];
- [manager release];
}
- [peripherals release];
[super dealloc];
}
- (void)stopScan
{
- // Scan's timeout.
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
- Q_ASSERT_X(manager, Q_FUNC_INFO, "invalid central (nil)");
- Q_ASSERT_X(scanPhase == activeScan, Q_FUNC_INFO, "invalid state");
- Q_ASSERT_X(!cancelled, Q_FUNC_INFO, "invalid state");
-
- [manager setDelegate:nil];
- [manager stopScan];
- scanPhase = noActivity;
-
- delegate->LEdeviceInquiryFinished();
-}
+ // Scan's "timeout" - we consider LE device
+ // discovery finished.
+ using namespace OSXBluetooth;
-- (void)handlePoweredOffAfterDelay
-{
- // If we are here, this means:
- // we received 'PoweredOff' while scanPhase == startingScan
- // and no 'PoweredOn' after this.
-
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
- Q_ASSERT_X(scanPhase == startingScan, Q_FUNC_INFO, "invalid state");
-
- scanPhase = noActivity;
- if (cancelled) {
- // Timeout happened before
- // the second status update, but after 'stop'.
- delegate->LEdeviceInquiryFinished();
- } else {
- // Timeout and no 'stop' between 'start'
- // and 'centralManagerDidUpdateStatus':
- delegate->LEnotSupported();
+ if (internalState == InquiryActive) {
+ if (scanTimer.elapsed() >= qt_LE_deviceInquiryLength() * 1000) {
+ // We indeed stop now:
+ [manager stopScan];
+ [manager setDelegate:nil];
+ internalState = InquiryFinished;
+ state.store(int(internalState));
+ } else {
+ dispatch_queue_t leQueue(qt_LE_queue());
+ Q_ASSERT(leQueue);
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
+ int64_t(qt_LE_deviceInquiryLength() / 100. * NSEC_PER_SEC)),
+ leQueue,
+ ^{
+ [self stopScan];
+ });
+ }
}
}
-- (bool)start
+- (void)handlePoweredOff
{
- Q_ASSERT_X(![self isActive], Q_FUNC_INFO, "LE device scan is already active");
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
-
- if (!peripherals) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "internal error";
- return false;
- }
-
- cancelled = false;
- [peripherals removeAllObjects];
+ // This is interesting on iOS only, where
+ // the system shows an alert asking to enable
+ // Bluetooth in the 'Settings' app. If not done yet (after 30
+ // seconds) - we consider it an error.
+ if (internalState == InquiryStarting) {
+ if (errorTimer.elapsed() >= 30000) {
+ [manager setDelegate:nil];
+ internalState = ErrorPoweredOff;
+ state.store(int(internalState));
+ } else {
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ Q_ASSERT(leQueue);
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
+ (int64_t)(30 / 100. * NSEC_PER_SEC)),
+ leQueue,
+ ^{
+ [self handlePoweredOff];
+ });
- if (manager) {
- // We can never be here, if status was not updated yet.
- [manager setDelegate:nil];
- [manager release];
+ }
}
+}
- startTime = QTime();
- scanPhase = startingScan;
- manager = [CBCentralManager alloc];
- manager = [manager initWithDelegate:self queue:nil];
- if (!manager) {
- qCCritical(QT_BT_OSX) << Q_FUNC_INFO << "failed to create a central manager";
- return false;
- }
+- (void)start
+{
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
- return true;
+ Q_ASSERT(leQueue);
+ manager.reset([[CBCentralManager alloc] initWithDelegate:self queue:leQueue]);
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
-
- const CBCentralManagerState state = central.state;
-
- if (scanPhase == startingScan && (state == CBCentralManagerStatePoweredOn
- || state == CBCentralManagerStateUnsupported
- || state == CBCentralManagerStateUnauthorized
- || state == CBCentralManagerStatePoweredOff)) {
- // We probably had 'PoweredOff' before,
- // cancel the previous handlePoweredOffAfterDelay.
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
- }
+ if (central != manager)
+ return;
- if (cancelled) {
- Q_ASSERT_X(scanPhase != activeScan, Q_FUNC_INFO, "in 'activeScan' phase");
- scanPhase = noActivity;
- delegate->LEdeviceInquiryFinished();
+ if (internalState != InquiryActive && internalState != InquiryStarting)
return;
- }
- if (state == CBCentralManagerStatePoweredOn) {
- if (scanPhase == startingScan) {
- scanPhase = activeScan;
-#ifndef Q_OS_OSX
- const NSTimeInterval timeout([QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) inquiryLength] / 1000);
- Q_ASSERT_X(timeout > 0., Q_FUNC_INFO, "invalid scan timeout");
- [self performSelector:@selector(stopScan) withObject:nil afterDelay:timeout];
-#endif
- startTime = QTime::currentTime();
+ using namespace OSXBluetooth;
+
+ dispatch_queue_t leQueue(qt_LE_queue());
+ Q_ASSERT(leQueue);
+
+ const CBCentralManagerState cbState(central.state);
+ if (cbState == CBCentralManagerStatePoweredOn) {
+ if (internalState == InquiryStarting) {
+ internalState = InquiryActive;
+ // Scan time is actually 10 seconds. Having a block with such delay can prevent
+ // 'self' from being deleted in time, which is not good. So we split this
+ // 10 s. timeout into smaller 'chunks'.
+ scanTimer.start();
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
+ int64_t(qt_LE_deviceInquiryLength() / 100. * NSEC_PER_SEC)),
+ leQueue,
+ ^{
+ [self stopScan];
+ });
[manager scanForPeripheralsWithServices:nil options:nil];
} // Else we ignore.
} else if (state == CBCentralManagerStateUnsupported || state == CBCentralManagerStateUnauthorized) {
- if (scanPhase == startingScan) {
- scanPhase = noActivity;
- delegate->LEnotSupported();
- } else if (scanPhase == activeScan) {
- // Cancel stopScan:
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
-
- scanPhase = noActivity;
+ if (internalState == InquiryActive) {
[manager stopScan];
- delegate->LEdeviceInquiryError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
+ // Not sure how this is possible at all, probably, can never happen.
+ internalState = ErrorPoweredOff;
+ } else {
+ internalState = ErrorLENotSupported;
}
- } else if (state == CBCentralManagerStatePoweredOff) {
- if (scanPhase == startingScan) {
+
+ [manager setDelegate:nil];
+ } else if (cbState == CBCentralManagerStatePoweredOff) {
+ if (internalState == InquiryStarting) {
#ifndef Q_OS_OSX
// On iOS a user can see at this point an alert asking to enable
// Bluetooth in the "Settings" app. If a user does,
// we'll receive 'PoweredOn' state update later.
- [self performSelector:@selector(handlePoweredOffAfterDelay) withObject:nil afterDelay:30.];
+ // No change in state. Wait for 30 seconds (we split it into 'chunks' not
+ // to retain 'self' for too long ) ...
+ errorTimer.start();
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
+ (int64_t)(30 / 100. * NSEC_PER_SEC)),
+ leQueue,
+ ^{
+ [self handlePoweredOff];
+ });
return;
#endif
- scanPhase = noActivity;
- delegate->LEnotSupported();
- } else if (scanPhase == activeScan) {
- // Cancel stopScan:
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
-
- scanPhase = noActivity;
+ internalState = ErrorPoweredOff;
+ } else {
+ internalState = ErrorPoweredOff;
[manager stopScan];
- delegate->LEdeviceInquiryError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
- } // Else we ignore.
+ }
+
+ [manager setDelegate:nil];
} else {
// The following two states we ignore (from Apple's docs):
//"
@@ -294,44 +264,36 @@ using namespace QT_NAMESPACE;
// -CBCentralManagerStateResetting
// The connection with the system service was momentarily
// lost; an update is imminent. "
+ // Wait for this imminent update.
}
+
+ state.store(int(internalState));
}
- (void)stop
{
- if (scanPhase != startingScan) {
- // startingScan means either no selector at all,
- // or handlePoweredOffAfterDelay and we do not want to cancel it yet,
- // waiting for DidUpdateState or handlePoweredOffAfterDelay, whoever
- // fires first ...
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
- }
-
- if (scanPhase == startingScan || cancelled) {
- // We have to wait for a status update or handlePoweredOffAfterDelay.
- cancelled = true;
- return;
- }
-
- if (scanPhase == activeScan) {
+ if (internalState == InquiryActive)
[manager stopScan];
- scanPhase = noActivity;
- delegate->LEdeviceInquiryFinished();
- }
+
+ [manager setDelegate:nil];
+ internalState = InquiryCancelled;
+ state.store(int(internalState));
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
- Q_UNUSED(central)
- Q_UNUSED(advertisementData)
+ Q_UNUSED(advertisementData);
using namespace OSXBluetooth;
- if (scanPhase != activeScan)
+ if (central != manager)
return;
- Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
+ if (internalState != InquiryActive)
+ return;
+
+ QBluetoothUuid deviceUuid;
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_7_0)
if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_9, QSysInfo::MV_IOS_7_0)) {
@@ -340,45 +302,64 @@ using namespace QT_NAMESPACE;
return;
}
- if (![peripherals objectForKey:peripheral.identifier]) {
- [peripherals setObject:peripheral forKey:peripheral.identifier];
- const QBluetoothUuid deviceUuid(OSXBluetooth::qt_uuid(peripheral.identifier));
- delegate->LEdeviceFound(peripheral, deviceUuid, advertisementData, RSSI);
+ if ([uuids containsObject:peripheral.identifier]) {
+ // We already know this peripheral ...
+ return;
}
- return;
+
+ [uuids addObject:peripheral.identifier];
+ deviceUuid = OSXBluetooth::qt_uuid(peripheral.identifier);
}
#endif
// Either SDK or the target is below 10.9/7.0:
// The property UUID was finally removed in iOS 9, we have
// to avoid compilation errors ...
- CFUUIDRef cfUUID = Q_NULLPTR;
+ if (deviceUuid.isNull()) {
+ CFUUIDRef cfUUID = Q_NULLPTR;
+
+ if ([peripheral respondsToSelector:@selector(UUID)]) {
+ // This will require a bridged cast if we switch to ARC ...
+ cfUUID = reinterpret_cast<CFUUIDRef>([peripheral performSelector:@selector(UUID)]);
+ }
- if ([peripheral respondsToSelector:@selector(UUID)]) {
- // This will require a bridged cast if we switch to ARC ...
- cfUUID = reinterpret_cast<CFUUIDRef>([peripheral performSelector:@selector(UUID)]);
+ if (!cfUUID) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "peripheral without CFUUID";
+ return;
+ }
+
+ StringStrongReference key(uuid_as_nsstring(cfUUID));
+ if ([uuids containsObject:key.data()])
+ return; // We've seen this peripheral before ...
+ [uuids addObject:key.data()];
+ deviceUuid = OSXBluetooth::qt_uuid(cfUUID);
}
- if (!cfUUID) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "peripheral without CFUUID";
+ if (deviceUuid.isNull()) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "no way to address peripheral, QBluetoothUuid is null";
return;
}
- StringStrongReference key(uuid_as_nsstring(cfUUID));
- if (![peripherals objectForKey:key.data()]) {
- [peripherals setObject:peripheral forKey:key.data()];
- const QBluetoothUuid deviceUuid(OSXBluetooth::qt_uuid(cfUUID));
- delegate->LEdeviceFound(peripheral, deviceUuid, advertisementData, RSSI);
- }
+ QString name;
+ if (peripheral.name)
+ name = QString::fromNSString(peripheral.name);
+
+ // TODO: fix 'classOfDevice' (0 for now).
+ QBluetoothDeviceInfo newDeviceInfo(deviceUuid, name, 0);
+ if (RSSI)
+ newDeviceInfo.setRssi([RSSI shortValue]);
+ // CoreBluetooth scans only for LE devices.
+ newDeviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
+ devices.append(newDeviceInfo);
}
-- (bool)isActive
+- (LEInquiryState) inquiryState
{
- return scanPhase == startingScan || scanPhase == activeScan;
+ return LEInquiryState(state.load());
}
-- (const QTime&)startTime
+- (const QList<QBluetoothDeviceInfo> &)discoveredDevices
{
- return startTime;
+ return devices;
}
@end
diff --git a/src/bluetooth/osx/osxbtledeviceinquiry_p.h b/src/bluetooth/osx/osxbtledeviceinquiry_p.h
index cb86cd14..9ca299ea 100644
--- a/src/bluetooth/osx/osxbtledeviceinquiry_p.h
+++ b/src/bluetooth/osx/osxbtledeviceinquiry_p.h
@@ -46,80 +46,59 @@
//
#include "qbluetoothdevicediscoveryagent.h"
+#include "qbluetoothdeviceinfo.h"
+#include "osxbtutility_p.h"
-#include <QtCore/qdatetime.h>
+#include <QtCore/qelapsedtimer.h>
#include <QtCore/qglobal.h>
+#include <QtCore/qatomic.h>
#include <QtCore/qlist.h>
#include <Foundation/Foundation.h>
-@class QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry);
-
@class CBCentralManager;
@class CBPeripheral;
QT_BEGIN_NAMESPACE
-class QBluetoothDeviceInfo;
class QBluetoothUuid;
-namespace OSXBluetooth {
-
-class LEDeviceInquiryDelegate
-{
-public:
- typedef QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) LEDeviceInquiryObjC;
-
- virtual ~LEDeviceInquiryDelegate();
-
- // At the moment the only error we're reporting is PoweredOffError!
- virtual void LEdeviceInquiryError(QBluetoothDeviceDiscoveryAgent::Error error) = 0;
-
- virtual void LEnotSupported() = 0;
- virtual void LEdeviceFound(CBPeripheral *peripheral, const QBluetoothUuid &uuid,
- NSDictionary *advertisementData, NSNumber *RSSI) = 0;
- virtual void LEdeviceInquiryFinished() = 0;
-};
-
-}
-
QT_END_NAMESPACE
-// Bluetooth Low Energy scan for iOS and OS X.
-// Strong enum would be quite handy ...
-enum LEScanPhase
+enum LEInquiryState
{
- noActivity,
- startingScan,
- activeScan
+ InquiryStarting,
+ InquiryActive,
+ InquiryFinished,
+ InquiryCancelled,
+ ErrorPoweredOff,
+ ErrorLENotSupported
};
@interface QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) : NSObject
-{// Protocols are adopted in the mm file.
- QT_PREPEND_NAMESPACE(OSXBluetooth)::LEDeviceInquiryDelegate *delegate;
+{
+ QT_PREPEND_NAMESPACE(OSXBluetooth)::ObjCScopedPointer<NSMutableSet> uuids;
+ QT_PREPEND_NAMESPACE(OSXBluetooth)::ObjCScopedPointer<CBCentralManager> manager;
- // TODO: scoped pointers/shared pointers?
- NSMutableDictionary *peripherals; // Found devices.
- CBCentralManager *manager;
+ QList<QBluetoothDeviceInfo> devices;
- LEScanPhase scanPhase;
- bool cancelled;
- QTime startTime;
-}
+ LEInquiryState internalState;
+ QT_PREPEND_NAMESPACE(QAtomicInt) state;
-// Inquiry length in milliseconds.
-+ (int)inquiryLength;
+ // Timers to check if we can execute delayed callbacks:
+ QT_PREPEND_NAMESPACE(QElapsedTimer) errorTimer;
+ QT_PREPEND_NAMESPACE(QElapsedTimer) scanTimer;
+}
-- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(OSXBluetooth)::LEDeviceInquiryDelegate *)aDelegate;
+- (id)init;
- (void)dealloc;
-// Actual scan can be delayed - we have to wait for a status update first.
-- (bool)start;
-// Stop can be delayed - if we're waiting for a status update.
+// IMPORTANT: both 'start' and 'stop' are to be executed on the "Qt's LE queue".
+- (void)start;
- (void)stop;
-- (bool)isActive;
-- (const QTime &)startTime;
+- (LEInquiryState)inquiryState;
+- (const QList<QBluetoothDeviceInfo> &)discoveredDevices;
@end
diff --git a/src/bluetooth/osx/osxbtutility.mm b/src/bluetooth/osx/osxbtutility.mm
index a5d3d936..08ff699d 100644
--- a/src/bluetooth/osx/osxbtutility.mm
+++ b/src/bluetooth/osx/osxbtutility.mm
@@ -305,6 +305,47 @@ ObjCStrongReference<NSData> data_from_bytearray(const QByteArray & qtData)
return result;
}
+// A small RAII class for a dispatch queue.
+class SerialDispatchQueue
+{
+public:
+ explicit SerialDispatchQueue(const char *label)
+ {
+ Q_ASSERT(label);
+
+ queue = dispatch_queue_create(label, DISPATCH_QUEUE_SERIAL);
+ if (!queue) {
+ qCCritical(QT_BT_OSX) << "failed to create dispatch queue with label"
+ << label;
+ }
+ }
+ ~SerialDispatchQueue()
+ {
+ if (queue)
+ dispatch_release(queue);
+ }
+
+ dispatch_queue_t data() const
+ {
+ return queue;
+ }
+private:
+ dispatch_queue_t queue;
+
+ Q_DISABLE_COPY(SerialDispatchQueue)
+};
+
+dispatch_queue_t qt_LE_queue()
+{
+ static const SerialDispatchQueue leQueue("qt-bluetooth-LE-queue");
+ return leQueue.data();
+}
+
+unsigned qt_LE_deviceInquiryLength()
+{
+ return 10;
+}
+
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/osx/osxbtutility_p.h b/src/bluetooth/osx/osxbtutility_p.h
index a69e05c2..3506b0d1 100644
--- a/src/bluetooth/osx/osxbtutility_p.h
+++ b/src/bluetooth/osx/osxbtutility_p.h
@@ -306,6 +306,10 @@ inline QSysInfo::MacVersion qt_OS_limit(QSysInfo::MacVersion osxVersion, QSysInf
#endif
}
+dispatch_queue_t qt_LE_queue();
+// LE scan, in seconds.
+unsigned qt_LE_deviceInquiryLength();
+
} // namespace OSXBluetooth
// Logging category for both OS X and iOS.
diff --git a/src/bluetooth/qbluetoothaddress.cpp b/src/bluetooth/qbluetoothaddress.cpp
index 8e3c29c6..5a0abf45 100644
--- a/src/bluetooth/qbluetoothaddress.cpp
+++ b/src/bluetooth/qbluetoothaddress.cpp
@@ -59,15 +59,13 @@ QT_BEGIN_NAMESPACE
Returns true if the Bluetooth addresses are not equal, otherwise returns false.
*/
-namespace {
-class BluetoothAddressRegisterMetaTypes
+static void registerQBluetoothAddressMetaType()
{
-public:
- BluetoothAddressRegisterMetaTypes()
- {
+ static bool initDone = false;
+ if (!initDone) {
qRegisterMetaType<QBluetoothAddress>();
+ initDone = true;
}
-} _registerBluetoothAddressMetaTypes;
}
/*!
@@ -76,6 +74,7 @@ public:
QBluetoothAddress::QBluetoothAddress() :
d_ptr(new QBluetoothAddressPrivate)
{
+ registerQBluetoothAddressMetaType();
}
/*!
@@ -84,6 +83,8 @@ QBluetoothAddress::QBluetoothAddress() :
QBluetoothAddress::QBluetoothAddress(quint64 address) :
d_ptr(new QBluetoothAddressPrivate)
{
+ registerQBluetoothAddressMetaType();
+
Q_D(QBluetoothAddress);
d->m_address = address;
}
@@ -97,6 +98,8 @@ QBluetoothAddress::QBluetoothAddress(quint64 address) :
QBluetoothAddress::QBluetoothAddress(const QString &address) :
d_ptr(new QBluetoothAddressPrivate)
{
+ registerQBluetoothAddressMetaType();
+
Q_D(QBluetoothAddress);
QString a = address;
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
index 1556c5f9..30a6acb6 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
@@ -31,6 +31,7 @@
**
****************************************************************************/
+#include "qbluetoothdevicediscoverytimer_osx_p.h"
#include "qbluetoothdevicediscoveryagent.h"
#include "osx/osxbtledeviceinquiry_p.h"
#include "qbluetoothlocaldevice.h"
@@ -51,27 +52,29 @@ QT_BEGIN_NAMESPACE
using OSXBluetooth::ObjCScopedPointer;
-class QBluetoothDeviceDiscoveryAgentPrivate : public OSXBluetooth::LEDeviceInquiryDelegate
+class QBluetoothDeviceDiscoveryAgentPrivate
{
friend class QBluetoothDeviceDiscoveryAgent;
+ friend class OSXBluetooth::DDATimerHandler;
+
public:
QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &address,
QBluetoothDeviceDiscoveryAgent *q);
virtual ~QBluetoothDeviceDiscoveryAgentPrivate();
- bool isValid() const;
bool isActive() const;
void start();
void stop();
private:
- // LEDeviceInquiryDelegate:
- void LEdeviceInquiryError(QBluetoothDeviceDiscoveryAgent::Error error) Q_DECL_OVERRIDE;
- void LEnotSupported() Q_DECL_OVERRIDE;
- void LEdeviceFound(CBPeripheral *peripheral, const QBluetoothUuid &deviceUuid,
- NSDictionary *advertisementData, NSNumber *RSSI) Q_DECL_OVERRIDE;
- void LEdeviceInquiryFinished() Q_DECL_OVERRIDE;
+ typedef QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) LEDeviceInquiryObjC;
+
+ void LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error);
+ void LEnotSupported();
+ void LEdeviceFound(const QBluetoothDeviceInfo &info);
+ void LEinquiryFinished();
+ void checkLETimeout();
void setError(QBluetoothDeviceDiscoveryAgent::Error, const QString &text = QString());
@@ -90,8 +93,45 @@ private:
bool startPending;
bool stopPending;
+
+ QScopedPointer<OSXBluetooth::DDATimerHandler> timer;
};
+namespace OSXBluetooth {
+
+DDATimerHandler::DDATimerHandler(QBluetoothDeviceDiscoveryAgentPrivate *d)
+ : owner(d)
+{
+ Q_ASSERT_X(owner, Q_FUNC_INFO, "invalid pointer");
+
+ timer.setSingleShot(false);
+ connect(&timer, &QTimer::timeout, this, &DDATimerHandler::onTimer);
+}
+
+void DDATimerHandler::start(int msec)
+{
+ Q_ASSERT_X(msec > 0, Q_FUNC_INFO, "invalid time interval");
+ if (timer.isActive()) {
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "timer is active";
+ return;
+ }
+
+ timer.start(msec);
+}
+
+void DDATimerHandler::stop()
+{
+ timer.stop();
+}
+
+void DDATimerHandler::onTimer()
+{
+ Q_ASSERT(owner);
+ owner->checkLETimeout();
+}
+
+}
+
QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &adapter,
QBluetoothDeviceDiscoveryAgent *q) :
q_ptr(q),
@@ -103,29 +143,20 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(con
Q_UNUSED(adapter);
Q_ASSERT_X(q != Q_NULLPTR, Q_FUNC_INFO, "invalid q_ptr (null)");
-
- // OSXBTLEDeviceInquiry can be constructed even if LE is not supported -
- // at this stage it's only a memory allocation of the object itself,
- // if it fails - we have some memory-related problems.
- LEDeviceInquiry newInquiryLE([[LEDeviceInquiryObjC alloc] initWithDelegate:this]);
- if (!newInquiryLE) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to initialize a device inquiry object";
- return;
- }
-
- inquiryLE.reset(newInquiryLE.take());
}
QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
{
-}
-
-bool QBluetoothDeviceDiscoveryAgentPrivate::isValid() const
-{
- // isValid() - Qt does not use exceptions, but the ctor
- // can fail to initialize some important data-members
- // - this is what meant here by valid/invalid.
- return inquiryLE;
+ if (inquiryLE) {
+ // We want the LE scan to stop as soon as possible.
+ if (dispatch_queue_t leQueue = OSXBluetooth::qt_LE_queue()) {
+ // Local variable to be retained ...
+ LEDeviceInquiryObjC *inq = inquiryLE.data();
+ dispatch_async(leQueue, ^{
+ [inq stop];
+ });
+ }
+ }
}
bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
@@ -135,50 +166,66 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
if (stopPending)
return false;
- return [inquiryLE isActive];
+ return inquiryLE;
}
void QBluetoothDeviceDiscoveryAgentPrivate::start()
{
- Q_ASSERT_X(isValid(), Q_FUNC_INFO, "called on invalid device discovery agent");
Q_ASSERT_X(!isActive(), Q_FUNC_INFO, "called on active device discovery agent");
- Q_ASSERT_X(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError,
- Q_FUNC_INFO, "called with an invalid Bluetooth adapter");
if (stopPending) {
startPending = true;
return;
}
- discoveredDevices.clear();
- setError(QBluetoothDeviceDiscoveryAgent::NoError);
+ using namespace OSXBluetooth;
- if (![inquiryLE start]) {
- // We can be here only if we have some kind of
- // resource allocation error.
+ inquiryLE.reset([[LEDeviceInquiryObjC alloc] init]);
+ dispatch_queue_t leQueue(qt_LE_queue());
+ if (!leQueue || !inquiryLE) {
setError(QBluetoothDeviceDiscoveryAgent::UnknownError,
QCoreApplication::translate(DEV_DISCOVERY, DD_NOT_STARTED));
emit q_ptr->error(lastError);
}
+
+ discoveredDevices.clear();
+ setError(QBluetoothDeviceDiscoveryAgent::NoError);
+
+ // CoreBluetooth does not have a timeout. We start a timer here
+ // and check if scan really started and if yes if we have a timeout.
+ timer.reset(new OSXBluetooth::DDATimerHandler(this));
+ timer->start(2000);
+
+ // Create a local variable - to have a strong referece in a block.
+ LEDeviceInquiryObjC *inq = inquiryLE.data();
+ dispatch_async(leQueue, ^{
+ [inq start];
+ });
}
void QBluetoothDeviceDiscoveryAgentPrivate::stop()
{
- Q_ASSERT_X(isValid(), Q_FUNC_INFO, "called on invalid device discovery agent");
Q_ASSERT_X(isActive(), Q_FUNC_INFO, "called whithout active inquiry");
- Q_ASSERT_X(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError,
- Q_FUNC_INFO, "called with invalid bluetooth adapter");
startPending = false;
stopPending = true;
+ dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
+ Q_ASSERT(leQueue);
+
setError(QBluetoothDeviceDiscoveryAgent::NoError);
- // Can be asynchronous (depending on a status update of CBCentralManager).
- // The call itself is always 'success'.
- [inquiryLE stop];
+
+ // Create a local variable - to have a strong referece in a block.
+ LEDeviceInquiryObjC *inq = inquiryLE.data();
+ dispatch_async(leQueue, ^{
+ [inq stop];
+ });
+ // We consider LE scan to be stopped immediately and
+ // do not care about this LEDeviceInquiry object anymore.
+ LEinquiryFinished();
}
-void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceInquiryError(QBluetoothDeviceDiscoveryAgent::Error error)
+void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error)
{
// At the moment the only error reported by osxbtledeviceinquiry
// can be 'powered off' error, it happens
@@ -187,6 +234,9 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceInquiryError(QBluetoothDevic
Q_ASSERT_X(error == QBluetoothDeviceDiscoveryAgent::PoweredOffError,
Q_FUNC_INFO, "unexpected error");
+ inquiryLE.reset();
+ timer->stop();
+
startPending = false;
stopPending = false;
setError(error);
@@ -195,36 +245,17 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceInquiryError(QBluetoothDevic
void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported()
{
+ inquiryLE.reset();
+ timer->stop();
+
startPending = false;
stopPending = false;
setError(QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError);
emit q_ptr->error(lastError);
}
-void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound(CBPeripheral *peripheral, const QBluetoothUuid &deviceUuid,
- NSDictionary *advertisementData,
- NSNumber *RSSI)
+void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound(const QBluetoothDeviceInfo &newDeviceInfo)
{
- Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)");
-
- QT_BT_MAC_AUTORELEASEPOOL;
-
- QString name;
- if (peripheral.name && peripheral.name.length) {
- name = QString::fromNSString(peripheral.name);
- } else {
- NSString *const localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
- if (localName && [localName length])
- name = QString::fromNSString(localName);
- }
-
- // TODO: fix 'classOfDevice' (0 for now).
- QBluetoothDeviceInfo newDeviceInfo(deviceUuid, name, 0);
- if (RSSI)
- newDeviceInfo.setRssi([RSSI shortValue]);
- // CoreBluetooth scans only for LE devices.
- newDeviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
-
// Update, append or discard.
for (int i = 0, e = discoveredDevices.size(); i < e; ++i) {
if (discoveredDevices[i].deviceUuid() == newDeviceInfo.deviceUuid()) {
@@ -241,9 +272,10 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound(CBPeripheral *peripher
emit q_ptr->deviceDiscovered(newDeviceInfo);
}
-void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceInquiryFinished()
+void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished()
{
- Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid device discovery agent");
+ inquiryLE.reset();
+ timer->stop();
if (stopPending && !startPending) {
stopPending = false;
@@ -257,6 +289,41 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceInquiryFinished()
}
}
+void QBluetoothDeviceDiscoveryAgentPrivate::checkLETimeout()
+{
+ Q_ASSERT_X(inquiryLE, Q_FUNC_INFO, "LE device inquiry is nil");
+
+ using namespace OSXBluetooth;
+
+ const LEInquiryState state([inquiryLE inquiryState]);
+ if (state == InquiryStarting || state == InquiryActive)
+ return; // Wait ...
+
+ if (state == ErrorPoweredOff)
+ return LEinquiryError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
+
+ if (state == ErrorLENotSupported)
+ return LEnotSupported();
+
+ if (state == InquiryFinished) {
+ // Process found devices if any ...
+ const QList<QBluetoothDeviceInfo> leDevices([inquiryLE discoveredDevices]);
+ foreach (const QBluetoothDeviceInfo &info, leDevices) {
+ // We were cancelled on a previous device discovered signal ...
+ if (!inquiryLE)
+ break;
+ LEdeviceFound(info);
+ }
+
+ if (inquiryLE)
+ LEinquiryFinished();
+ return;
+ }
+
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unexpected inquiry state in LE timeout";
+ // Actually, this deserves an assert :)
+}
+
void QBluetoothDeviceDiscoveryAgentPrivate::setError(QBluetoothDeviceDiscoveryAgent::Error error,
const QString &text)
{
@@ -329,36 +396,22 @@ QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices()
void QBluetoothDeviceDiscoveryAgent::start()
{
if (d_ptr->lastError != InvalidBluetoothAdapterError) {
- if (d_ptr->isValid()) {
- if (!isActive())
- d_ptr->start();
- else
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "already started";
- } else {
- // We previously failed to initialize
- // private object correctly.
- d_ptr->setError(InvalidBluetoothAdapterError);
- emit error(InvalidBluetoothAdapterError);
- }
+ if (!isActive())
+ d_ptr->start();
+ else
+ qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "already started";
}
}
void QBluetoothDeviceDiscoveryAgent::stop()
{
- if (d_ptr->isValid()) {
- if (isActive() && d_ptr->lastError != InvalidBluetoothAdapterError)
- d_ptr->stop();
- else
- qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "failed to stop";
- }
+ if (isActive() && d_ptr->lastError != InvalidBluetoothAdapterError)
+ d_ptr->stop();
}
bool QBluetoothDeviceDiscoveryAgent::isActive() const
{
- if (d_ptr->isValid())
- return d_ptr->isActive();
-
- return false;
+ return d_ptr->isActive();
}
QBluetoothDeviceDiscoveryAgent::Error QBluetoothDeviceDiscoveryAgent::error() const
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
index ebf9352d..1cfe8286 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
@@ -44,6 +44,7 @@
#include "qbluetoothuuid.h"
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qscopedpointer.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
@@ -58,15 +59,16 @@ QT_BEGIN_NAMESPACE
using OSXBluetooth::ObjCScopedPointer;
-class QBluetoothDeviceDiscoveryAgentPrivate : public OSXBluetooth::DeviceInquiryDelegate,
- public OSXBluetooth::LEDeviceInquiryDelegate
+class QBluetoothDeviceDiscoveryAgentPrivate : public OSXBluetooth::DeviceInquiryDelegate
{
friend class QBluetoothDeviceDiscoveryAgent;
friend class OSXBluetooth::DDATimerHandler;
public:
+ typedef QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) LEDeviceInquiryObjC;
+
QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress & address,
QBluetoothDeviceDiscoveryAgent *q);
- virtual ~QBluetoothDeviceDiscoveryAgentPrivate(); // Just to make compiler happy.
+ virtual ~QBluetoothDeviceDiscoveryAgentPrivate();
bool isValid() const;
bool isActive() const;
@@ -86,12 +88,11 @@ private:
void inquiryFinished(IOBluetoothDeviceInquiry *inq) Q_DECL_OVERRIDE;
void error(IOBluetoothDeviceInquiry *inq, IOReturn error) Q_DECL_OVERRIDE;
void deviceFound(IOBluetoothDeviceInquiry *inq, IOBluetoothDevice *device) Q_DECL_OVERRIDE;
- // LEDeviceInquiryDelegate:
- void LEdeviceInquiryError(QBluetoothDeviceDiscoveryAgent::Error error) Q_DECL_OVERRIDE;
- void LEnotSupported() Q_DECL_OVERRIDE;
- void LEdeviceFound(CBPeripheral *peripheral, const QBluetoothUuid &deviceUuid,
- NSDictionary *advertisementData, NSNumber *RSSI) Q_DECL_OVERRIDE;
- void LEdeviceInquiryFinished() Q_DECL_OVERRIDE;
+
+ //
+ void LEinquiryFinished();
+ void LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error);
+ void LEnotSupported();
// Check if it's a really new device/updated info and emit
// q_ptr->deviceDiscovered.
@@ -127,7 +128,7 @@ private:
typedef QList<QBluetoothDeviceInfo> DevicesList;
DevicesList discoveredDevices;
- OSXBluetooth::DDATimerHandler timer;
+ QScopedPointer<OSXBluetooth::DDATimerHandler> timer;
};
namespace OSXBluetooth {
@@ -137,7 +138,7 @@ DDATimerHandler::DDATimerHandler(QBluetoothDeviceDiscoveryAgentPrivate *d)
{
Q_ASSERT_X(owner, Q_FUNC_INFO, "invalid pointer");
- timer.setSingleShot(true);
+ timer.setSingleShot(false);
connect(&timer, &QTimer::timeout, this, &DDATimerHandler::onTimer);
}
@@ -173,8 +174,7 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(con
startPending(false),
stopPending(false),
lastError(QBluetoothDeviceDiscoveryAgent::NoError),
- inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry),
- timer(this)
+ inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry)
{
Q_ASSERT_X(q != Q_NULLPTR, Q_FUNC_INFO, "invalid q_ptr (null)");
@@ -192,23 +192,22 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(con
return;
}
- // OSXBTLEDeviceInquiry can be constructed even if LE is not supported -
- // at this stage it's only a memory allocation of the object itself,
- // if it fails - we have some memory-related problem.
- LEDeviceInquiry newInquiryLE([[LEDeviceInquiryObjC alloc] initWithDelegate:this]);
- if (!newInquiryLE) {
- qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "failed to "
- "initialize a LE inquiry";
- return;
- }
-
hostController.reset(controller.take());
inquiry.reset(newInquiry.take());
- inquiryLE.reset(newInquiryLE.take());
}
QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
{
+ if (inquiryLE && agentState != NonActive) {
+ // We want the LE scan to stop as soon as possible.
+ if (dispatch_queue_t leQueue = OSXBluetooth::qt_LE_queue()) {
+ // Local variable to be retained ...
+ LEDeviceInquiryObjC *inq = inquiryLE.data();
+ dispatch_async(leQueue, ^{
+ [inq stop];
+ });
+ }
+ }
}
bool QBluetoothDeviceDiscoveryAgentPrivate::isValid() const
@@ -218,7 +217,7 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isValid() const
// (and the error is probably not even related to Bluetooth at all)
// - say, allocation error - this is what meant here by valid/invalid.
return hostController && [hostController powerState] == kBluetoothHCIPowerStateON
- && inquiry && inquiryLE;
+ && inquiry;
}
bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
@@ -263,21 +262,29 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLE()
Q_ASSERT_X(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError,
Q_FUNC_INFO, "called with an invalid Bluetooth adapter");
- agentState = LEScan;
+ using namespace OSXBluetooth;
- // CoreBluetooth does not have a timeout. We start a timer here
- // and check if scan really started and if yes if we have a timeout.
- timer.start([LEDeviceInquiryObjC inquiryLength]);
+ inquiryLE.reset([[LEDeviceInquiryObjC alloc] init]);
- if (![inquiryLE start]) {
- // We can be here only if we have some kind of resource allocation error, so we
- // do not emit finished, we emit error.
- timer.stop();
+ dispatch_queue_t leQueue(qt_LE_queue());
+ if (!leQueue || !inquiryLE) {
setError(QBluetoothDeviceDiscoveryAgent::UnknownError,
QCoreApplication::translate(DEV_DISCOVERY, DD_NOT_STARTED_LE));
agentState = NonActive;
emit q_ptr->error(lastError);
}
+
+ agentState = LEScan;
+ // CoreBluetooth does not have a timeout. We start a timer here
+ // and check if scan is active/finished/finished with error(s).
+ timer.reset(new OSXBluetooth::DDATimerHandler(this));
+ timer->start(2000);
+
+ // We need the local variable so that it's retained ...
+ LEDeviceInquiryObjC *inq = inquiryLE.data();
+ dispatch_async(leQueue, ^{
+ [inq start];
+ });
}
void QBluetoothDeviceDiscoveryAgentPrivate::stop()
@@ -287,6 +294,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
Q_ASSERT_X(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError,
Q_FUNC_INFO, "called with invalid bluetooth adapter");
+ using namespace OSXBluetooth;
+
const bool prevStart = startPending;
startPending = false;
stopPending = true;
@@ -303,9 +312,16 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
emit q_ptr->error(lastError);
}
} else {
- // Can be asynchronous (depending on a status update of CBCentralManager).
- // The call itself is always 'success'.
- [inquiryLE stop];
+ dispatch_queue_t leQueue(qt_LE_queue());
+ Q_ASSERT(leQueue);
+ // We need the local variable so that it's retained ...
+ LEDeviceInquiryObjC *inq = inquiryLE.data();
+ dispatch_async(leQueue, ^{
+ [inq stop];
+ });
+ // We consider LE scan to be stopped immediately and
+ // do not care about this LEDeviceInquiry object anymore.
+ LEinquiryFinished();
}
}
@@ -429,31 +445,45 @@ void QBluetoothDeviceDiscoveryAgentPrivate::checkLETimeout()
Q_ASSERT_X(agentState == LEScan, Q_FUNC_INFO, "invalid agent state");
Q_ASSERT_X(inquiryLE, Q_FUNC_INFO, "LE device inquiry is nil");
- const int timeout = [LEDeviceInquiryObjC inquiryLength];
- Q_ASSERT(timeout > 0);
- const QTime scanStartTime([inquiryLE startTime]);
- if (scanStartTime.isValid()) {
- const int elapsed = scanStartTime.msecsTo(QTime::currentTime());
- Q_ASSERT(elapsed >= 0);
- if (elapsed >= timeout)
- [inquiryLE stop];
- else
- timer.start(timeout - elapsed);
- } else {
- // Scan not started yet. Wait 5 seconds more.
- timer.start(timeout / 2);
+ using namespace OSXBluetooth;
+
+ const LEInquiryState state([inquiryLE inquiryState]);
+ if (state == InquiryStarting || state == InquiryActive)
+ return; // Wait ...
+
+ if (state == ErrorPoweredOff)
+ return LEinquiryError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
+
+ if (state == ErrorLENotSupported)
+ return LEnotSupported();
+
+ if (state == InquiryFinished) {
+ // Process found devices if any ...
+ const QList<QBluetoothDeviceInfo> leDevices([inquiryLE discoveredDevices]);
+ foreach (const QBluetoothDeviceInfo &info, leDevices) {
+ // We were cancelled on a previous device discovered signal ...
+ if (agentState != LEScan)
+ break;
+ deviceFound(info);
+ }
+
+ if (agentState == LEScan)
+ LEinquiryFinished();
+ return;
}
+
+ qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "unexpected inquiry state in LE timeout";
+ // Actually, this deserves an assert :)
}
-void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceInquiryError(QBluetoothDeviceDiscoveryAgent::Error error)
+void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error)
{
// At the moment the only error reported can be 'powered off' error, it happens
// after the LE scan started (so we have LE support and this is a real PoweredOffError).
- Q_ASSERT_X(error == QBluetoothDeviceDiscoveryAgent::PoweredOffError,
- Q_FUNC_INFO, "unexpected error code");
-
- timer.stop();
+ Q_ASSERT(error == QBluetoothDeviceDiscoveryAgent::PoweredOffError);
+ timer->stop();
+ inquiryLE.reset();
agentState = NonActive;
setError(error);
emit q_ptr->error(lastError);
@@ -461,46 +491,17 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceInquiryError(QBluetoothDevic
void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported()
{
- // Not supported is not an error.
+ // Not supported is not an error (we still have 'Classic').
qCDebug(QT_BT_OSX) << "no Bluetooth LE support";
- // After we call startLE and before receive NotSupported,
- // the user can call stop (setting a pending stop).
- // So the same rule apply:
- timer.stop();
-
- LEdeviceInquiryFinished();
+ LEinquiryFinished();
}
-void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound(CBPeripheral *peripheral, const QBluetoothUuid &deviceUuid,
- NSDictionary *advertisementData,
- NSNumber *RSSI)
-{
- Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)");
- Q_ASSERT_X(agentState == LEScan, Q_FUNC_INFO,
- "invalid agent state, expected LE scan");
-
- Q_UNUSED(advertisementData)
-
- QString name;
- if (peripheral.name)
- name = QString::fromNSString(peripheral.name);
-
- // TODO: fix 'classOfDevice' (0 for now).
- QBluetoothDeviceInfo newDeviceInfo(deviceUuid, name, 0);
- if (RSSI)
- newDeviceInfo.setRssi([RSSI shortValue]);
- // CoreBluetooth scans only for LE devices.
- newDeviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
-
- deviceFound(newDeviceInfo);
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceInquiryFinished()
+void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished()
{
// The same logic as in inquiryFinished, but does not start LE scan.
agentState = NonActive;
-
- timer.stop();
+ inquiryLE.reset();
+ timer->stop();
if (stopPending && !startPending) {
stopPending = false;
diff --git a/src/bluetooth/qbluetoothdeviceinfo.cpp b/src/bluetooth/qbluetoothdeviceinfo.cpp
index 0a66c2c2..7d5d8f0c 100644
--- a/src/bluetooth/qbluetoothdeviceinfo.cpp
+++ b/src/bluetooth/qbluetoothdeviceinfo.cpp
@@ -453,6 +453,12 @@ bool QBluetoothDeviceInfo::operator!=(const QBluetoothDeviceInfo &other) const
/*!
Returns the address of the device.
+
+ \note On iOS and OS X this address is invalid. Instead \l deviceUuid() should be used.
+ Those two platforms do not expose Bluetooth addresses for found Bluetooth devices
+ and utilize unique device identifiers.
+
+ \sa deviceUuid()
*/
QBluetoothAddress QBluetoothDeviceInfo::address() const
{
diff --git a/src/bluetooth/qbluetoothlocaldevice.cpp b/src/bluetooth/qbluetoothlocaldevice.cpp
index 99264962..eb270f8d 100644
--- a/src/bluetooth/qbluetoothlocaldevice.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice.cpp
@@ -97,20 +97,17 @@ QT_BEGIN_NAMESPACE
*/
-namespace {
-class LocalDeviceRegisterMetaTypes
+void registerQBluetoothLocalDeviceMetaType()
{
-public:
- LocalDeviceRegisterMetaTypes()
- {
+ static bool initDone = false;
+ if (!initDone) {
qRegisterMetaType<QBluetoothLocalDevice::HostMode>();
qRegisterMetaType<QBluetoothLocalDevice::Pairing>();
qRegisterMetaType<QBluetoothLocalDevice::Error>();
+ initDone = true;
}
-} _registerLocalDeviceMetaTypes;
}
-
#ifndef QT_OSX_BLUETOOTH
/*!
diff --git a/src/bluetooth/qbluetoothlocaldevice_android.cpp b/src/bluetooth/qbluetoothlocaldevice_android.cpp
index 20ac3d0a..083bc190 100644
--- a/src/bluetooth/qbluetoothlocaldevice_android.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_android.cpp
@@ -52,6 +52,8 @@ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(
obj(0),
pendingHostModeTransition(false)
{
+ registerQBluetoothLocalDeviceMetaType();
+
initialize(address);
receiver = new LocalDeviceBroadcastReceiver(q_ptr);
diff --git a/src/bluetooth/qbluetoothlocaldevice_bluez.cpp b/src/bluetooth/qbluetoothlocaldevice_bluez.cpp
index d2ec70b9..0f5d4917 100644
--- a/src/bluetooth/qbluetoothlocaldevice_bluez.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_bluez.cpp
@@ -656,6 +656,8 @@ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice
msgConnection(0),
q_ptr(q)
{
+ registerQBluetoothLocalDeviceMetaType();
+
if (isBluez5())
initializeAdapterBluez5();
else
diff --git a/src/bluetooth/qbluetoothlocaldevice_osx.mm b/src/bluetooth/qbluetoothlocaldevice_osx.mm
index 71b7b81a..b1957d09 100644
--- a/src/bluetooth/qbluetoothlocaldevice_osx.mm
+++ b/src/bluetooth/qbluetoothlocaldevice_osx.mm
@@ -105,6 +105,8 @@ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice
const QBluetoothAddress &address) :
q_ptr(q)
{
+ registerQBluetoothLocalDeviceMetaType();
+
Q_ASSERT_X(q, Q_FUNC_INFO, "invalid q_ptr (null)");
QT_BT_MAC_AUTORELEASEPOOL;
diff --git a/src/bluetooth/qbluetoothlocaldevice_p.cpp b/src/bluetooth/qbluetoothlocaldevice_p.cpp
index 2785e84c..0b7c5c44 100644
--- a/src/bluetooth/qbluetoothlocaldevice_p.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_p.cpp
@@ -34,18 +34,22 @@
#include "qbluetoothlocaldevice.h"
#include "qbluetoothaddress.h"
+#include "qbluetoothlocaldevice_p.h"
+
QT_BEGIN_NAMESPACE
QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
QObject(parent),
d_ptr(0)
{
+ registerQBluetoothLocalDeviceMetaType();
}
QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &, QObject *parent) :
QObject(parent),
d_ptr(0)
{
+ registerQBluetoothLocalDeviceMetaType();
}
QString QBluetoothLocalDevice::name() const
diff --git a/src/bluetooth/qbluetoothlocaldevice_p.h b/src/bluetooth/qbluetoothlocaldevice_p.h
index 1d4db40d..70d1727b 100644
--- a/src/bluetooth/qbluetoothlocaldevice_p.h
+++ b/src/bluetooth/qbluetoothlocaldevice_p.h
@@ -80,6 +80,8 @@ QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
+extern void registerQBluetoothLocalDeviceMetaType();
+
class QBluetoothAddress;
#ifdef QT_ANDROID_BLUETOOTH
diff --git a/src/bluetooth/qbluetoothuuid.cpp b/src/bluetooth/qbluetoothuuid.cpp
index cfce871c..3c8dc786 100644
--- a/src/bluetooth/qbluetoothuuid.cpp
+++ b/src/bluetooth/qbluetoothuuid.cpp
@@ -311,7 +311,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QUuid, baseUuid, ("{00000000-0000-1000-8000-00805F9B34
\value DescriptorValueChanged This characteristic is related to the Environmental Sensing Service.
\value DeviceName The Device Name characteristic contains the name of the device.
\value DewPoint This characteristic states the dew point in degree Celsius.
- \value DSTOffset The DST Offset characteristic describes the offset employed by the daylight saving time.
+ \value DSTOffset The DST Offset characteristic describes the offset employed by daylight-saving time.
\value Elevation The Elevation characteristic states the elevation above/below sea level.
\value EmailAddress This characteristic states the email of the user.
\value ExactTime256 The Exact Time 256 characteristic describes the data, day and time
@@ -497,16 +497,13 @@ Q_GLOBAL_STATIC_WITH_ARGS(QUuid, baseUuid, ("{00000000-0000-1000-8000-00805F9B34
\value UnknownDescriptorType The descriptor type is unknown.
*/
-namespace
+static void registerQBluetoothUuidMetaType()
{
- class BtUuidRegisterMetaTypes
- {
- public:
- BtUuidRegisterMetaTypes()
- {
- qRegisterMetaType<QBluetoothUuid>();
- }
- } _registerBtUuidMetaTypes;
+ static bool initDone = false;
+ if (!initDone) {
+ qRegisterMetaType<QBluetoothUuid>();
+ initDone = true;
+ }
}
/*!
@@ -514,6 +511,7 @@ namespace
*/
QBluetoothUuid::QBluetoothUuid()
{
+ registerQBluetoothUuidMetaType();
}
/*!
@@ -525,6 +523,7 @@ QBluetoothUuid::QBluetoothUuid(ProtocolUuid uuid)
baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
baseUuid()->data4[6], baseUuid()->data4[7])
{
+ registerQBluetoothUuidMetaType();
}
/*!
@@ -535,6 +534,7 @@ QBluetoothUuid::QBluetoothUuid(ServiceClassUuid uuid)
baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
baseUuid()->data4[6], baseUuid()->data4[7])
{
+ registerQBluetoothUuidMetaType();
}
/*!
@@ -546,6 +546,7 @@ QBluetoothUuid::QBluetoothUuid(CharacteristicType uuid)
baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
baseUuid()->data4[6], baseUuid()->data4[7])
{
+ registerQBluetoothUuidMetaType();
}
/*!
@@ -557,7 +558,7 @@ QBluetoothUuid::QBluetoothUuid(DescriptorType uuid)
baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
baseUuid()->data4[6], baseUuid()->data4[7])
{
-
+ registerQBluetoothUuidMetaType();
}
/*!
@@ -568,6 +569,7 @@ QBluetoothUuid::QBluetoothUuid(quint16 uuid)
baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
baseUuid()->data4[6], baseUuid()->data4[7])
{
+ registerQBluetoothUuidMetaType();
}
/*!
@@ -578,6 +580,7 @@ QBluetoothUuid::QBluetoothUuid(quint32 uuid)
baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
baseUuid()->data4[6], baseUuid()->data4[7])
{
+ registerQBluetoothUuidMetaType();
}
/*!
@@ -587,6 +590,7 @@ QBluetoothUuid::QBluetoothUuid(quint32 uuid)
*/
QBluetoothUuid::QBluetoothUuid(quint128 uuid)
{
+ registerQBluetoothUuidMetaType();
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
data1 = qFromBigEndian<quint32>(*reinterpret_cast<quint32 *>(&uuid.data[0]));
@@ -605,6 +609,7 @@ QT_WARNING_POP
QBluetoothUuid::QBluetoothUuid(const QString &uuid)
: QUuid(uuid)
{
+ registerQBluetoothUuidMetaType();
}
/*!
@@ -613,6 +618,7 @@ QBluetoothUuid::QBluetoothUuid(const QString &uuid)
QBluetoothUuid::QBluetoothUuid(const QBluetoothUuid &uuid)
: QUuid(uuid)
{
+ registerQBluetoothUuidMetaType();
}
/*!
@@ -621,6 +627,7 @@ QBluetoothUuid::QBluetoothUuid(const QBluetoothUuid &uuid)
QBluetoothUuid::QBluetoothUuid(const QUuid &uuid)
: QUuid(uuid)
{
+ registerQBluetoothUuidMetaType();
}
/*!
diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp
index 62e8f7e3..e39df97c 100644
--- a/src/bluetooth/qlowenergycontroller.cpp
+++ b/src/bluetooth/qlowenergycontroller.cpp
@@ -194,18 +194,17 @@ QT_BEGIN_NAMESPACE
\sa discoverServices(), error()
*/
-namespace {
-class QLowEnergyControllerMetaTypes
+void registerQLowEnergyControllerMetaType()
{
-public:
- QLowEnergyControllerMetaTypes()
- {
+ static bool initDone = false;
+ if (!initDone) {
qRegisterMetaType<QLowEnergyController::ControllerState>();
qRegisterMetaType<QLowEnergyController::Error>();
+ initDone = true;
}
-} qLowEnergyControllerMetaTypes;
}
+
void QLowEnergyControllerPrivate::setError(
QLowEnergyController::Error newError)
{
diff --git a/src/bluetooth/qlowenergycontroller_android.cpp b/src/bluetooth/qlowenergycontroller_android.cpp
index b04ddedd..767c91f8 100644
--- a/src/bluetooth/qlowenergycontroller_android.cpp
+++ b/src/bluetooth/qlowenergycontroller_android.cpp
@@ -45,6 +45,7 @@ QLowEnergyControllerPrivate::QLowEnergyControllerPrivate()
error(QLowEnergyController::NoError),
hub(0)
{
+ registerQLowEnergyControllerMetaType();
}
QLowEnergyControllerPrivate::~QLowEnergyControllerPrivate()
diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp
index 18d0f5a1..a00ac565 100644
--- a/src/bluetooth/qlowenergycontroller_bluez.cpp
+++ b/src/bluetooth/qlowenergycontroller_bluez.cpp
@@ -205,6 +205,7 @@ QLowEnergyControllerPrivate::QLowEnergyControllerPrivate()
encryptionChangePending(false),
hciManager(0)
{
+ registerQLowEnergyControllerMetaType();
qRegisterMetaType<QList<QLowEnergyHandle> >();
hciManager = new HciManager(localAdapter, this);
@@ -268,7 +269,9 @@ void QLowEnergyControllerPrivate::connectToDevice()
}
// connect
- l2cpSocket->connectToService(remoteDevice, ATTRIBUTE_CHANNEL_ID);
+ // Unbuffered mode required to separate each GATT packet
+ l2cpSocket->connectToService(remoteDevice, ATTRIBUTE_CHANNEL_ID,
+ QIODevice::ReadWrite | QIODevice::Unbuffered);
}
void QLowEnergyControllerPrivate::l2cpConnected()
@@ -1723,9 +1726,9 @@ bool QLowEnergyControllerPrivate::increaseEncryptLevelfRequired(quint8 errorCode
return false;
switch (errorCode) {
- case ATT_ERROR_INSUF_AUTHORIZATION:
case ATT_ERROR_INSUF_ENCRYPTION:
case ATT_ERROR_INSUF_AUTHENTICATION:
+ case ATT_ERROR_INSUF_ENCR_KEY_SIZE:
if (!hciManager->isValid())
return false;
if (!hciManager->monitorEvent(HciManager::EncryptChangeEvent))
diff --git a/src/bluetooth/qlowenergycontroller_osx.mm b/src/bluetooth/qlowenergycontroller_osx.mm
index d0d65248..396f82bb 100644
--- a/src/bluetooth/qlowenergycontroller_osx.mm
+++ b/src/bluetooth/qlowenergycontroller_osx.mm
@@ -56,17 +56,15 @@ QT_BEGIN_NAMESPACE
namespace {
-
-class QLowEnergyControllerMetaTypes
+static void registerQLowEnergyControllerMetaType()
{
-public:
- QLowEnergyControllerMetaTypes()
- {
+ static bool initDone = false;
+ if (!initDone) {
qRegisterMetaType<QLowEnergyController::ControllerState>();
qRegisterMetaType<QLowEnergyController::Error>();
+ initDone = true;
}
-} qLowEnergyControllerMetaTypes;
-
+}
typedef QSharedPointer<QLowEnergyServicePrivate> ServicePrivate;
@@ -137,6 +135,8 @@ QLowEnergyControllerPrivateOSX::QLowEnergyControllerPrivateOSX(QLowEnergyControl
controllerState(QLowEnergyController::UnconnectedState),
addressType(QLowEnergyController::PublicAddress)
{
+ registerQLowEnergyControllerMetaType();
+
// This is the "wrong" constructor - no valid device UUID to connect later.
Q_ASSERT_X(q, Q_FUNC_INFO, "invalid q_ptr (null)");
// We still create a manager, to simplify error handling later.
@@ -157,6 +157,8 @@ QLowEnergyControllerPrivateOSX::QLowEnergyControllerPrivateOSX(QLowEnergyControl
controllerState(QLowEnergyController::UnconnectedState),
addressType(QLowEnergyController::PublicAddress)
{
+ registerQLowEnergyControllerMetaType();
+
Q_ASSERT_X(q, Q_FUNC_INFO, "invalid q_ptr (null)");
centralManager.reset([[ObjCCentralManager alloc] initWithDelegate:this]);
if (!centralManager) {
diff --git a/src/bluetooth/qlowenergycontroller_p.cpp b/src/bluetooth/qlowenergycontroller_p.cpp
index b3c718b5..79addae2 100644
--- a/src/bluetooth/qlowenergycontroller_p.cpp
+++ b/src/bluetooth/qlowenergycontroller_p.cpp
@@ -40,6 +40,7 @@ QLowEnergyControllerPrivate::QLowEnergyControllerPrivate()
state(QLowEnergyController::UnconnectedState),
error(QLowEnergyController::NoError)
{
+ registerQLowEnergyControllerMetaType();
}
QLowEnergyControllerPrivate::~QLowEnergyControllerPrivate()
diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h
index f587d3f9..40318700 100644
--- a/src/bluetooth/qlowenergycontroller_p.h
+++ b/src/bluetooth/qlowenergycontroller_p.h
@@ -84,6 +84,8 @@ class HciManager;
class LowEnergyNotificationHub;
#endif
+extern void registerQLowEnergyControllerMetaType();
+
typedef QMap<QBluetoothUuid, QSharedPointer<QLowEnergyServicePrivate> > ServiceDataMap;
class QLowEnergyControllerPrivate : public QObject
diff --git a/src/src.pro b/src/src.pro
index c5585757..97b32522 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,7 +1,10 @@
TEMPLATE = subdirs
SUBDIRS += bluetooth nfc
-android: SUBDIRS += android
+android {
+ SUBDIRS += android
+ android.depends += bluetooth nfc
+}
contains(QT_CONFIG, private_tests) {
bluetooth_doc_snippets.subdir = bluetooth/doc/snippets
diff --git a/tests/auto/qbluetoothserver/qbluetoothserver.pro b/tests/auto/qbluetoothserver/qbluetoothserver.pro
index 95621926..f1baed01 100644
--- a/tests/auto/qbluetoothserver/qbluetoothserver.pro
+++ b/tests/auto/qbluetoothserver/qbluetoothserver.pro
@@ -4,7 +4,6 @@ CONFIG += testcase
QT = core concurrent bluetooth testlib
osx:QT += widgets
-osx:CONFIG += insignificant_test
OTHER_FILES += \
README.txt
diff --git a/tests/auto/qlowenergycharacteristic/qlowenergycharacteristic.pro b/tests/auto/qlowenergycharacteristic/qlowenergycharacteristic.pro
index 7e86526f..24106573 100644
--- a/tests/auto/qlowenergycharacteristic/qlowenergycharacteristic.pro
+++ b/tests/auto/qlowenergycharacteristic/qlowenergycharacteristic.pro
@@ -4,5 +4,4 @@ CONFIG += testcase
QT = core bluetooth testlib
-osx:CONFIG += insignificant_test
diff --git a/tests/auto/qlowenergycontroller/qlowenergycontroller.pro b/tests/auto/qlowenergycontroller/qlowenergycontroller.pro
index 9d25d8a3..24178b6e 100644
--- a/tests/auto/qlowenergycontroller/qlowenergycontroller.pro
+++ b/tests/auto/qlowenergycontroller/qlowenergycontroller.pro
@@ -10,5 +10,4 @@ SOURCES += tst_qlowenergycontroller.cpp
osx|ios {
QT += widgets
- CONFIG += insignificant_test
}
diff --git a/tests/auto/qlowenergydescriptor/qlowenergydescriptor.pro b/tests/auto/qlowenergydescriptor/qlowenergydescriptor.pro
index 4df897b8..81ec9566 100644
--- a/tests/auto/qlowenergydescriptor/qlowenergydescriptor.pro
+++ b/tests/auto/qlowenergydescriptor/qlowenergydescriptor.pro
@@ -4,5 +4,3 @@ CONFIG += testcase
QT = core bluetooth testlib
-osx:CONFIG += insignificant_test
-