summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2018-05-28 14:35:17 +0200
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2018-05-31 14:18:19 +0000
commit5bdc4e8b0b1e6664b7c289cfc9c1a9d12da6e87e (patch)
treeddfff4a9893fe45dbb6d9d890c19d405a4810f4a
parentc2513dce68f2643b0c62e13d16d376115d9c8476 (diff)
Reimplement scan/manager state timeouts using GCD timer
And remove some essentially duplicated code. Task-number: QTBUG-68422 Change-Id: I677581ebb0998d64a0081f568479efb7e8156474 Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
-rw-r--r--src/bluetooth/osx/osxbtgcdtimer.mm1
-rw-r--r--src/bluetooth/osx/osxbtledeviceinquiry.mm114
-rw-r--r--src/bluetooth/osx/osxbtledeviceinquiry_p.h18
3 files changed, 34 insertions, 99 deletions
diff --git a/src/bluetooth/osx/osxbtgcdtimer.mm b/src/bluetooth/osx/osxbtgcdtimer.mm
index 0a49c25c..095f8680 100644
--- a/src/bluetooth/osx/osxbtgcdtimer.mm
+++ b/src/bluetooth/osx/osxbtgcdtimer.mm
@@ -105,6 +105,7 @@
- (void)cancelTimer
{
cancelled = true;
+ timeoutHandler = nil;
}
@end
diff --git a/src/bluetooth/osx/osxbtledeviceinquiry.mm b/src/bluetooth/osx/osxbtledeviceinquiry.mm
index 60222370..2cece15b 100644
--- a/src/bluetooth/osx/osxbtledeviceinquiry.mm
+++ b/src/bluetooth/osx/osxbtledeviceinquiry.mm
@@ -65,9 +65,7 @@ QBluetoothUuid qt_uuid(NSUUID *nsUuid)
}
const int timeStepMS = 100;
-
const int powerOffTimeoutMS = 30000;
-const qreal powerOffTimeStepS = 30. / 100.;
struct AdvertisementData {
// That's what CoreBluetooth has:
@@ -115,14 +113,6 @@ QT_END_NAMESPACE
QT_USE_NAMESPACE
-@interface QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) (PrivateAPI) <CBCentralManagerDelegate>
-// These two methods are scheduled with a small time step
-// within a given timeout, they either re-schedule
-// themselves or emit a signal/stop some operation.
-- (void)stopScan;
-- (void)handlePoweredOff;
-@end
-
@implementation QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry)
-(id)initWithNotifier:(LECBManagerNotifier *)aNotifier
@@ -153,60 +143,22 @@ QT_USE_NAMESPACE
[super dealloc];
}
-- (void)stopScan
+- (void)timeout
{
- using namespace OSXBluetooth;
-
- // We never schedule stopScan if there is no timeout:
- Q_ASSERT(inquiryTimeoutMS > 0);
-
if (internalState == InquiryActive) {
- const int elapsed = scanTimer.elapsed();
- if (elapsed >= inquiryTimeoutMS) {
- [manager stopScan];
- [manager setDelegate:nil];
- internalState = InquiryFinished;
- Q_ASSERT(notifier);
- emit notifier->discoveryFinished();
- } else {
- // Re-schedule 'stopScan':
- dispatch_queue_t leQueue(qt_LE_queue());
- Q_ASSERT(leQueue);
- const int timeChunkMS = std::min(inquiryTimeoutMS - elapsed, timeStepMS);
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
- int64_t(timeChunkMS / 1000. * NSEC_PER_SEC)),
- leQueue,
- ^{
- [self stopScan];
- });
- }
- }
-}
-
-- (void)handlePoweredOff
-{
- // 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.
- using namespace OSXBluetooth;
-
- if (internalState == InquiryStarting) {
- if (errorTimer.elapsed() >= powerOffTimeoutMS) {
- [manager setDelegate:nil];
- internalState = ErrorPoweredOff;
- Q_ASSERT(notifier);
- emit notifier->CBManagerError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
- } else {
- dispatch_queue_t leQueue(qt_LE_queue());
- Q_ASSERT(leQueue);
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
- (int64_t)(powerOffTimeStepS * NSEC_PER_SEC)),
- leQueue,
- ^{
- [self handlePoweredOff];
- });
- }
+ [manager stopScan];
+ [manager setDelegate:nil];
+ internalState = InquiryFinished;
+ Q_ASSERT(notifier);
+ emit notifier->discoveryFinished();
+ } else if (internalState == InquiryStarting) {
+ // 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 this as an error.
+ [manager setDelegate:nil];
+ internalState = ErrorPoweredOff;
+ Q_ASSERT(notifier);
+ emit notifier->CBManagerError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
}
}
@@ -233,9 +185,6 @@ QT_USE_NAMESPACE
using namespace OSXBluetooth;
- dispatch_queue_t leQueue(qt_LE_queue());
- Q_ASSERT(leQueue);
-
const auto state = central.state;
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_10_0) || QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13)
if (state == CBManagerStatePoweredOn) {
@@ -246,18 +195,9 @@ QT_USE_NAMESPACE
internalState = InquiryActive;
if (inquiryTimeoutMS > 0) {
- // We have a finite-length discovery, schedule stopScan,
- // with a smaller time step, otherwise it can prevent
- // 'self' from being deleted in time, which is not good
- // (the block will retain 'self', waiting for timeout).
- scanTimer.start();
- const int timeChunkMS = std::min(timeStepMS, inquiryTimeoutMS);
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
- int64_t(timeChunkMS / 1000. * NSEC_PER_SEC)),
- leQueue,
- ^{
- [self stopScan];
- });
+ [elapsedTimer cancelTimer];
+ elapsedTimer.reset([[GCDTimerObjC alloc] initWithDelegate:self]);
+ [elapsedTimer startWithTimeout:inquiryTimeoutMS step:timeStepMS];
}
[manager scanForPeripheralsWithServices:nil options:nil];
@@ -287,19 +227,15 @@ QT_USE_NAMESPACE
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,
+ // enable Bluetooth in the "Settings" app. If a user does so,
// we'll receive 'PoweredOn' state update later.
- // No change in internalState. Wait for 30 seconds
- // (we split it into smaller steps not to retain 'self' for
- // too long ) ...
- errorTimer.start();
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
- (int64_t)(powerOffTimeStepS * NSEC_PER_SEC)),
- leQueue,
- ^{
- [self handlePoweredOff];
- });
+ // No change in internalState. Wait for 30 seconds.
+ [elapsedTimer cancelTimer];
+ elapsedTimer.reset([[GCDTimerObjC alloc] initWithDelegate:self]);
+ [elapsedTimer startWithTimeout:powerOffTimeoutMS step:300];
return;
+#else
+ Q_UNUSED(powerOffTimeoutMS)
#endif
internalState = ErrorPoweredOff;
emit notifier->CBManagerError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
@@ -330,6 +266,8 @@ QT_USE_NAMESPACE
if (internalState == InquiryActive)
[manager stopScan];
+ [elapsedTimer cancelTimer];
+
[manager setDelegate:nil];
internalState = InquiryCancelled;
diff --git a/src/bluetooth/osx/osxbtledeviceinquiry_p.h b/src/bluetooth/osx/osxbtledeviceinquiry_p.h
index fc787a6d..a19055ab 100644
--- a/src/bluetooth/osx/osxbtledeviceinquiry_p.h
+++ b/src/bluetooth/osx/osxbtledeviceinquiry_p.h
@@ -53,10 +53,10 @@
#include "qbluetoothdevicediscoveryagent.h"
#include "qbluetoothdeviceinfo.h"
+#include "osxbtgcdtimer_p.h"
#include "osxbtutility_p.h"
#include "osxbluetooth_p.h"
-#include <QtCore/qelapsedtimer.h>
#include <QtCore/qglobal.h>
#include <QtCore/qlist.h>
@@ -75,10 +75,8 @@ class LECBManagerNotifier;
QT_END_NAMESPACE
-// Ugly but all these QT_PREPEND_NAMESPACE etc. are even worse ...
-using OSXBluetooth::LECBManagerNotifier;
-using OSXBluetooth::ObjCScopedPointer;
-using QT_PREPEND_NAMESPACE(QElapsedTimer);
+using QT_PREPEND_NAMESPACE(OSXBluetooth)::LECBManagerNotifier;
+using QT_PREPEND_NAMESPACE(OSXBluetooth)::ObjCScopedPointer;
enum LEInquiryState
{
@@ -90,7 +88,7 @@ enum LEInquiryState
ErrorLENotSupported
};
-@interface QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) : NSObject
+@interface QT_MANGLE_NAMESPACE(OSXBTLEDeviceInquiry) : NSObject<CBCentralManagerDelegate, QT_MANGLE_NAMESPACE(GCDTimerDelegate)>
{
LECBManagerNotifier *notifier;
ObjCScopedPointer<CBCentralManager> manager;
@@ -99,16 +97,14 @@ enum LEInquiryState
LEInquiryState internalState;
int inquiryTimeoutMS;
- // Timers to check if we can execute delayed callbacks:
- QT_PREPEND_NAMESPACE(QElapsedTimer) errorTimer;
- QT_PREPEND_NAMESPACE(QElapsedTimer) scanTimer;
+ QT_PREPEND_NAMESPACE(OSXBluetooth)::GCDTimer elapsedTimer;
}
- (id)initWithNotifier:(LECBManagerNotifier *)aNotifier;
- (void)dealloc;
-// IMPORTANT: both 'startWithTimeout' and 'stop'
-// can be executed only on the "Qt's LE queue".
+// IMPORTANT: both 'startWithTimeout' and 'stop' MUST be executed on the "Qt's
+// LE queue".
- (void)startWithTimeout:(int)timeout;
- (void)stop;