summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm')
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm226
1 files changed, 114 insertions, 112 deletions
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
index 30a6acb6..3f4c6755 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
@@ -1,46 +1,53 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** 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:LGPL21$
+** $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 http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** 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 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** 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.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 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 "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>
@@ -50,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,
@@ -64,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());
@@ -85,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)");
}
@@ -152,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];
});
}
@@ -169,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");
@@ -180,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];
});
}
@@ -217,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
@@ -235,7 +231,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDisco
Q_FUNC_INFO, "unexpected error");
inquiryLE.reset();
- timer->stop();
startPending = false;
stopPending = false;
@@ -246,7 +241,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDisco
void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported()
{
inquiryLE.reset();
- timer->stop();
startPending = false;
stopPending = false;
@@ -275,7 +269,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound(const QBluetoothDevice
void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished()
{
inquiryLE.reset();
- timer->stop();
if (stopPending && !startPending) {
stopPending = false;
@@ -283,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)
{
@@ -367,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);
}
@@ -393,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()
@@ -424,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