diff options
author | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2023-01-03 10:37:21 +0100 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2023-02-24 13:59:28 +0100 |
commit | ae1a1f5efce291f613a13757ff6f744fcca2d2ce (patch) | |
tree | 4d0b562d220783e75d4aa2cc3c5cae1d28fcd4e0 /tests | |
parent | 935ec099758487b57970732f0ecfe7021b655968 (diff) | |
download | qtconnectivity-ae1a1f5efce291f613a13757ff6f744fcca2d2ce.tar.gz |
QtBluetooth: port the code to the new permissions API (CoreBluetooth)
We only _check_ if permissions were granted, leaving it up to an application
to _request_ permissions. If permission status is not 'Granted', we bail
out ealy setting MissionPermissionsError. QLowEnergyController::init is
now a no-op for Darwin, because it's OK to create a peripheral/central and no need
to set any error yet. Autotests require minor adjustments - they were
already passing if BT is off, as it is on CI (checking Bluetooth local
device and its status), but if BT is somewhere on, tests can try to scan or
connect not having permissions granted - for this we adjust the tests,
using permission API.
[ChangeLog][Important Behavior Changes][QtBluetooth][Darwin] Do not request
permissions implicitly, only check them and leave it to applications to request
permissions explicitly.
Task-number: QTBUG-109964
Change-Id: I95c04744e979614ffb6d992da2e279e86b272679
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
Diffstat (limited to 'tests')
3 files changed, 115 insertions, 8 deletions
diff --git a/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp b/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp index daa14e45..b192e120 100644 --- a/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp +++ b/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp @@ -14,6 +14,14 @@ #include <qbluetoothdevicediscoveryagent.h> #include <qbluetoothlocaldevice.h> +#if QT_CONFIG(permissions) +#include <QtCore/qcoreapplication.h> +#include <QtCore/qpermissions.h> +#include <QtCore/qnamespace.h> +#endif // permissions + +#include <memory> + QT_USE_NAMESPACE /* @@ -62,12 +70,28 @@ private slots: void tst_discoveryMethods(); private: qsizetype noOfLocalDevices; + using DiscoveryAgentPtr = std::unique_ptr<QBluetoothDeviceDiscoveryAgent>; +#if QT_CONFIG(permissions) + Qt::PermissionStatus permissionStatus = Qt::PermissionStatus::Undetermined; +#endif }; tst_QBluetoothDeviceDiscoveryAgent::tst_QBluetoothDeviceDiscoveryAgent() { QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true")); qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::Error>(); +#if QT_CONFIG(permissions) + permissionStatus = qApp->checkPermission(QBluetoothPermission{}); + if (permissionStatus == Qt::PermissionStatus::Undetermined) { + QTestEventLoop loop; + qApp->requestPermission(QBluetoothPermission{}, [this, &loop](const QPermission &permission){ + permissionStatus = permission.status(); + loop.exitLoop(); + }); + if (permissionStatus == Qt::PermissionStatus::Undetermined) // Did not return immediately? + loop.enterLoopMSecs(30000); + } +#endif } tst_QBluetoothDeviceDiscoveryAgent::~tst_QBluetoothDeviceDiscoveryAgent() @@ -105,21 +129,24 @@ void tst_QBluetoothDeviceDiscoveryAgent::initTestCase() void tst_QBluetoothDeviceDiscoveryAgent::tst_invalidBtAddress() { - QBluetoothDeviceDiscoveryAgent *discoveryAgent = new QBluetoothDeviceDiscoveryAgent( - QBluetoothAddress(QStringLiteral("11:11:11:11:11:11"))); + DiscoveryAgentPtr discoveryAgent(new QBluetoothDeviceDiscoveryAgent( + QBluetoothAddress(QStringLiteral("11:11:11:11:11:11")))); QCOMPARE(discoveryAgent->error(), QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError); discoveryAgent->start(); QCOMPARE(discoveryAgent->isActive(), false); - delete discoveryAgent; - discoveryAgent = new QBluetoothDeviceDiscoveryAgent(QBluetoothAddress()); +#if QT_CONFIG(permissions) + if (permissionStatus != Qt::PermissionStatus::Granted) + return; +#endif + + discoveryAgent.reset(new QBluetoothDeviceDiscoveryAgent(QBluetoothAddress())); QCOMPARE(discoveryAgent->error(), QBluetoothDeviceDiscoveryAgent::NoError); if (!QBluetoothLocalDevice::allDevices().isEmpty()) { discoveryAgent->start(); QCOMPARE(discoveryAgent->isActive(), true); } - delete discoveryAgent; } void tst_QBluetoothDeviceDiscoveryAgent::deviceDiscoveryDebug(const QBluetoothDeviceInfo &info) @@ -131,6 +158,7 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries() { if (androidBluetoothEmulator()) QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input"); + QBluetoothDeviceDiscoveryAgent discoveryAgent; QVERIFY(discoveryAgent.error() == discoveryAgent.NoError); @@ -148,6 +176,14 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries() QVERIFY(errorSpy.isEmpty()); discoveryAgent.start(); +#if QT_CONFIG(permissions) + if (permissionStatus != Qt::PermissionStatus::Granted) { + // If bluetooth is OFF, the permission does not get checked (e.g. on Darwin), + // but not to depend on the order in which errors generated, we + // do not compare error value with MissionPermissionsError here. + return; + } +#endif if (errorSpy.isEmpty()) { QVERIFY(discoveryAgent.isActive()); @@ -327,7 +363,12 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_deviceDiscovery() // this, SLOT(deviceDiscoveryDebug(QBluetoothDeviceInfo))); discoveryAgent.start(); + if (!errorSpy.isEmpty()) { +#if QT_CONFIG(permissions) + if (permissionStatus == Qt::PermissionStatus::Granted) +#endif + QCOMPARE(noOfLocalDevices, 0); QVERIFY(!discoveryAgent.isActive()); QSKIP("No local Bluetooth device available. Skipping remaining part of test."); @@ -457,10 +498,15 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_discoveryMethods() // Start discovery, probably both Classic and LE methods: agent.start(supportedMethods); +#if QT_CONFIG(permissions) + if (permissionStatus != Qt::PermissionStatus::Granted) { + QCOMPARE(agent.error(), QBluetoothDeviceDiscoveryAgent::MissingPermissionsError); + QSKIP("The remaining test requires the Bluetooth permission granted"); + } +#endif QVERIFY(agent.isActive()); QVERIFY(errorSpy.isEmpty()); - #define RUN_DISCOVERY(maxTimeout, step, condition) \ for (int scanTime = maxTimeout; (condition) && scanTime > 0; scanTime -= step) \ QTest::qWait(step); diff --git a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp index c83f4bc5..ed4a86bb 100644 --- a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp +++ b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp @@ -14,6 +14,13 @@ #include <QLowEnergyController> #include <QLowEnergyCharacteristic> +#if QT_CONFIG(permissions) +#include <QCoreApplication> +#include <QPermissions> + +#include <QtCore/qnamespace.h> +#endif + #include <QDebug> /*! @@ -59,6 +66,9 @@ private: QBluetoothDeviceInfo remoteDeviceInfo; QList<QBluetoothUuid> foundServices; bool isBluezDbusLE = false; +#if QT_CONFIG(permissions) + Qt::PermissionStatus permissionStatus = Qt::PermissionStatus::Undetermined; +#endif }; tst_QLowEnergyController::tst_QLowEnergyController() @@ -81,6 +91,24 @@ tst_QLowEnergyController::tst_QLowEnergyController() isBluezDbusLE = (bluetoothdVersion() >= QVersionNumber(5, 42)); qDebug() << "isDBusBluez:" << isBluezDbusLE; #endif + +#if QT_CONFIG(permissions) + // FIXME: for Android, set additional parameters for scan and connect + // permissions. + permissionStatus = qApp->checkPermission(QBluetoothPermission{}); + if (permissionStatus == Qt::PermissionStatus::Undetermined) { + QTestEventLoop eventLoop; + qApp->requestPermission(QBluetoothPermission{}, [this, &eventLoop](const QPermission &permission){ + permissionStatus = permission.status(); + eventLoop.exitLoop(); + }); + if (permissionStatus == Qt::PermissionStatus::Undetermined) + eventLoop.enterLoop(30000); + } + // Note: even with missing Bluetooth permission, we still can run tests on + // LE controller to test its logic/errors it emits, even if we cannot scan + // and cannot connect. +#endif // permission } tst_QLowEnergyController::~tst_QLowEnergyController() @@ -109,7 +137,6 @@ void tst_QLowEnergyController::initTestCase() #endif // QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true")); - devAgent = new QBluetoothDeviceDiscoveryAgent(this); devAgent->setLowEnergyDiscoveryTimeout(5000); @@ -120,6 +147,12 @@ void tst_QLowEnergyController::initTestCase() bool deviceFound = false; devAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); +#if QT_CONFIG(permissions) + if (permissionStatus != Qt::PermissionStatus::Granted) { + QCOMPARE(devAgent->error(), QBluetoothDeviceDiscoveryAgent::MissingPermissionsError); + return; + } +#endif QTRY_VERIFY_WITH_TIMEOUT(!finishedSpy.isEmpty(), 30000); const QList<QBluetoothDeviceInfo> infos = devAgent->discoveredDevices(); for (const QBluetoothDeviceInfo &info : infos) { @@ -223,6 +256,7 @@ void tst_QLowEnergyController::tst_emptyCtor() #else QCOMPARE(control->error(), QLowEnergyController::NoError); #endif + control->connectToDevice(); QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), 10000); @@ -234,7 +268,6 @@ void tst_QLowEnergyController::tst_emptyCtor() QVERIFY(lastError == QLowEnergyController::UnknownRemoteDeviceError // if local device on platform found || lastError == QLowEnergyController::InvalidBluetoothAdapterError); // otherwise, e.g. fallback backend } - } void tst_QLowEnergyController::tst_connect() diff --git a/tests/auto/qlowenergydescriptor/tst_qlowenergydescriptor.cpp b/tests/auto/qlowenergydescriptor/tst_qlowenergydescriptor.cpp index b3046a52..80ad9938 100644 --- a/tests/auto/qlowenergydescriptor/tst_qlowenergydescriptor.cpp +++ b/tests/auto/qlowenergydescriptor/tst_qlowenergydescriptor.cpp @@ -12,6 +12,12 @@ #include <QLowEnergyController> #include <QBluetoothLocalDevice> +#if QT_CONFIG(permissions) +#include <QCoreApplication> +#include <QPermissions> +#include <QtCore/qnamespace.h> +#endif + QT_USE_NAMESPACE class tst_QLowEnergyDescriptor : public QObject @@ -35,12 +41,27 @@ private: QList<QBluetoothDeviceInfo> remoteLeDeviceInfos; QLowEnergyController *globalControl; QLowEnergyService *globalService; +#if QT_CONFIG(permissions) + Qt::PermissionStatus permissionStatus = Qt::PermissionStatus::Undetermined; +#endif }; tst_QLowEnergyDescriptor::tst_QLowEnergyDescriptor() : globalControl(nullptr), globalService(nullptr) { QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true")); +#if QT_CONFIG(permissions) + permissionStatus = qApp->checkPermission(QBluetoothPermission{}); + if (permissionStatus == Qt::PermissionStatus::Undetermined) { + QTestEventLoop loop; + qApp->requestPermission(QBluetoothPermission{}, [this, &loop](const QPermission &permission){ + permissionStatus = permission.status(); + loop.exitLoop(); + }); + if (permissionStatus == Qt::PermissionStatus::Undetermined) + loop.enterLoopMSecs(30000); + } +#endif } tst_QLowEnergyDescriptor::~tst_QLowEnergyDescriptor() @@ -65,6 +86,13 @@ void tst_QLowEnergyDescriptor::initTestCase() } } +#if QT_CONFIG(permissions) + if (permissionStatus != Qt::PermissionStatus::Granted) { + qWarning("Use of BLuetooth LE requires the Bluetooth permission granted"); + return; + } +#endif + // find an arbitrary low energy device in vicinity // find an arbitrary service with descriptor |