summaryrefslogtreecommitdiffstats
path: root/tests/manual/examples
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual/examples')
-rw-r--r--tests/manual/examples/btscanner/CMakeLists.txt48
-rw-r--r--tests/manual/examples/btscanner/Info.plist41
-rw-r--r--tests/manual/examples/btscanner/btscanner.pro24
-rw-r--r--tests/manual/examples/btscanner/device.cpp182
-rw-r--r--tests/manual/examples/btscanner/device.h49
-rw-r--r--tests/manual/examples/btscanner/device.ui118
-rw-r--r--tests/manual/examples/btscanner/main.cpp33
-rw-r--r--tests/manual/examples/btscanner/service.cpp62
-rw-r--r--tests/manual/examples/btscanner/service.h36
-rw-r--r--tests/manual/examples/btscanner/service.ui71
10 files changed, 664 insertions, 0 deletions
diff --git a/tests/manual/examples/btscanner/CMakeLists.txt b/tests/manual/examples/btscanner/CMakeLists.txt
new file mode 100644
index 00000000..08bac2df
--- /dev/null
+++ b/tests/manual/examples/btscanner/CMakeLists.txt
@@ -0,0 +1,48 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(btscanner LANGUAGES CXX)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+ endif()
+
+qt_internal_add_manual_test(btscanner
+ GUI
+ SOURCES
+ device.cpp device.h device.ui
+ main.cpp
+ service.cpp service.h service.ui
+ LIBRARIES
+ Qt::Bluetooth
+ Qt::Core
+ Qt::Widgets
+ ENABLE_AUTOGEN_TOOLS
+ uic
+)
+
+if(MACOS)
+ # Explicitly link against the static permission plugin because tests
+ # currently don't have finalizers run for them except for iOS.
+ # TODO: Remove this when qtbase automatically runs finalizers for tests: QTBUG-112212
+ target_link_libraries(btscanner PRIVATE Qt6::QDarwinBluetoothPermissionPlugin)
+endif()
+
+set_target_properties(btscanner PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+if(APPLE)
+ if (IOS)
+ set_target_properties(btscanner PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist"
+ )
+ else()
+ # Using absolute path for shared plist files is a Ninja bug workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../examples/bluetooth/shared ABSOLUTE)
+ set_target_properties(btscanner PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.cmake.macos.plist"
+ )
+ endif()
+endif()
diff --git a/tests/manual/examples/btscanner/Info.plist b/tests/manual/examples/btscanner/Info.plist
new file mode 100644
index 00000000..49fd2191
--- /dev/null
+++ b/tests/manual/examples/btscanner/Info.plist
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${QMAKE_SHORT_VERSION}</string>
+ <key>CFBundleSignature</key>
+ <string>${QMAKE_PKGINFO_TYPEINFO}</string>
+ <key>CFBundleVersion</key>
+ <string>${QMAKE_FULL_VERSION}</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>MinimumOSVersion</key>
+ <string>${IPHONEOS_DEPLOYMENT_TARGET}</string>
+ <key>NSBluetoothAlwaysUsageDescription</key>
+ <string>Qt's BT scanner wants to access your Bluetooth adapter!</string>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/tests/manual/examples/btscanner/btscanner.pro b/tests/manual/examples/btscanner/btscanner.pro
new file mode 100644
index 00000000..3ef49969
--- /dev/null
+++ b/tests/manual/examples/btscanner/btscanner.pro
@@ -0,0 +1,24 @@
+TARGET = btscanner
+
+QT = core bluetooth widgets
+requires(qtConfig(listwidget))
+TEMPLATE = app
+
+SOURCES = \
+ main.cpp \
+ device.cpp \
+ service.cpp
+
+ios: QMAKE_INFO_PLIST = Info.plist
+macos: QMAKE_INFO_PLIST = ../../../../examples/bluetooth/shared/Info.qmake.macos.plist
+
+HEADERS = \
+ device.h \
+ service.h
+
+FORMS = \
+ device.ui \
+ service.ui
+
+target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/btscanner
+INSTALLS += target
diff --git a/tests/manual/examples/btscanner/device.cpp b/tests/manual/examples/btscanner/device.cpp
new file mode 100644
index 00000000..6d1f775f
--- /dev/null
+++ b/tests/manual/examples/btscanner/device.cpp
@@ -0,0 +1,182 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "device.h"
+#include "service.h"
+#include "ui_device.h"
+
+#include <QtBluetooth/qbluetoothaddress.h>
+#include <QtBluetooth/qbluetoothdevicediscoveryagent.h>
+#include <QtBluetooth/qbluetoothlocaldevice.h>
+
+#include <QtWidgets/qmenu.h>
+
+#if QT_CONFIG(permissions)
+#include <QtCore/qpermissions.h>
+#include <QtWidgets/qmessagebox.h>
+#include <QtWidgets/qapplication.h>
+#endif // QT_CONFIG(permissions)
+
+static QColor colorForPairing(QBluetoothLocalDevice::Pairing pairing)
+{
+ return pairing == QBluetoothLocalDevice::Paired
+ || pairing == QBluetoothLocalDevice::AuthorizedPaired
+ ? QColor(Qt::green) : QColor(Qt::red);
+}
+
+DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget *parent) :
+ QDialog(parent),
+ localDevice(new QBluetoothLocalDevice(this)),
+ ui(new Ui::DeviceDiscovery)
+{
+#ifdef Q_OS_ANDROID
+ this->setWindowState(Qt::WindowMaximized);
+#endif
+ ui->setupUi(this);
+ ui->stopScan->setVisible(false);
+
+ // In case of multiple Bluetooth adapters it is possible to set the adapter
+ // to be used. Example code:
+ //
+ // QBluetoothAddress address("XX:XX:XX:XX:XX:XX");
+ // discoveryAgent = new QBluetoothDeviceDiscoveryAgent(address, this);
+
+ discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
+
+ connect(ui->scan, &QAbstractButton::clicked, this, &DeviceDiscoveryDialog::startScan);
+ connect(ui->stopScan, &QAbstractButton::clicked, this, &DeviceDiscoveryDialog::stopScan);
+
+ connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
+ this, &DeviceDiscoveryDialog::addDevice);
+ connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished,
+ this, &DeviceDiscoveryDialog::scanFinished);
+
+ connect(ui->list, &QListWidget::itemActivated,
+ this, &DeviceDiscoveryDialog::itemActivated);
+
+ connect(localDevice, &QBluetoothLocalDevice::hostModeStateChanged,
+ this, &DeviceDiscoveryDialog::hostModeStateChanged);
+
+ hostModeStateChanged(localDevice->hostMode());
+ // add context menu for devices to be able to pair device
+ ui->list->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->list, &QWidget::customContextMenuRequested,
+ this, &DeviceDiscoveryDialog::displayPairingMenu);
+ connect(localDevice, &QBluetoothLocalDevice::pairingFinished,
+ this, &DeviceDiscoveryDialog::pairingDone);
+}
+
+DeviceDiscoveryDialog::~DeviceDiscoveryDialog()
+{
+ delete ui;
+}
+
+void DeviceDiscoveryDialog::addDevice(const QBluetoothDeviceInfo &info)
+{
+ const QString label = info.address().toString() + u' ' + info.name();
+ const auto items = ui->list->findItems(label, Qt::MatchExactly);
+ if (items.isEmpty()) {
+ QListWidgetItem *item = new QListWidgetItem(label);
+ QBluetoothLocalDevice::Pairing pairingStatus = localDevice->pairingStatus(info.address());
+ item->setForeground(colorForPairing(pairingStatus));
+ ui->list->addItem(item);
+ }
+}
+
+void DeviceDiscoveryDialog::startScan()
+{
+#if QT_CONFIG(permissions)
+ if (qApp->checkPermission(QBluetoothPermission{}) != Qt::PermissionStatus::Granted) {
+ QMessageBox::warning(this, tr("Missing permission"),
+ tr("Permission is needed to use Bluetooth. "\
+ "Please grant the permission to this "\
+ "application in the system settings."));
+ return;
+ }
+#endif // QT_CONFIG(permissions)
+ discoveryAgent->start();
+ ui->scan->setVisible(false);
+ ui->stopScan->setVisible(true);
+}
+
+void DeviceDiscoveryDialog::stopScan()
+{
+ discoveryAgent->stop();
+ scanFinished();
+}
+
+void DeviceDiscoveryDialog::scanFinished()
+{
+ ui->scan->setVisible(true);
+ ui->stopScan->setVisible(false);
+}
+
+void DeviceDiscoveryDialog::itemActivated(QListWidgetItem *item)
+{
+ const QString text = item->text();
+ const auto index = text.indexOf(' ');
+ if (index == -1)
+ return;
+
+ QBluetoothAddress address(text.left(index));
+ QString name(text.mid(index + 1));
+
+ ServiceDiscoveryDialog d(name, address);
+ d.exec();
+}
+
+void DeviceDiscoveryDialog::on_discoverable_clicked(bool clicked)
+{
+ if (clicked)
+ localDevice->setHostMode(QBluetoothLocalDevice::HostDiscoverable);
+ else
+ localDevice->setHostMode(QBluetoothLocalDevice::HostConnectable);
+}
+
+void DeviceDiscoveryDialog::on_power_clicked(bool clicked)
+{
+ if (clicked)
+ localDevice->powerOn();
+ else
+ localDevice->setHostMode(QBluetoothLocalDevice::HostPoweredOff);
+}
+
+void DeviceDiscoveryDialog::hostModeStateChanged(QBluetoothLocalDevice::HostMode mode)
+{
+ ui->power->setChecked(mode != QBluetoothLocalDevice::HostPoweredOff);
+ ui->discoverable->setChecked(mode == QBluetoothLocalDevice::HostDiscoverable);
+
+ const bool on = mode != QBluetoothLocalDevice::HostPoweredOff;
+ ui->scan->setEnabled(on);
+ ui->discoverable->setEnabled(on);
+}
+void DeviceDiscoveryDialog::displayPairingMenu(const QPoint &pos)
+{
+ if (ui->list->count() == 0)
+ return;
+ QMenu menu(this);
+ QAction *pairAction = menu.addAction("Pair");
+ QAction *removePairAction = menu.addAction("Remove Pairing");
+ QAction *chosenAction = menu.exec(ui->list->viewport()->mapToGlobal(pos));
+ QListWidgetItem *currentItem = ui->list->currentItem();
+
+ QString text = currentItem->text();
+ const auto index = text.indexOf(' ');
+ if (index == -1)
+ return;
+
+ QBluetoothAddress address (text.left(index));
+ if (chosenAction == pairAction) {
+ localDevice->requestPairing(address, QBluetoothLocalDevice::Paired);
+ } else if (chosenAction == removePairAction) {
+ localDevice->requestPairing(address, QBluetoothLocalDevice::Unpaired);
+ }
+}
+void DeviceDiscoveryDialog::pairingDone(const QBluetoothAddress &address,
+ QBluetoothLocalDevice::Pairing pairing)
+{
+ const auto items = ui->list->findItems(address.toString(), Qt::MatchContains);
+ const QColor color = colorForPairing(pairing);
+ for (auto *item : items)
+ item->setForeground(color);
+}
diff --git a/tests/manual/examples/btscanner/device.h b/tests/manual/examples/btscanner/device.h
new file mode 100644
index 00000000..389062bb
--- /dev/null
+++ b/tests/manual/examples/btscanner/device.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef DEVICE_H
+#define DEVICE_H
+
+#include <QtBluetooth/qbluetoothlocaldevice.h>
+
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_NAMESPACE
+class QBluetoothAddress;
+class QBluetoothDeviceDiscoveryAgent;
+class QBluetoothDeviceInfo;
+class QListWidgetItem;
+
+namespace Ui {
+ class DeviceDiscovery;
+}
+QT_END_NAMESPACE
+
+class DeviceDiscoveryDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ DeviceDiscoveryDialog(QWidget *parent = nullptr);
+ ~DeviceDiscoveryDialog();
+
+public slots:
+ void addDevice(const QBluetoothDeviceInfo &info);
+ void on_power_clicked(bool clicked);
+ void on_discoverable_clicked(bool clicked);
+ void displayPairingMenu(const QPoint &pos);
+ void pairingDone(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
+private slots:
+ void startScan();
+ void stopScan();
+ void scanFinished();
+ void itemActivated(QListWidgetItem *item);
+ void hostModeStateChanged(QBluetoothLocalDevice::HostMode mode);
+
+private:
+ QBluetoothDeviceDiscoveryAgent *discoveryAgent;
+ QBluetoothLocalDevice *localDevice;
+ Ui::DeviceDiscovery *ui;
+};
+
+#endif
diff --git a/tests/manual/examples/btscanner/device.ui b/tests/manual/examples/btscanner/device.ui
new file mode 100644
index 00000000..fd86a358
--- /dev/null
+++ b/tests/manual/examples/btscanner/device.ui
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DeviceDiscovery</class>
+ <widget class="QDialog" name="DeviceDiscovery">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>411</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Bluetooth Scanner</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QListWidget" name="list"/>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Local Device</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="power">
+ <property name="text">
+ <string>Bluetooth Powered On</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="discoverable">
+ <property name="text">
+ <string>Discoverable</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="scan">
+ <property name="text">
+ <string>Scan</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="stopScan">
+ <property name="text">
+ <string>Stop scan</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="clear">
+ <property name="text">
+ <string>Clear</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="quit">
+ <property name="text">
+ <string>Quit</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>quit</sender>
+ <signal>clicked()</signal>
+ <receiver>DeviceDiscovery</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>323</x>
+ <y>275</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>396</x>
+ <y>268</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>clear</sender>
+ <signal>clicked()</signal>
+ <receiver>list</receiver>
+ <slot>clear()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>188</x>
+ <y>276</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>209</x>
+ <y>172</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/tests/manual/examples/btscanner/main.cpp b/tests/manual/examples/btscanner/main.cpp
new file mode 100644
index 00000000..8ed2e652
--- /dev/null
+++ b/tests/manual/examples/btscanner/main.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "device.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtWidgets/qapplication.h>
+
+#if QT_CONFIG(permissions)
+#include <QtCore/qpermissions.h>
+#endif
+
+int main(int argc, char *argv[])
+{
+ // QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
+ QApplication app(argc, argv);
+ DeviceDiscoveryDialog d;
+
+ d.show();
+
+ // Check, and if needed, request a permission to use Bluetooth.
+#if QT_CONFIG(permissions)
+ const auto permissionStatus = app.checkPermission(QBluetoothPermission{});
+ if (permissionStatus == Qt::PermissionStatus::Undetermined) {
+ app.requestPermission(QBluetoothPermission{}, [](const QPermission &){
+ });
+ }
+ // Else means either 'Granted' or 'Denied' and both normally must be
+ // changed using the system's settings application.
+#endif // QT_CONFIG(permissions)
+
+ return app.exec();
+}
diff --git a/tests/manual/examples/btscanner/service.cpp b/tests/manual/examples/btscanner/service.cpp
new file mode 100644
index 00000000..aa6fe43c
--- /dev/null
+++ b/tests/manual/examples/btscanner/service.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "service.h"
+#include "ui_service.h"
+
+#include <QtBluetooth/qbluetoothaddress.h>
+#include <QtBluetooth/qbluetoothlocaldevice.h>
+#include <QtBluetooth/qbluetoothservicediscoveryagent.h>
+#include <QtBluetooth/qbluetoothserviceinfo.h>
+#include <QtBluetooth/qbluetoothuuid.h>
+
+
+ServiceDiscoveryDialog::ServiceDiscoveryDialog(const QString &name,
+ const QBluetoothAddress &address, QWidget *parent)
+ : QDialog(parent), ui(new Ui::ServiceDiscovery)
+{
+ ui->setupUi(this);
+
+ //Using default Bluetooth adapter
+ QBluetoothLocalDevice localDevice;
+ QBluetoothAddress adapterAddress = localDevice.address();
+
+ // In case of multiple Bluetooth adapters it is possible to
+ // set which adapter will be used by providing MAC Address.
+ // Example code:
+ //
+ // QBluetoothAddress adapterAddress("XX:XX:XX:XX:XX:XX");
+ // discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress, this);
+
+ discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress, this);
+ discoveryAgent->setRemoteAddress(address);
+
+ setWindowTitle(name);
+
+ connect(discoveryAgent, &QBluetoothServiceDiscoveryAgent::serviceDiscovered,
+ this, &ServiceDiscoveryDialog::addService);
+ connect(discoveryAgent, &QBluetoothServiceDiscoveryAgent::finished,
+ ui->status, &QWidget::hide);
+
+ discoveryAgent->start();
+}
+
+ServiceDiscoveryDialog::~ServiceDiscoveryDialog()
+{
+ delete ui;
+}
+
+void ServiceDiscoveryDialog::addService(const QBluetoothServiceInfo &info)
+{
+ if (info.serviceName().isEmpty())
+ return;
+
+ QString line = info.serviceName();
+ if (!info.serviceDescription().isEmpty())
+ line.append("\n\t" + info.serviceDescription());
+ if (!info.serviceProvider().isEmpty())
+ line.append("\n\t" + info.serviceProvider());
+
+ ui->list->addItem(line);
+}
diff --git a/tests/manual/examples/btscanner/service.h b/tests/manual/examples/btscanner/service.h
new file mode 100644
index 00000000..1c84f38c
--- /dev/null
+++ b/tests/manual/examples/btscanner/service.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SERVICE_H
+#define SERVICE_H
+
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_NAMESPACE
+class QBluetoothAddress;
+class QBluetoothServiceDiscoveryAgent;
+class QBluetoothServiceInfo;
+
+namespace Ui {
+ class ServiceDiscovery;
+}
+QT_END_NAMESPACE
+
+class ServiceDiscoveryDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ ServiceDiscoveryDialog(const QString &name, const QBluetoothAddress &address,
+ QWidget *parent = nullptr);
+ ~ServiceDiscoveryDialog();
+
+public slots:
+ void addService(const QBluetoothServiceInfo &info);
+
+private:
+ QBluetoothServiceDiscoveryAgent *discoveryAgent;
+ Ui::ServiceDiscovery *ui;
+};
+
+#endif
diff --git a/tests/manual/examples/btscanner/service.ui b/tests/manual/examples/btscanner/service.ui
new file mode 100644
index 00000000..4ca12ee0
--- /dev/null
+++ b/tests/manual/examples/btscanner/service.ui
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServiceDiscovery</class>
+ <widget class="QDialog" name="ServiceDiscovery">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>539</width>
+ <height>486</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Available Services</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QListWidget" name="list"/>
+ </item>
+ <item>
+ <widget class="QLabel" name="status">
+ <property name="text">
+ <string>Querying...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Close</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ServiceDiscovery</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>396</x>
+ <y>457</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>535</x>
+ <y>443</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ServiceDiscovery</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>339</x>
+ <y>464</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>535</x>
+ <y>368</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>