diff options
author | Timur Pocheptsov <Timur.Pocheptsov@digia.com> | 2014-09-30 17:29:15 +0200 |
---|---|---|
committer | Timur Pocheptsov <Timur.Pocheptsov@digia.com> | 2014-10-16 09:46:15 +0200 |
commit | e417b7036e35744daa1978cd236798e3ee1693c0 (patch) | |
tree | 3e86b6ce833e70efa75f8151302973a030338fb2 | |
parent | 552bdb884b44fffde3075ee2016a8a5c04108b3c (diff) |
QtBluetooth - device discovery test on OS X.
- Enable this auto test on OS X, requires a modification: 'stop' is synchronous
and so cancelSpy.isEmpty() == false (the last QVERIFY fails.
- Fix several problems with SDK versions (workarounds for non-existing methods in SDK < 10.9).
- Change error handling: we set an error in a ctor _only_ if QBluetoothAddress parameter was
not null (!isNull()) and we failed to find a local device with such an address. This is the
only case documented/expected, all others _do_ _not_ set an error, even if a local adapter
is off or does not exits. This fixes a failing (to integrate) auto-test.
Change-Id: I9902211078330f296775f1c3249da166c19001a4
Reviewed-by: Alex Blasche <alexander.blasche@digia.com>
5 files changed, 79 insertions, 42 deletions
diff --git a/src/bluetooth/osx/osxbtdevicepair.mm b/src/bluetooth/osx/osxbtdevicepair.mm index 8edc30a6..c9d6de32 100644 --- a/src/bluetooth/osx/osxbtdevicepair.mm +++ b/src/bluetooth/osx/osxbtdevicepair.mm @@ -97,7 +97,13 @@ using namespace QT_NAMESPACE; - (void)dealloc { - [m_pairing stop]; // Stop also sets a delegate to nil (Apple's docs). +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_NA) + // Stop also sets a delegate to nil (Apple's docs). + // 10.9 only. + [m_pairing stop]; +#else + [m_pairing setDelegate:nil]; +#endif [m_pairing release]; [super dealloc]; @@ -171,22 +177,16 @@ using namespace QT_NAMESPACE; - (void)devicePairingStarted:(id)sender { Q_UNUSED(sender) - // - NSLog(@"pairing started ... to be implemented"); } - (void)devicePairingConnecting:(id)sender { Q_UNUSED(sender) - - NSLog(@"connecting ... to be implemented"); } - (void)deviceParingPINCodeRequest:(id)sender { Q_UNUSED(sender) - - NSLog(@"pin code request ... to be implemented"); } - (void)devicePairingUserConfirmationRequest:(id)sender @@ -206,8 +206,6 @@ using namespace QT_NAMESPACE; { Q_UNUSED(sender) Q_UNUSED(passkey) - - NSLog(@"pass key notification ... to be implemented"); } - (void)devicePairingFinished:(id)sender error:(IOReturn)error diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm index 2f808038..5f2881af 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm @@ -126,7 +126,6 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(con if (!controller) { qCCritical(QT_BT_OSX) << "QBluetoothDeviceDiscoveryAgentPrivate() " "no default host controller"; - setError(QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError); return; } @@ -134,7 +133,6 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(con if (!newInquiry) { // Obj-C's way of "reporting errors": qCCritical(QT_BT_OSX) << "QBluetoothDeviceDiscoveryAgentPrivate() " "failed to initialize an inquiry"; - setError(QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError); return; } @@ -167,6 +165,7 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const void QBluetoothDeviceDiscoveryAgentPrivate::start() { + Q_ASSERT_X(isValid(), "start()", "called on invalid device discovery agent"); Q_ASSERT_X(!isActive(), "start()", "called on active device discovery agent"); Q_ASSERT_X(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError, "start()", "called with invalid bluetooth adapter"); @@ -188,6 +187,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start() void QBluetoothDeviceDiscoveryAgentPrivate::stop() { + Q_ASSERT_X(isValid(), "stop()", "called on invalid device discovery agent"); Q_ASSERT_X(isActive(), "stop()", "called whithout active inquiry"); Q_ASSERT_X(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError, "stop()", "called with invalid bluetooth adapter"); @@ -375,8 +375,18 @@ QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices() void QBluetoothDeviceDiscoveryAgent::start() { - if (!isActive() && d_ptr->lastError != InvalidBluetoothAdapterError) - d_ptr->start(); + if (d_ptr->lastError != InvalidBluetoothAdapterError) { + if (d_ptr->isValid()) { + if (!isActive()) + d_ptr->start(); + } else { + // We previously failed to initialize d_ptr correctly: + // either some memory allocation problem or + // no BT adapter found. + d_ptr->setError(InvalidBluetoothAdapterError); + emit error(InvalidBluetoothAdapterError); + } + } } void QBluetoothDeviceDiscoveryAgent::stop() diff --git a/src/bluetooth/qbluetoothserviceinfo_osx.mm b/src/bluetooth/qbluetoothserviceinfo_osx.mm index 2ab2c9f1..ae88b4e7 100644 --- a/src/bluetooth/qbluetoothserviceinfo_osx.mm +++ b/src/bluetooth/qbluetoothserviceinfo_osx.mm @@ -62,20 +62,23 @@ namespace { // This is not in osxbtutility_p, since it's not required // in general and just fixes the problem with SDK < 10.9, // where we have to care about about IOBluetoothSDPServiceRecordRef. -class ServiceRecordDeleter +class ServiceRecordRefGuard { public: - ServiceRecordDeleter(IOBluetoothSDPServiceRecordRef r) + ServiceRecordRefGuard(IOBluetoothSDPServiceRecordRef r) : recordRef(r) { } - ~ServiceRecordDeleter() + ~ServiceRecordRefGuard() { if (recordRef) // Requires non-NULL pointers. CFRelease(recordRef); } +private: IOBluetoothSDPServiceRecordRef recordRef; + + Q_DISABLE_COPY(ServiceRecordRefGuard) }; } @@ -85,7 +88,6 @@ class QBluetoothServiceInfoPrivate public: typedef QBluetoothServiceInfo QSInfo; QBluetoothServiceInfoPrivate(QBluetoothServiceInfo *q); - ~QBluetoothServiceInfoPrivate(); bool registerService(const QBluetoothAddress &localAdapter = QBluetoothAddress()); @@ -105,20 +107,17 @@ private: typedef OSXBluetooth::ObjCScopedPointer<IOBluetoothSDPServiceRecord> SDPRecord; SDPRecord serviceRecord; + BluetoothSDPServiceRecordHandle serviceRecordHandle; }; QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate(QBluetoothServiceInfo *q) : q_ptr(q), - registered(false) + registered(false), + serviceRecordHandle(0) { Q_ASSERT_X(q, "QBluetoothServiceInfoPrivate()", "invalid q_ptr (null)"); } -QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate() -{ - // TODO: should it unregister? -} - bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &localAdapter) { Q_UNUSED(localAdapter) @@ -129,8 +128,6 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca Q_ASSERT_X(!serviceRecord, "QBluetoothServiceInfoPrivate::registerService()", "not registered, but serviceRecord is not nil"); - // TODO: create a service description (as NSDictionary) and add to the - // local SDP server via IOBluetoothSDPServiceRecord and its methods. using namespace OSXBluetooth; ObjCStrongReference<NSMutableDictionary> @@ -143,56 +140,79 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca } SDPRecord newRecord; - #if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_NA) newRecord.reset([[IOBluetoothSDPServiceRecord publishedServiceRecordWithDictionary:serviceDict] retain]); - #else IOBluetoothSDPServiceRecordRef recordRef = Q_NULLPTR; // With ARC this will require a different cast? const IOReturn status = IOBluetoothAddServiceDict((CFDictionaryRef)serviceDict.data(), &recordRef); if (status != kIOReturnSuccess) { qCWarning(QT_BT_OSX) << "QBluetoothServiceInfoPrivate::registerService(), " - "failed to create register a service record"; + "failed to register a service record"; return false; } - const ServiceRecordDeleter refGuard(recordRef); + const ServiceRecordRefGuard refGuard(recordRef); newRecord.reset([[IOBluetoothSDPServiceRecord withSDPServiceRecordRef:recordRef] retain]); - // It's weird, but ... it's not possible to release a record ref yet! + // It's weird, but ... it's not possible to release a record ref yet. #endif if (!newRecord) { qCWarning(QT_BT_OSX) << "QBluetoothServiceInfoPrivate::registerService(), " - "failed to create register a service record"; + "failed to register a service record"; + // In case of SDK < 10.9 it's not possible to remove a service record ... + // no way to obtain record handle yet. + return false; + } + + BluetoothSDPServiceRecordHandle newRecordHandle = 0; + if ([newRecord getServiceRecordHandle:&newRecordHandle] != kIOReturnSuccess) { + qCWarning(QT_BT_OSX) << "QBluetoothServiceInfoPrivate::registerService(), " + "failed to register a service record"; +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_NA) + [newRecord removeServiceRecord]; +#endif + // With SDK < 10.9 there is no way to unregister at this point ... return false; } const QSInfo::Protocol type = q_ptr->socketProtocol(); quint16 realPort = 0; QBluetoothServerPrivate *server = Q_NULLPTR; + bool configured = false; if (type == QBluetoothServiceInfo::L2capProtocol) { BluetoothL2CAPPSM psm = 0; server = QBluetoothServerPrivate::registeredServer(q_ptr->protocolServiceMultiplexer(), type); - if ([newRecord getL2CAPPSM:&psm] != kIOReturnSuccess) { - [newRecord removeServiceRecord]; - return false; + if ([newRecord getL2CAPPSM:&psm] == kIOReturnSuccess) { + configured = true; + realPort = psm; } - realPort = psm; } else if (type == QBluetoothServiceInfo::RfcommProtocol) { BluetoothRFCOMMChannelID channelID = 0; server = QBluetoothServerPrivate::registeredServer(q_ptr->serverChannel(), type); - if ([newRecord getRFCOMMChannelID:&channelID] != kIOReturnSuccess) { - [newRecord removeServiceRecord]; - return false; + if ([newRecord getRFCOMMChannelID:&channelID] == kIOReturnSuccess) { + configured = true; + realPort = channelID; } - realPort = channelID; + } + + if (!configured) { +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_NA) + [newRecord removeServiceRecord]; +#else + IOBluetoothRemoveServiceWithRecordHandle(newRecordHandle); +#endif + qCWarning(QT_BT_OSX) << "QBluetoothServiceInfoPrivate::registerService(), " + "failed to register a service record"; + return false; } registered = true; serviceRecord.reset(newRecord.take()); + serviceRecordHandle = newRecordHandle; + if (server) server->startListener(realPort); @@ -212,7 +232,13 @@ bool QBluetoothServiceInfoPrivate::unregisterService() Q_ASSERT_X(serviceRecord, "QBluetoothServiceInfoPrivate::unregisterService()", "service registered, but serviceRecord is nil"); +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_9, __IPHONE_NA) [serviceRecord removeServiceRecord]; +#else + // Assert on newRecordHandle? Is 0 a valid/invalid handle? + IOBluetoothRemoveServiceWithRecordHandle(serviceRecordHandle); +#endif + serviceRecord.reset(nil); const QSInfo::Protocol type = q_ptr->socketProtocol(); @@ -228,6 +254,7 @@ bool QBluetoothServiceInfoPrivate::unregisterService() server->stopListener(); registered = false; + serviceRecordHandle = 0; return true; } diff --git a/tests/auto/qbluetoothdevicediscoveryagent/qbluetoothdevicediscoveryagent.pro b/tests/auto/qbluetoothdevicediscoveryagent/qbluetoothdevicediscoveryagent.pro index 43eda822..a7868123 100644 --- a/tests/auto/qbluetoothdevicediscoveryagent/qbluetoothdevicediscoveryagent.pro +++ b/tests/auto/qbluetoothdevicediscoveryagent/qbluetoothdevicediscoveryagent.pro @@ -3,7 +3,6 @@ TARGET=tst_qbluetoothdevicediscoveryagent CONFIG += testcase QT = core concurrent bluetooth testlib +osx:QT += widgets DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 - -osx:CONFIG += insignificant_test diff --git a/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp b/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp index ca22c8ea..dec85fba 100644 --- a/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp +++ b/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp @@ -314,7 +314,10 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries() QVERIFY(errorSpy.isEmpty()); // should only have 1 cancel QVERIFY(finishedSpy.count() == 1); - QVERIFY(cancelSpy.isEmpty()); + + // On OS X, stop is synchronous (signal will be emitted immediately). + if (!immediateSignal) + QVERIFY(cancelSpy.isEmpty()); } void tst_QBluetoothDeviceDiscoveryAgent::finished() |