6#include <QtBluetooth/qbluetoothaddress.h>
7#include <QtBluetooth/qbluetoothdeviceinfo.h>
8#include <QtBluetooth/qbluetoothserviceinfo.h>
9#include <QtBluetooth/qbluetoothservicediscoveryagent.h>
10#include <QtBluetooth/qbluetoothuuid.h>
11#include <QtBluetooth/private/qohosbluetoothaccess_p.h>
12#include <QtBluetooth/private/qohosbluetoothremotedevice_p.h>
14#include <QtCore/qloggingcategory.h>
15#include <QtCore/qvariant.h>
22using QtOhosBluetooth::QOhosBluetoothErrorCode;
24Q_DECLARE_LOGGING_CATEGORY(QT_BT_OHOS)
28bool uuidFilteredOut(
const QList<QBluetoothUuid> &uuidFilter,
const QBluetoothUuid &uuid)
30 return !uuidFilter.isEmpty() && !uuidFilter.contains(uuid);
33QBluetoothServiceInfo makeRfcommServiceInfo(
34 const QBluetoothDeviceInfo &deviceInfo,
const QBluetoothUuid &serviceUuid)
36 constexpr quint8 unknownRfcommServerChannel = 0;
37 constexpr quint16 serialPortProfileVersion = 0x0100;
40 serviceInfo.setDevice(deviceInfo);
42 QBluetoothServiceInfo::Sequence l2capProtocol;
43 l2capProtocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
45 QBluetoothServiceInfo::Sequence rfcommProtocol;
46 rfcommProtocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm));
47 rfcommProtocol << QVariant::fromValue(unknownRfcommServerChannel);
49 QBluetoothServiceInfo::Sequence protocolDescriptorList;
50 protocolDescriptorList << QVariant::fromValue(l2capProtocol);
51 protocolDescriptorList << QVariant::fromValue(rfcommProtocol);
52 serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
54 QBluetoothServiceInfo::Sequence serialPortProfile;
55 QBluetoothServiceInfo::Sequence serialPortProfileClassId;
56 serialPortProfileClassId
57 << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
58 serialPortProfileClassId << QVariant::fromValue(serialPortProfileVersion);
59 serialPortProfile << QVariant::fromValue(serialPortProfileClassId);
60 serviceInfo.setAttribute(
61 QBluetoothServiceInfo::BluetoothProfileDescriptorList, serialPortProfile);
63 QBluetoothServiceInfo::Sequence browseGroup;
64 browseGroup << QVariant::fromValue(
65 QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup));
66 serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, browseGroup);
68 QBluetoothServiceInfo::Sequence serviceClassIds;
69 serviceClassIds << QVariant::fromValue(serviceUuid);
70 serviceClassIds << QVariant::fromValue(
71 QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
72 serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, serviceClassIds);
74 serviceInfo.setServiceUuid(serviceUuid);
75 serviceInfo.setServiceProvider(QBluetoothServiceDiscoveryAgent::tr(
"QtOhosBluetooth"));
76 serviceInfo.setServiceName(QBluetoothServiceDiscoveryAgent::tr(
"Serial Port Profile"));
83QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
84 QBluetoothServiceDiscoveryAgent *qp,
const QBluetoothAddress &)
85 : error(QBluetoothServiceDiscoveryAgent::NoError)
87 , mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery)
89 , m_remoteDeviceProxy(QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::instance())
93 m_remoteDeviceProxy.get(),
94 &QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::remoteDeviceServicesRead,
96 [
this](
const QtOhosBluetooth::RemoteDeviceServices &remoteDeviceServices) {
97 reportRemoteDeviceServices(remoteDeviceServices);
101QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate() =
default;
103void QBluetoothServiceDiscoveryAgentPrivate::reportErrorAsync(
104 QBluetoothServiceDiscoveryAgent::Error discoveryError,
const QString &discoveryErrorString)
106 error = discoveryError;
107 errorString = discoveryErrorString;
108 QMetaObject::invokeMethod(
110 [
this, discoveryError]() {
111 Q_EMIT q_ptr->errorOccurred(discoveryError);
113 Qt::QueuedConnection);
116void QBluetoothServiceDiscoveryAgentPrivate::finishDeviceDiscoveryAsync()
118 QMetaObject::invokeMethod(
121 if (discoveryState() != ServiceDiscovery)
124 _q_serviceDiscoveryFinished();
126 Qt::QueuedConnection);
129void QBluetoothServiceDiscoveryAgentPrivate::reportRemoteDeviceServices(
130 const QtOhosBluetooth::RemoteDeviceServices &remoteDeviceServices)
132 if (m_optRequestedDeviceId != remoteDeviceServices.deviceId)
135 m_optRequestedDeviceId.reset();
137 const auto addressStr = QString::fromStdString(remoteDeviceServices.deviceId);
138 const QBluetoothDeviceInfo bluetoothDeviceInfo(
139 QBluetoothAddress(addressStr),
140 remoteDeviceServices.optDeviceName
141 ? QString::fromStdString(*remoteDeviceServices.optDeviceName)
143 remoteDeviceServices.optClassOfDevice.value_or(0));
145 const auto discoveredServicesCountBeforeDevice = discoveredServices.size();
147 auto reportServiceForUuid = [&](
const QBluetoothUuid &uuid) {
148 const auto serviceInfo = makeRfcommServiceInfo(bluetoothDeviceInfo, uuid);
149 if (isDuplicatedService(serviceInfo))
152 discoveredServices.append(serviceInfo);
153 QMetaObject::invokeMethod(
155 [
this, serviceInfo]() {
156 Q_EMIT q_ptr->serviceDiscovered(serviceInfo);
158 Qt::QueuedConnection);
161 if (remoteDeviceServices.optProfileUuids) {
162 for (
const auto &profileUuid : *remoteDeviceServices.optProfileUuids) {
163 const auto uuid = QBluetoothUuid(QString::fromStdString(profileUuid));
164 if (uuidFilteredOut(uuidFilter, uuid))
167 reportServiceForUuid(uuid);
172 "%s: could not read the remote standard profile UUIDs of the device %ls. Continuing...",
173 Q_FUNC_INFO, qUtf16Printable(addressStr));
176 if (singleDevice && !uuidFilter.isEmpty() && !remoteDeviceServices.lowEnergyOnly) {
177 for (
const auto &requestedUuid : uuidFilter)
178 reportServiceForUuid(requestedUuid);
181 if (!remoteDeviceServices.optProfileUuids && singleDevice
182 && discoveredServices.size() == discoveredServicesCountBeforeDevice) {
184 QBluetoothServiceDiscoveryAgent::InputOutputError,
185 QBluetoothServiceDiscoveryAgent::tr(
"Cannot obtain service uuids"));
188 finishDeviceDiscoveryAsync();
191void QBluetoothServiceDiscoveryAgentPrivate::start(
const QBluetoothAddress &address)
193 auto accessProxy = QtOhosBluetooth::QOhosBluetoothAccessProxy::instance();
194 if (accessProxy->tryGetBluetoothState() != QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState::STATE_ON) {
195 qCWarning(QT_BT_OHOS,
"%s: bluetooth not in powered on state. Ignoring...", Q_FUNC_INFO);
196 discoveredDevices.clear();
198 QBluetoothServiceDiscoveryAgent::PoweredOffError,
199 QBluetoothServiceDiscoveryAgent::tr(
"Device is powered off"));
200 finishDeviceDiscoveryAsync();
204 m_optRequestedDeviceId = address.toString().toStdString();
206 const auto optErrorCode = m_remoteDeviceProxy->requestRemoteDeviceServices(address.toString());
210 m_optRequestedDeviceId.reset();
213 QT_BT_OHOS,
"%s: could not start reading the services of the device %ls, error code: %u",
214 Q_FUNC_INFO, qUtf16Printable(address.toString()), qToUnderlying(*optErrorCode));
217 if (*optErrorCode == QOhosBluetoothErrorCode::PermissionDenied) {
219 QBluetoothServiceDiscoveryAgent::MissingPermissionsError,
220 QBluetoothServiceDiscoveryAgent::tr(
"Missing bluetooth permission"));
223 QBluetoothServiceDiscoveryAgent::InputOutputError,
224 QBluetoothServiceDiscoveryAgent::tr(
"Cannot obtain service uuids"));
228 finishDeviceDiscoveryAsync();
231void QBluetoothServiceDiscoveryAgentPrivate::stop()
233 m_optRequestedDeviceId.reset();
234 QMetaObject::invokeMethod(q_ptr, &QBluetoothServiceDiscoveryAgent::canceled, Qt::QueuedConnection);