diff options
Diffstat (limited to 'src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm')
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm | 192 |
1 files changed, 94 insertions, 98 deletions
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm index 0e4b460f..3f4c6755 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm @@ -37,16 +37,17 @@ ** ****************************************************************************/ -#include "qbluetoothdevicediscoverytimer_osx_p.h" #include "qbluetoothdevicediscoveryagent.h" #include "osx/osxbtledeviceinquiry_p.h" #include "qbluetoothlocaldevice.h" #include "qbluetoothdeviceinfo.h" +#include "osx/osxbtnotifier_p.h" #include "osx/osxbtutility_p.h" #include "osx/uistrings_p.h" #include "qbluetoothuuid.h" #include <QtCore/qloggingcategory.h> +#include <QtCore/qobject.h> #include <QtCore/qglobal.h> #include <QtCore/qstring.h> #include <QtCore/qdebug.h> @@ -56,12 +57,24 @@ QT_BEGIN_NAMESPACE -using OSXBluetooth::ObjCScopedPointer; +namespace +{ + +void registerQDeviceDiscoveryMetaType() +{ + static bool initDone = false; + if (!initDone) { + qRegisterMetaType<QBluetoothDeviceInfo>(); + qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::Error>(); + initDone = true; + } +} + +}//namespace -class QBluetoothDeviceDiscoveryAgentPrivate +class QBluetoothDeviceDiscoveryAgentPrivate : public QObject { friend class QBluetoothDeviceDiscoveryAgent; - friend class OSXBluetooth::DDATimerHandler; public: QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &address, @@ -70,17 +83,16 @@ public: bool isActive() const; - void start(); + void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods m); void stop(); private: - typedef QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) LEDeviceInquiryObjC; + using LEDeviceInquiryObjC = QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry); void LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error); void LEnotSupported(); void LEdeviceFound(const QBluetoothDeviceInfo &info); void LEinquiryFinished(); - void checkLETimeout(); void setError(QBluetoothDeviceDiscoveryAgent::Error, const QString &text = QString()); @@ -91,63 +103,30 @@ private: QBluetoothDeviceDiscoveryAgent::InquiryType inquiryType; - typedef ObjCScopedPointer<LEDeviceInquiryObjC> LEDeviceInquiry; + using LEDeviceInquiry = OSXBluetooth::ObjCScopedPointer<LEDeviceInquiryObjC>; LEDeviceInquiry inquiryLE; - typedef QList<QBluetoothDeviceInfo> DevicesList; + using DevicesList = QList<QBluetoothDeviceInfo>; DevicesList discoveredDevices; bool startPending; bool stopPending; - QScopedPointer<OSXBluetooth::DDATimerHandler> timer; + int lowEnergySearchTimeout; }; -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), lastError(QBluetoothDeviceDiscoveryAgent::NoError), inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry), startPending(false), - stopPending(false) + stopPending(false), + lowEnergySearchTimeout(OSXBluetooth::defaultLEScanTimeoutMS) { Q_UNUSED(adapter); + registerQDeviceDiscoveryMetaType(); Q_ASSERT_X(q != Q_NULLPTR, Q_FUNC_INFO, "invalid q_ptr (null)"); } @@ -158,7 +137,7 @@ QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() if (dispatch_queue_t leQueue = OSXBluetooth::qt_LE_queue()) { // Local variable to be retained ... LEDeviceInquiryObjC *inq = inquiryLE.data(); - dispatch_async(leQueue, ^{ + dispatch_sync(leQueue, ^{ [inq stop]; }); } @@ -175,7 +154,7 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const return inquiryLE; } -void QBluetoothDeviceDiscoveryAgentPrivate::start() +void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods /*methods*/) { Q_ASSERT_X(!isActive(), Q_FUNC_INFO, "called on active device discovery agent"); @@ -186,26 +165,37 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start() using namespace OSXBluetooth; - inquiryLE.reset([[LEDeviceInquiryObjC alloc] init]); + QScopedPointer<LECBManagerNotifier> notifier(new LECBManagerNotifier); + // Connections: + using ErrMemFunPtr = void (LECBManagerNotifier::*)(QBluetoothDeviceDiscoveryAgent::Error); + notifier->connect(notifier.data(), ErrMemFunPtr(&LECBManagerNotifier::CBManagerError), + this, &QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError); + notifier->connect(notifier.data(), &LECBManagerNotifier::LEnotSupported, + this, &QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported); + notifier->connect(notifier.data(), &LECBManagerNotifier::discoveryFinished, + this, &QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished); + notifier->connect(notifier.data(), &LECBManagerNotifier::deviceDiscovered, + this, &QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound); + + inquiryLE.reset([[LEDeviceInquiryObjC alloc] initWithNotifier:notifier.data()]); + if (inquiryLE) + notifier.take(); // Whatever happens next, inquiryLE is already the owner ... + 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); + return; } 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]; + [inq startWithTimeout:lowEnergySearchTimeout]; }); } @@ -223,7 +213,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop() // Create a local variable - to have a strong referece in a block. LEDeviceInquiryObjC *inq = inquiryLE.data(); - dispatch_async(leQueue, ^{ + dispatch_sync(leQueue, ^{ [inq stop]; }); // We consider LE scan to be stopped immediately and @@ -241,7 +231,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDisco Q_FUNC_INFO, "unexpected error"); inquiryLE.reset(); - timer->stop(); startPending = false; stopPending = false; @@ -252,7 +241,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDisco void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported() { inquiryLE.reset(); - timer->stop(); startPending = false; stopPending = false; @@ -281,7 +269,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound(const QBluetoothDevice void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished() { inquiryLE.reset(); - timer->stop(); if (stopPending && !startPending) { stopPending = false; @@ -289,47 +276,14 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished() } else if (startPending) { startPending = false; stopPending = false; - start(); + // always the same method for start() on iOS + // classic search not supported + start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); } else { emit q_ptr->finished(); } } -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) { @@ -373,7 +327,7 @@ QBluetoothDeviceDiscoveryAgent::QBluetoothDeviceDiscoveryAgent( d_ptr(new QBluetoothDeviceDiscoveryAgentPrivate(deviceAdapter, this)) { if (!deviceAdapter.isNull()) { - qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "local device address is " + qCWarning(QT_BT_OSX) << "local device address is " "not available, provided address is ignored"; d_ptr->setError(InvalidBluetoothAdapterError); } @@ -399,14 +353,39 @@ QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices() return d_ptr->discoveredDevices; } +QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods() +{ + return LowEnergyMethod; +} + void QBluetoothDeviceDiscoveryAgent::start() { if (d_ptr->lastError != InvalidBluetoothAdapterError) { if (!isActive()) - d_ptr->start(); + d_ptr->start(supportedDiscoveryMethods()); else - qCDebug(QT_BT_OSX) << Q_FUNC_INFO << "already started"; + qCDebug(QT_BT_OSX) << "already started"; + } +} + +void QBluetoothDeviceDiscoveryAgent::start(DiscoveryMethods methods) +{ + if (methods == NoMethod) + return; + + DiscoveryMethods supported = + QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods(); + + if (!((supported & methods) == methods)) { + d_ptr->lastError = UnsupportedDiscoveryMethod; + d_ptr->errorString = QBluetoothDeviceDiscoveryAgent::tr("One or more device discovery methods " + "are not supported on this platform"); + emit error(d_ptr->lastError); + return; } + + if (!isActive() && d_ptr->lastError != InvalidBluetoothAdapterError) + d_ptr->start(methods); } void QBluetoothDeviceDiscoveryAgent::stop() @@ -430,4 +409,21 @@ QString QBluetoothDeviceDiscoveryAgent::errorString() const return d_ptr->errorString; } +int QBluetoothDeviceDiscoveryAgent::lowEnergyDiscoveryTimeout() const +{ + return d_ptr->lowEnergySearchTimeout; +} + +void QBluetoothDeviceDiscoveryAgent::setLowEnergyDiscoveryTimeout(int timeout) +{ + // cannot deliberately turn it off + if (timeout < 0) { + qCDebug(QT_BT_OSX) << "The Bluetooth Low Energy device discovery timeout cannot be negative."; + return; + } + + d_ptr->lowEnergySearchTimeout = timeout; + return; +} + QT_END_NAMESPACE |