diff options
author | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2019-04-26 14:18:26 +0200 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2019-06-14 14:21:53 +0200 |
commit | 722fde4664b8b3f5f661e37d212c32ba0fb2bbad (patch) | |
tree | bc00af5f01f15ed0b74c2d8a9cf2c93405eef6f7 | |
parent | 50b589b85f1caa68846316e8b3dbe4f8c416775b (diff) |
De-duplicate device discovery code (Darwin)
- use the shared *._p.h file/class declaration for the private class
- use the shared *.cpp with the public class implementation
- get rid of *_ios.mm - iOS/tvOS/watchOS specific implementation
and use the shared (by macOS, iOS, tvOS, watchOS) *_darwin.mm source.
- get rid of somewhat weird 'isValid' in the private class, it is
is not taken care of in the public API anyway and today its
whole concept/usage looks (quite) buggy to me. I only have to
check that the default controller is not nil and has the
state 'ON'.
Task-number: QTBUG-75348
Change-Id: I5383e4f8df02ac12f069c2f59e252cb8a200800b
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
-rw-r--r-- | src/bluetooth/bluetooth.pro | 6 | ||||
-rw-r--r-- | src/bluetooth/osx/btdelegates.cpp | 4 | ||||
-rw-r--r-- | src/bluetooth/osx/btdelegates_p.h | 16 | ||||
-rw-r--r-- | src/bluetooth/osx/btraii_p.h | 5 | ||||
-rw-r--r-- | src/bluetooth/osx/osxbt.pri | 21 | ||||
-rw-r--r-- | src/bluetooth/osx/osxbtdeviceinquiry.mm | 24 | ||||
-rw-r--r-- | src/bluetooth/osx/osxbtdeviceinquiry_p.h | 24 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm (renamed from src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm) | 327 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm | 458 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_p.h | 63 |
10 files changed, 184 insertions, 764 deletions
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro index 2bcdee12..71c8e6ed 100644 --- a/src/bluetooth/bluetooth.pro +++ b/src/bluetooth/bluetooth.pro @@ -162,7 +162,7 @@ qtConfig(bluez) { include(osx/osxbt.pri) OBJECTIVE_SOURCES += \ qbluetoothlocaldevice_osx.mm \ - qbluetoothdevicediscoveryagent_osx.mm \ + qbluetoothdevicediscoveryagent_darwin.mm \ qbluetoothserviceinfo_osx.mm \ qbluetoothservicediscoveryagent_osx.mm \ qbluetoothsocket_osx.mm \ @@ -177,7 +177,6 @@ qtConfig(bluez) { qbluetoothtransferreply_osx_p.h \ qlowenergycontroller_osx_p.h - SOURCES -= qbluetoothdevicediscoveryagent.cpp SOURCES -= qbluetoothserviceinfo.cpp SOURCES -= qbluetoothservicediscoveryagent.cpp SOURCES -= qbluetoothsocket.cpp @@ -192,7 +191,7 @@ qtConfig(bluez) { LIBS_PRIVATE += -framework Foundation -framework CoreBluetooth OBJECTIVE_SOURCES += \ - qbluetoothdevicediscoveryagent_ios.mm \ + qbluetoothdevicediscoveryagent_darwin.mm \ qlowenergycontroller_osx.mm \ qlowenergyservice_osx.mm @@ -208,7 +207,6 @@ qtConfig(bluez) { qbluetoothsocket_dummy.cpp \ qbluetoothserver_p.cpp - SOURCES -= qbluetoothdevicediscoveryagent.cpp SOURCES -= qlowenergyservice.cpp SOURCES -= qlowenergycontroller.cpp SOURCES -= qlowenergycontrollerbase.cpp diff --git a/src/bluetooth/osx/btdelegates.cpp b/src/bluetooth/osx/btdelegates.cpp index c86516f9..531ca1df 100644 --- a/src/bluetooth/osx/btdelegates.cpp +++ b/src/bluetooth/osx/btdelegates.cpp @@ -39,6 +39,8 @@ #include "btdelegates_p.h" +#if defined(Q_OS_MACOS) + QT_BEGIN_NAMESPACE namespace DarwinBluetooth { @@ -70,3 +72,5 @@ SocketListener::~SocketListener() } // namespace DarwinBluetooth QT_END_NAMESPACE + +#endif diff --git a/src/bluetooth/osx/btdelegates_p.h b/src/bluetooth/osx/btdelegates_p.h index cb29b87e..11fbcc28 100644 --- a/src/bluetooth/osx/btdelegates_p.h +++ b/src/bluetooth/osx/btdelegates_p.h @@ -58,9 +58,9 @@ #include <QtCore/qsharedpointer.h> #include <QtCore/qglobal.h> -#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) +#if defined(Q_OS_MACOS) + #include <IOKit/IOReturn.h> -#endif #include <cstdint> @@ -72,8 +72,6 @@ class QByteArray; namespace DarwinBluetooth { -#if defined(Q_OS_MACOS) - class DeviceInquiryDelegate { public: @@ -81,7 +79,7 @@ public: virtual void inquiryFinished() = 0; virtual void error(IOReturn error) = 0; - virtual void deviceFound(void *ioBluetoothDevice) = 0; + virtual void classicDeviceFound(void *ioBluetoothDevice) = 0; }; class PairingDelegate @@ -141,15 +139,11 @@ public: virtual void openNotifyL2CAP(void *l2capChannel) = 0; }; -#else - -#error "This header is only for macOS (Bluetooth Classic only)" - -#endif // Q_OS_MACOS - } // namespace DarwinBluetooth QT_END_NAMESPACE +#endif // Q_OS_MACOS + #endif // DARWINBTDELEGATES_P_H diff --git a/src/bluetooth/osx/btraii_p.h b/src/bluetooth/osx/btraii_p.h index b64defb6..6053d63b 100644 --- a/src/bluetooth/osx/btraii_p.h +++ b/src/bluetooth/osx/btraii_p.h @@ -107,6 +107,11 @@ public: return static_cast<ObjCType *>(objCInstance); } + operator bool() const + { + return !!objCInstance; + } + private: void *objCInstance = nullptr; }; diff --git a/src/bluetooth/osx/osxbt.pri b/src/bluetooth/osx/osxbt.pri index ae6111ee..89276310 100644 --- a/src/bluetooth/osx/osxbt.pri +++ b/src/bluetooth/osx/osxbt.pri @@ -1,8 +1,15 @@ -SOURCES += osx/uistrings.cpp osx/osxbtnotifier.cpp +SOURCES += osx/uistrings.cpp \ + osx/osxbtnotifier.cpp \ + osx/btdelegates.cpp + PRIVATE_HEADERS += osx/uistrings_p.h \ - osx/osxbtgcdtimer_p.h + osx/osxbtgcdtimer_p.h \ + osx/btraii_p.h \ + osx/btdelegates_p.h + -OBJECTIVE_SOURCES += osx/osxbtgcdtimer.mm +OBJECTIVE_SOURCES += osx/osxbtgcdtimer.mm \ + osx/btraii.mm #QMAKE_CXXFLAGS_WARN_ON += -Wno-nullability-completeness CONFIG(osx) { @@ -21,9 +28,7 @@ CONFIG(osx) { osx/osxbluetooth_p.h \ osx/osxbtcentralmanager_p.h \ osx/osxbtnotifier_p.h \ - osx/osxbtperipheralmanager_p.h \ - osx/btraii_p.h \ - osx/btdelegates_p.h + osx/osxbtperipheralmanager_p.h OBJECTIVE_SOURCES += osx/osxbtutility.mm \ osx/osxbtdevicepair.mm \ @@ -38,9 +43,7 @@ CONFIG(osx) { osx/osxbtobexsession.mm \ osx/osxbtledeviceinquiry.mm \ osx/osxbtcentralmanager.mm \ - osx/osxbtperipheralmanager.mm \ - osx/btraii.mm - SOURCES += osx/btdelegates.cpp + osx/osxbtperipheralmanager.mm } else { PRIVATE_HEADERS += osx/osxbtutility_p.h \ osx/osxbtledeviceinquiry_p.h \ diff --git a/src/bluetooth/osx/osxbtdeviceinquiry.mm b/src/bluetooth/osx/osxbtdeviceinquiry.mm index 57cd73e1..3a77c1f7 100644 --- a/src/bluetooth/osx/osxbtdeviceinquiry.mm +++ b/src/bluetooth/osx/osxbtdeviceinquiry.mm @@ -43,30 +43,16 @@ #include <QtCore/qloggingcategory.h> #include <QtCore/qdebug.h> -QT_BEGIN_NAMESPACE - -namespace OSXBluetooth { - -DeviceInquiryDelegate::~DeviceInquiryDelegate() -{ -} - -} - - -QT_END_NAMESPACE - QT_USE_NAMESPACE - @implementation QT_MANGLE_NAMESPACE(OSXBTDeviceInquiry) { IOBluetoothDeviceInquiry *m_inquiry; bool m_active; - QT_PREPEND_NAMESPACE(OSXBluetooth::DeviceInquiryDelegate) *m_delegate;//C++ "delegate" + DarwinBluetooth::DeviceInquiryDelegate *m_delegate;//C++ "delegate" } -- (id)initWithDelegate:(OSXBluetooth::DeviceInquiryDelegate *)delegate +- (id)initWithDelegate:(DarwinBluetooth::DeviceInquiryDelegate *)delegate { if (self = [super init]) { Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid device inquiry delegate (null)"); @@ -158,9 +144,9 @@ QT_USE_NAMESPACE // QtBluetooth has not too many error codes, 'UnknownError' is not really // useful, report the actual error code here: qCWarning(QT_BT_OSX) << "IOKit error code: " << error; - m_delegate->error(sender, error); + m_delegate->error(error); } else { - m_delegate->inquiryFinished(sender); + m_delegate->inquiryFinished(); } } @@ -171,7 +157,7 @@ QT_USE_NAMESPACE return; Q_ASSERT_X(m_delegate, Q_FUNC_INFO, "invalid device inquiry delegate (null)"); - m_delegate->deviceFound(sender, device); + m_delegate->classicDeviceFound(device); } - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry *)sender diff --git a/src/bluetooth/osx/osxbtdeviceinquiry_p.h b/src/bluetooth/osx/osxbtdeviceinquiry_p.h index 0fec2db2..86ed3fdf 100644 --- a/src/bluetooth/osx/osxbtdeviceinquiry_p.h +++ b/src/bluetooth/osx/osxbtdeviceinquiry_p.h @@ -52,36 +52,16 @@ // #include "osxbluetooth_p.h" +#include "btdelegates_p.h" #include <QtCore/qglobal.h> #include <Foundation/Foundation.h> #include <IOKit/IOReturn.h> -@class QT_MANGLE_NAMESPACE(OSXBTDeviceInquiry); - -QT_BEGIN_NAMESPACE - -namespace OSXBluetooth { - -class DeviceInquiryDelegate { -public: - typedef QT_MANGLE_NAMESPACE(OSXBTDeviceInquiry) DeviceInquiryObjC; - - virtual ~DeviceInquiryDelegate(); - - virtual void inquiryFinished(IOBluetoothDeviceInquiry *inq) = 0; - virtual void error(IOBluetoothDeviceInquiry *inq, IOReturn error) = 0; - virtual void deviceFound(IOBluetoothDeviceInquiry *inq, IOBluetoothDevice *device) = 0; -}; - -} - -QT_END_NAMESPACE - @interface QT_MANGLE_NAMESPACE(OSXBTDeviceInquiry) : NSObject<IOBluetoothDeviceInquiryDelegate> -- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(OSXBluetooth::DeviceInquiryDelegate) *)delegate; +- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth::DeviceInquiryDelegate) *)delegate; - (void)dealloc; - (bool)isActive; diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm index f62ca0dd..d9883d28 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm @@ -37,11 +37,14 @@ ** ****************************************************************************/ +#include "qbluetoothdevicediscoveryagent_p.h" #include "qbluetoothdevicediscoveryagent.h" + #include "osx/osxbtledeviceinquiry_p.h" +#ifdef Q_OS_MACOS #include "osx/osxbtdeviceinquiry_p.h" -#include "qbluetoothlocaldevice.h" #include "osx/osxbtsdpinquiry_p.h" +#endif // Q_OS_MACOS #include "qbluetoothdeviceinfo.h" #include "osx/osxbtnotifier_p.h" #include "osx/osxbtutility_p.h" @@ -51,13 +54,14 @@ #include "qbluetoothaddress.h" #include "osx/uistrings_p.h" #include "qbluetoothuuid.h" +#include "osx/btraii_p.h" #include <QtCore/qloggingcategory.h> #include <QtCore/qscopedpointer.h> +#include <QtCore/qvector.h> #include <QtCore/qglobal.h> #include <QtCore/qstring.h> #include <QtCore/qdebug.h> -#include <QtCore/qlist.h> #include <Foundation/Foundation.h> @@ -75,108 +79,42 @@ void registerQDeviceDiscoveryMetaType() initDone = true; } } +#ifdef Q_OS_MACOS +using InquiryObjC = QT_MANGLE_NAMESPACE(OSXBTDeviceInquiry); +#endif // Q_OS_MACOS -}//namespace - -class QBluetoothDeviceDiscoveryAgentPrivate : public QObject, - public OSXBluetooth::DeviceInquiryDelegate -{ - friend class QBluetoothDeviceDiscoveryAgent; -public: - template<class T> - using ObjCScopedPointer = OSXBluetooth::ObjCScopedPointer<T>; - using LEDeviceInquiryObjC = QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry); - - QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress & address, - QBluetoothDeviceDiscoveryAgent *q); - - ~QBluetoothDeviceDiscoveryAgentPrivate() override; - - bool isValid() const; - bool isActive() const; - - void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods); - void startClassic(); - void startLE(); - void stop(); - -private: - enum AgentState { - NonActive, - ClassicScan, - LEScan - }; - - // DeviceInquiryDelegate: - void inquiryFinished(IOBluetoothDeviceInquiry *inq) override; - void error(IOBluetoothDeviceInquiry *inq, IOReturn error) override; - void deviceFound(IOBluetoothDeviceInquiry *inq, IOBluetoothDevice *device) 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. - void deviceFound(const QBluetoothDeviceInfo &newDeviceInfo); - - void setError(IOReturn error, const QString &text = QString()); - void setError(QBluetoothDeviceDiscoveryAgent::Error, - const QString &text = QString()); - - QBluetoothDeviceDiscoveryAgent *q_ptr; - AgentState agentState; - - QBluetoothAddress adapterAddress; +using LEInquiryObjC = QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry); - bool startPending; - bool stopPending; - - QBluetoothDeviceDiscoveryAgent::Error lastError; - QString errorString; - - QBluetoothDeviceDiscoveryAgent::InquiryType inquiryType; - - using DeviceInquiry = ObjCScopedPointer<DeviceInquiryObjC>; - DeviceInquiry inquiry; - - using LEDeviceInquiry = ObjCScopedPointer<LEDeviceInquiryObjC>; - LEDeviceInquiry inquiryLE; - - using HostController = ObjCScopedPointer<IOBluetoothHostController>; - HostController hostController; - - using DevicesList = QList<QBluetoothDeviceInfo>; - DevicesList discoveredDevices; - - int lowEnergySearchTimeout; - QBluetoothDeviceDiscoveryAgent::DiscoveryMethods requestedMethods; -}; +} //namespace QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &adapter, QBluetoothDeviceDiscoveryAgent *q) : - q_ptr(q), + inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry), + lastError(QBluetoothDeviceDiscoveryAgent::NoError), agentState(NonActive), adapterAddress(adapter), startPending(false), stopPending(false), - lastError(QBluetoothDeviceDiscoveryAgent::NoError), - inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry), lowEnergySearchTimeout(OSXBluetooth::defaultLEScanTimeoutMS), - requestedMethods(QBluetoothDeviceDiscoveryAgent::ClassicMethod - | QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) +#ifdef Q_OS_MACOS + requestedMethods(QBluetoothDeviceDiscoveryAgent::ClassicMethod | QBluetoothDeviceDiscoveryAgent::LowEnergyMethod), +#else + requestedMethods(QBluetoothDeviceDiscoveryAgent::ClassicMethod), +#endif // Q_OS_MACOS + q_ptr(q) { registerQDeviceDiscoveryMetaType(); Q_ASSERT_X(q != nullptr, Q_FUNC_INFO, "invalid q_ptr (null)"); - HostController controller([[IOBluetoothHostController defaultController] retain]); - if (!controller || [controller powerState] != kBluetoothHCIPowerStateON) { +#ifdef Q_OS_MACOS + IOBluetoothHostController *hostController = [IOBluetoothHostController defaultController]; + if (!hostController || [hostController powerState] != kBluetoothHCIPowerStateON) { qCCritical(QT_BT_OSX) << "no default host controller or adapter is off"; return; } - - hostController.reset(controller.take()); + controller.reset(hostController, DarwinBluetooth::RetainPolicy::doInitialRetain); +#endif } QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() @@ -185,7 +123,7 @@ QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() // 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(); + LEInquiryObjC *inq = inquiryLE.getAs<LEInquiryObjC>(); dispatch_sync(leQueue, ^{ [inq stop]; }); @@ -193,11 +131,6 @@ QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() } } -bool QBluetoothDeviceDiscoveryAgentPrivate::isValid() const -{ - return hostController && [hostController powerState] == kBluetoothHCIPowerStateON; -} - bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const { if (startPending) @@ -211,12 +144,19 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods) { - Q_ASSERT(isValid()); Q_ASSERT(!isActive()); Q_ASSERT(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError); Q_ASSERT(methods & (QBluetoothDeviceDiscoveryAgent::ClassicMethod | QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)); +#ifdef Q_OS_MACOS + if (!controller) { + setError(QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError); + emit q_ptr->error(lastError); + return; + } +#endif // Q_OS_MACOS + requestedMethods = methods; if (stopPending) { @@ -230,16 +170,18 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent agentState = NonActive; discoveredDevices.clear(); setError(QBluetoothDeviceDiscoveryAgent::NoError); - +#ifdef Q_OS_MACOS if (requestedMethods & QBluetoothDeviceDiscoveryAgent::ClassicMethod) return startClassic(); +#endif // Q_OS_MACOS startLE(); } +#ifdef Q_OS_MACOS + void QBluetoothDeviceDiscoveryAgentPrivate::startClassic() { - Q_ASSERT(isValid()); Q_ASSERT(!isActive()); Q_ASSERT(lastError == QBluetoothDeviceDiscoveryAgent::NoError); Q_ASSERT(requestedMethods & QBluetoothDeviceDiscoveryAgent::ClassicMethod); @@ -249,7 +191,9 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startClassic() if (!inquiry) { // The first Classic scan for this DDA. - inquiry.reset([[DeviceInquiryObjC alloc]initWithDelegate:this]); + inquiry.reset([[InquiryObjC alloc] initWithDelegate:this], + DarwinBluetooth::RetainPolicy::noInitialRetain); + if (!inquiry) { qCCritical(QT_BT_OSX) << "failed to initialize an Classic device inquiry"; setError(QBluetoothDeviceDiscoveryAgent::UnknownError, @@ -261,7 +205,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startClassic() agentState = ClassicScan; - const IOReturn res = [inquiry start]; + const IOReturn res = [inquiry.getAs<InquiryObjC>() start]; if (res != kIOReturnSuccess) { setError(res, QCoreApplication::translate(DEV_DISCOVERY, DD_NOT_STARTED)); agentState = NonActive; @@ -269,9 +213,10 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startClassic() } } +#endif // Q_OS_MACOS + void QBluetoothDeviceDiscoveryAgentPrivate::startLE() { - Q_ASSERT(isValid()); Q_ASSERT(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError); Q_ASSERT(requestedMethods & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); @@ -291,7 +236,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLE() this, DeviceMemFunPtr(&QBluetoothDeviceDiscoveryAgentPrivate::deviceFound)); // Check queue and create scanner: - inquiryLE.reset([[LEDeviceInquiryObjC alloc] initWithNotifier:notifier.data()]); + inquiryLE.reset([[LEInquiryObjC alloc] initWithNotifier:notifier.data()], + DarwinBluetooth::RetainPolicy::noInitialRetain); if (inquiryLE) notifier.take(); // Whatever happens next, inquiryLE is already the owner ... @@ -307,7 +253,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLE() // Now start in on LE queue: agentState = LEScan; // We need the local variable so that it's retained ... - LEDeviceInquiryObjC *inq = inquiryLE.data(); + LEInquiryObjC *inq = inquiryLE.getAs<LEInquiryObjC>(); dispatch_async(leQueue, ^{ [inq startWithTimeout:lowEnergySearchTimeout]; }); @@ -315,7 +261,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLE() 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"); @@ -328,8 +273,9 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop() setError(QBluetoothDeviceDiscoveryAgent::NoError); +#ifdef Q_OS_MACOS if (agentState == ClassicScan) { - const IOReturn res = [inquiry stop]; + const IOReturn res = [inquiry.getAs<InquiryObjC>() stop]; if (res != kIOReturnSuccess) { qCWarning(QT_BT_OSX) << "failed to stop"; startPending = prevStart; @@ -338,10 +284,14 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop() emit q_ptr->error(lastError); } } else { +#else + { + Q_UNUSED(prevStart) +#endif // Q_OS_MACOS dispatch_queue_t leQueue(qt_LE_queue()); Q_ASSERT(leQueue); // We need the local variable so that it's retained ... - LEDeviceInquiryObjC *inq = inquiryLE.data(); + LEInquiryObjC *inq = inquiryLE.getAs<LEInquiryObjC>(); dispatch_sync(leQueue, ^{ [inq stop]; }); @@ -351,12 +301,10 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop() } } -void QBluetoothDeviceDiscoveryAgentPrivate::inquiryFinished(IOBluetoothDeviceInquiry *inq) -{ - Q_UNUSED(inq) - - Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid device discovery agent"); //We can never be here. +#ifdef Q_OS_MACOS +void QBluetoothDeviceDiscoveryAgentPrivate::inquiryFinished() +{ // The subsequent start(LE) function (if any) // will (re)set the correct state. agentState = NonActive; @@ -381,12 +329,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::inquiryFinished(IOBluetoothDeviceInq } } -void QBluetoothDeviceDiscoveryAgentPrivate::error(IOBluetoothDeviceInquiry *inq, IOReturn error) +void QBluetoothDeviceDiscoveryAgentPrivate::error(IOReturn error) { - Q_UNUSED(inq) - - Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid device discovery agent"); - startPending = false; stopPending = false; @@ -395,12 +339,11 @@ void QBluetoothDeviceDiscoveryAgentPrivate::error(IOBluetoothDeviceInquiry *inq, emit q_ptr->error(lastError); } -void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(IOBluetoothDeviceInquiry *inq, IOBluetoothDevice *device) +void QBluetoothDeviceDiscoveryAgentPrivate::classicDeviceFound(void *obj) { - Q_UNUSED(inq) - - Q_ASSERT_X(isValid(), Q_FUNC_INFO, "invalid device discovery agent"); + auto device = static_cast<IOBluetoothDevice *>(obj); Q_ASSERT_X(device, Q_FUNC_INFO, "invalid IOBluetoothDevice (nil)"); + Q_ASSERT_X(agentState == ClassicScan, Q_FUNC_INFO, "invalid agent state (expected classic scan)"); @@ -417,7 +360,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(IOBluetoothDeviceInquiry if (device.name) deviceName = QString::fromNSString(device.name); - const qint32 classOfDevice(device.classOfDevice); + const auto classOfDevice = qint32(device.classOfDevice); QBluetoothDeviceInfo deviceInfo(deviceAddress, deviceName, classOfDevice); deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration); @@ -439,6 +382,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::setError(IOReturn error, const QStri setError(QBluetoothDeviceDiscoveryAgent::UnknownError, text); } +#endif // Q_OS_MACOS + void QBluetoothDeviceDiscoveryAgentPrivate::setError(QBluetoothDeviceDiscoveryAgent::Error error, const QString &text) { lastError = error; @@ -459,14 +404,14 @@ void QBluetoothDeviceDiscoveryAgentPrivate::setError(QBluetoothDeviceDiscoveryAg case QBluetoothDeviceDiscoveryAgent::InputOutputError: errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_IO); break; + case QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError: + errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_NOTSUPPORTED); + break; case QBluetoothDeviceDiscoveryAgent::UnknownError: default: errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_UNKNOWN_ERROR); } } - - if (lastError != QBluetoothDeviceDiscoveryAgent::NoError) - qCDebug(QT_BT_OSX) << "error set:"<<errorString; } void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error) @@ -487,6 +432,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported() { qCDebug(QT_BT_OSX) << "no Bluetooth LE support"; +#ifdef Q_OS_MACOS if (requestedMethods & QBluetoothDeviceDiscoveryAgent::ClassicMethod) { // Having both Classic | LE means this is not an error. LEinquiryFinished(); @@ -497,6 +443,13 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported() // as UnsupportedDiscoveryMethod. LEinquiryError(QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod); } +#else + inquiryLE.reset(); + startPending = false; + stopPending = false; + setError(QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError); + emit q_ptr->error(lastError); +#endif } void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished() @@ -522,8 +475,12 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(const QBluetoothDeviceIn // Core Bluetooth does not allow us to access addresses, we have to use uuid instead. // This uuid has nothing to do with uuids in Bluetooth in general (it's generated by // Apple's framework using some algorithm), but it's a 128-bit uuid after all. - const bool isLE = newDeviceInfo.coreConfigurations() == QBluetoothDeviceInfo::LowEnergyCoreConfiguration; - + const bool isLE = +#ifdef Q_OS_MACOS + newDeviceInfo.coreConfigurations() == QBluetoothDeviceInfo::LowEnergyCoreConfiguration; +#else + true; +#endif // Q_OS_MACOS for (int i = 0, e = discoveredDevices.size(); i < e; ++i) { if (isLE) { if (discoveredDevices[i].deviceUuid() == newDeviceInfo.deviceUuid()) { @@ -564,6 +521,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(const QBluetoothDeviceIn return; } } else { +#ifdef Q_OS_MACOS if (discoveredDevices[i].address() == newDeviceInfo.address()) { if (discoveredDevices[i] == newDeviceInfo) return; @@ -572,6 +530,9 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(const QBluetoothDeviceIn emit q_ptr->deviceDiscovered(newDeviceInfo); return; } +#else + Q_UNREACHABLE(); +#endif // Q_OS_MACOS } } @@ -579,125 +540,13 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(const QBluetoothDeviceIn emit q_ptr->deviceDiscovered(newDeviceInfo); } -QBluetoothDeviceDiscoveryAgent::QBluetoothDeviceDiscoveryAgent(QObject *parent) : - QObject(parent), - d_ptr(new QBluetoothDeviceDiscoveryAgentPrivate(QBluetoothAddress(), this)) -{ -} - -QBluetoothDeviceDiscoveryAgent::QBluetoothDeviceDiscoveryAgent( - const QBluetoothAddress &deviceAdapter, QObject *parent) : - QObject(parent), - d_ptr(new QBluetoothDeviceDiscoveryAgentPrivate(deviceAdapter, this)) -{ - if (!deviceAdapter.isNull()) { - const QList<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices(); - for (const QBluetoothHostInfo &hostInfo : localDevices) { - if (hostInfo.address() == deviceAdapter) - return; - } - d_ptr->setError(InvalidBluetoothAdapterError); - } -} - -QBluetoothDeviceDiscoveryAgent::~QBluetoothDeviceDiscoveryAgent() -{ - delete d_ptr; -} - -QBluetoothDeviceDiscoveryAgent::InquiryType QBluetoothDeviceDiscoveryAgent::inquiryType() const -{ - return d_ptr->inquiryType; -} - -void QBluetoothDeviceDiscoveryAgent::setInquiryType(InquiryType type) -{ - d_ptr->inquiryType = type; -} - -QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices() const -{ - return d_ptr->discoveredDevices; -} - QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods() { +#ifdef Q_OS_MACOS return ClassicMethod | LowEnergyMethod; -} - -void QBluetoothDeviceDiscoveryAgent::start() -{ - start(supportedDiscoveryMethods()); -} - -void QBluetoothDeviceDiscoveryAgent::start(DiscoveryMethods methods) -{ - if (methods == NoMethod) - return; - - if ((supportedDiscoveryMethods() & methods) != methods) { - d_ptr->lastError = UnsupportedDiscoveryMethod; - d_ptr->errorString = tr("One or more device discovery methods " - "are not supported on this platform"); - emit error(d_ptr->lastError); - return; - } - - if (d_ptr->lastError != InvalidBluetoothAdapterError) { - if (d_ptr->isValid()) { - if (!isActive()) - d_ptr->start(methods); - } 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() -{ - if (d_ptr->isValid()) { - if (isActive() && d_ptr->lastError != InvalidBluetoothAdapterError) - d_ptr->stop(); - } -} - -bool QBluetoothDeviceDiscoveryAgent::isActive() const -{ - if (d_ptr->isValid()) - return d_ptr->isActive(); - - return false; -} - -QBluetoothDeviceDiscoveryAgent::Error QBluetoothDeviceDiscoveryAgent::error() const -{ - return d_ptr->lastError; -} - -QString QBluetoothDeviceDiscoveryAgent::errorString() const -{ - return d_ptr->errorString; -} - -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; -} - -int QBluetoothDeviceDiscoveryAgent::lowEnergyDiscoveryTimeout() const -{ - return d_ptr->lowEnergySearchTimeout; +#else + return LowEnergyMethod; +#endif // Q_OS_MACOS } QT_END_NAMESPACE diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm deleted file mode 100644 index 059f244d..00000000 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm +++ /dev/null @@ -1,458 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#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> -#include <QtCore/qlist.h> - -#include <CoreBluetooth/CoreBluetooth.h> - -QT_BEGIN_NAMESPACE - -namespace -{ - -void registerQDeviceDiscoveryMetaType() -{ - static bool initDone = false; - if (!initDone) { - qRegisterMetaType<QBluetoothDeviceInfo>(); - qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::Error>(); - initDone = true; - } -} - -}//namespace - -class QBluetoothDeviceDiscoveryAgentPrivate : public QObject -{ - friend class QBluetoothDeviceDiscoveryAgent; - -public: - QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &address, - QBluetoothDeviceDiscoveryAgent *q); - virtual ~QBluetoothDeviceDiscoveryAgentPrivate(); - - bool isActive() const; - - void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods m); - void stop(); - -private: - using LEDeviceInquiryObjC = QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry); - - void LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error); - void LEnotSupported(); - void LEdeviceFound(const QBluetoothDeviceInfo &info); - void LEinquiryFinished(); - - void setError(QBluetoothDeviceDiscoveryAgent::Error, const QString &text = QString()); - - QBluetoothDeviceDiscoveryAgent *q_ptr; - - QBluetoothDeviceDiscoveryAgent::Error lastError; - QString errorString; - - QBluetoothDeviceDiscoveryAgent::InquiryType inquiryType; - - using LEDeviceInquiry = OSXBluetooth::ObjCScopedPointer<LEDeviceInquiryObjC>; - LEDeviceInquiry inquiryLE; - - using DevicesList = QList<QBluetoothDeviceInfo>; - DevicesList discoveredDevices; - - bool startPending; - bool stopPending; - - int lowEnergySearchTimeout; -}; - -QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &adapter, - QBluetoothDeviceDiscoveryAgent *q) : - q_ptr(q), - lastError(QBluetoothDeviceDiscoveryAgent::NoError), - inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry), - startPending(false), - stopPending(false), - lowEnergySearchTimeout(OSXBluetooth::defaultLEScanTimeoutMS) -{ - Q_UNUSED(adapter); - - registerQDeviceDiscoveryMetaType(); - Q_ASSERT_X(q != nullptr, Q_FUNC_INFO, "invalid q_ptr (null)"); -} - -QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() -{ - 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_sync(leQueue, ^{ - [inq stop]; - }); - } - } -} - -bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const -{ - if (startPending) - return true; - if (stopPending) - return false; - - return inquiryLE; -} - -void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods /*methods*/) -{ - Q_ASSERT_X(!isActive(), Q_FUNC_INFO, "called on active device discovery agent"); - - if (stopPending) { - startPending = true; - return; - } - - using namespace OSXBluetooth; - - 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); - - // Create a local variable - to have a strong referece in a block. - LEDeviceInquiryObjC *inq = inquiryLE.data(); - dispatch_async(leQueue, ^{ - [inq startWithTimeout:lowEnergySearchTimeout]; - }); -} - -void QBluetoothDeviceDiscoveryAgentPrivate::stop() -{ - Q_ASSERT_X(isActive(), Q_FUNC_INFO, "called whithout active inquiry"); - - startPending = false; - stopPending = true; - - dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue()); - Q_ASSERT(leQueue); - - setError(QBluetoothDeviceDiscoveryAgent::NoError); - - // Create a local variable - to have a strong referece in a block. - LEDeviceInquiryObjC *inq = inquiryLE.data(); - dispatch_sync(leQueue, ^{ - [inq stop]; - }); - // We consider LE scan to be stopped immediately and - // do not care about this LEDeviceInquiry object anymore. - LEinquiryFinished(); -} - -void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error) -{ - // At the moment the only error reported by osxbtledeviceinquiry - // 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"); - - inquiryLE.reset(); - - startPending = false; - stopPending = false; - setError(error); - emit q_ptr->error(lastError); -} - -void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported() -{ - inquiryLE.reset(); - - startPending = false; - stopPending = false; - setError(QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError); - emit q_ptr->error(lastError); -} - -void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound(const QBluetoothDeviceInfo &newDeviceInfo) -{ - // Update, append or discard. - for (int i = 0, e = discoveredDevices.size(); i < e; ++i) { - if (discoveredDevices[i].deviceUuid() == newDeviceInfo.deviceUuid()) { - QBluetoothDeviceInfo::Fields updatedFields = QBluetoothDeviceInfo::Field::None; - if (discoveredDevices[i].rssi() != newDeviceInfo.rssi()) { - qCDebug(QT_BT_OSX) << "Updating RSSI for" << newDeviceInfo.address() - << newDeviceInfo.rssi(); - discoveredDevices[i].setRssi(newDeviceInfo.rssi()); - updatedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI); - } - - if (discoveredDevices[i].manufacturerData() != newDeviceInfo.manufacturerData()) { - qCDebug(QT_BT_OSX) << "Updating manufacturer data for" << newDeviceInfo.address(); - const QVector<quint16> keys = newDeviceInfo.manufacturerIds(); - for (auto key: keys) - discoveredDevices[i].setManufacturerData(key, newDeviceInfo.manufacturerData(key)); - updatedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData); - } - - if (lowEnergySearchTimeout > 0) { - if (discoveredDevices[i] != newDeviceInfo) { - discoveredDevices.replace(i, newDeviceInfo); - emit q_ptr->deviceDiscovered(newDeviceInfo); - } else { - if (!updatedFields.testFlag(QBluetoothDeviceInfo::Field::None)) - emit q_ptr->deviceUpdated(discoveredDevices[i], updatedFields); - } - - return; - } - - discoveredDevices.replace(i, newDeviceInfo); - emit q_ptr->deviceDiscovered(newDeviceInfo); - - if (!updatedFields.testFlag(QBluetoothDeviceInfo::Field::None)) - emit q_ptr->deviceUpdated(discoveredDevices[i], updatedFields); - - return; - } - } - - discoveredDevices.append(newDeviceInfo); - emit q_ptr->deviceDiscovered(newDeviceInfo); -} - -void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished() -{ - inquiryLE.reset(); - - if (stopPending && !startPending) { - stopPending = false; - emit q_ptr->canceled(); - } else if (startPending) { - startPending = false; - stopPending = false; - // always the same method for start() on iOS - // classic search not supported - start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); - } else { - emit q_ptr->finished(); - } -} - -void QBluetoothDeviceDiscoveryAgentPrivate::setError(QBluetoothDeviceDiscoveryAgent::Error error, - const QString &text) -{ - lastError = error; - - if (text.length() > 0) { - errorString = text; - } else { - switch (lastError) { - case QBluetoothDeviceDiscoveryAgent::NoError: - errorString = QString(); - break; - case QBluetoothDeviceDiscoveryAgent::PoweredOffError: - errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_POWERED_OFF); - break; - case QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError: - errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_INVALID_ADAPTER); - break; - case QBluetoothDeviceDiscoveryAgent::InputOutputError: - errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_IO); - break; - case QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError: - errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_NOTSUPPORTED); - break; - case QBluetoothDeviceDiscoveryAgent::UnknownError: - default: - errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_UNKNOWN_ERROR); - } - } -} - -QBluetoothDeviceDiscoveryAgent::QBluetoothDeviceDiscoveryAgent(QObject *parent) : - QObject(parent), - d_ptr(new QBluetoothDeviceDiscoveryAgentPrivate(QBluetoothAddress(), this)) -{ -} - -QBluetoothDeviceDiscoveryAgent::QBluetoothDeviceDiscoveryAgent( - const QBluetoothAddress &deviceAdapter, QObject *parent) : - QObject(parent), - d_ptr(new QBluetoothDeviceDiscoveryAgentPrivate(deviceAdapter, this)) -{ - if (!deviceAdapter.isNull()) { - qCWarning(QT_BT_OSX) << "local device address is " - "not available, provided address is ignored"; - d_ptr->setError(InvalidBluetoothAdapterError); - } -} - -QBluetoothDeviceDiscoveryAgent::~QBluetoothDeviceDiscoveryAgent() -{ - delete d_ptr; -} - -QBluetoothDeviceDiscoveryAgent::InquiryType QBluetoothDeviceDiscoveryAgent::inquiryType() const -{ - return d_ptr->inquiryType; -} - -void QBluetoothDeviceDiscoveryAgent::setInquiryType(QBluetoothDeviceDiscoveryAgent::InquiryType type) -{ - d_ptr->inquiryType = type; -} - -QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices() const -{ - return d_ptr->discoveredDevices; -} - -QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods() -{ - return LowEnergyMethod; -} - -void QBluetoothDeviceDiscoveryAgent::start() -{ - if (d_ptr->lastError != InvalidBluetoothAdapterError) { - if (!isActive()) - d_ptr->start(supportedDiscoveryMethods()); - else - 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() -{ - if (isActive() && d_ptr->lastError != InvalidBluetoothAdapterError) - d_ptr->stop(); -} - -bool QBluetoothDeviceDiscoveryAgent::isActive() const -{ - return d_ptr->isActive(); -} - -QBluetoothDeviceDiscoveryAgent::Error QBluetoothDeviceDiscoveryAgent::error() const -{ - return d_ptr->lastError; -} - -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 diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h index 3e76c13d..a59c6a94 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h @@ -58,6 +58,11 @@ #include <QtCore/QTimer> #endif +#ifdef Q_OS_DARWIN +#include "osx/btdelegates_p.h" +#include "osx/btraii_p.h" +#endif // Q_OS_DARWIN + #include <QtCore/QVariantMap> #include <QtBluetooth/QBluetoothAddress> @@ -93,11 +98,14 @@ class QWinRTBluetoothDeviceDiscoveryWorker; #endif class QBluetoothDeviceDiscoveryAgentPrivate -#if defined(QT_ANDROID_BLUETOOTH) || defined(QT_WINRT_BLUETOOTH) +#if defined(QT_ANDROID_BLUETOOTH) || defined(QT_WINRT_BLUETOOTH) || defined(Q_OS_DARWIN) : public QObject +#if defined(Q_OS_MACOS) + , public DarwinBluetooth::DeviceInquiryDelegate +#endif // Q_OS_MACOS { Q_OBJECT -#else +#else // BlueZ { #endif Q_DECLARE_PUBLIC(QBluetoothDeviceDiscoveryAgent) @@ -180,6 +188,57 @@ private: QTimer *leScanTimer; #endif +#ifdef Q_OS_DARWIN + + void startLE(); + +#ifdef Q_OS_MACOS + + void startClassic(); + + // Classic (IOBluetooth) inquiry delegate's methods: + void inquiryFinished() override; + void error(IOReturn error) override; + void classicDeviceFound(void *device) override; + // Classic (IOBluetooth) errors: + void setError(IOReturn error, const QString &text = QString()); + +#endif // Q_OS_MACOS + + // LE scan delegates (CoreBluetooth, all Darwin OSes): + void LEinquiryFinished(); + void LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error); + void LEnotSupported(); + + // LE errors: + void setError(QBluetoothDeviceDiscoveryAgent::Error, + const QString &text = QString()); + + // Both LE and Classic devices go there: + void deviceFound(const QBluetoothDeviceInfo &newDeviceInfo); + + enum AgentState { + NonActive, + ClassicScan, // macOS (IOBluetooth) only + LEScan + } agentState; + + QBluetoothAddress adapterAddress; + + bool startPending; + bool stopPending; + +#ifdef Q_OS_MACOS + + DarwinBluetooth::ScopedPointer controller; + DarwinBluetooth::ScopedPointer inquiry; + +#endif // Q_OS_MACOS + + DarwinBluetooth::ScopedPointer inquiryLE; + +#endif // Q_OS_DARWIN + int lowEnergySearchTimeout; QBluetoothDeviceDiscoveryAgent::DiscoveryMethods requestedMethods; QBluetoothDeviceDiscoveryAgent *q_ptr; |