Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qbluetoothservicediscoveryagent_ohos.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
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>
13
14#include <QtCore/qloggingcategory.h>
15#include <QtCore/qvariant.h>
16
17#include <algorithm>
18#include <optional>
19
20QT_BEGIN_NAMESPACE
21
22using QtOhosBluetooth::QOhosBluetoothErrorCode;
23
24Q_DECLARE_LOGGING_CATEGORY(QT_BT_OHOS)
25
26namespace {
27
28bool uuidFilteredOut(const QList<QBluetoothUuid> &uuidFilter, const QBluetoothUuid &uuid)
29{
30 return !uuidFilter.isEmpty() && !uuidFilter.contains(uuid);
31}
32
33QBluetoothServiceInfo makeRfcommServiceInfo(
34 const QBluetoothDeviceInfo &deviceInfo, const QBluetoothUuid &serviceUuid)
35{
36 constexpr quint8 unknownRfcommServerChannel = 0;
37 constexpr quint16 serialPortProfileVersion = 0x0100;
38
39 QBluetoothServiceInfo serviceInfo;
40 serviceInfo.setDevice(deviceInfo);
41
42 QBluetoothServiceInfo::Sequence l2capProtocol;
43 l2capProtocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
44
45 QBluetoothServiceInfo::Sequence rfcommProtocol;
46 rfcommProtocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm));
47 rfcommProtocol << QVariant::fromValue(unknownRfcommServerChannel);
48
49 QBluetoothServiceInfo::Sequence protocolDescriptorList;
50 protocolDescriptorList << QVariant::fromValue(l2capProtocol);
51 protocolDescriptorList << QVariant::fromValue(rfcommProtocol);
52 serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
53
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);
62
63 QBluetoothServiceInfo::Sequence browseGroup;
64 browseGroup << QVariant::fromValue(
65 QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup));
66 serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, browseGroup);
67
68 QBluetoothServiceInfo::Sequence serviceClassIds;
69 serviceClassIds << QVariant::fromValue(serviceUuid);
70 serviceClassIds << QVariant::fromValue(
71 QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
72 serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, serviceClassIds);
73
74 serviceInfo.setServiceUuid(serviceUuid);
75 serviceInfo.setServiceProvider(QBluetoothServiceDiscoveryAgent::tr("QtOhosBluetooth"));
76 serviceInfo.setServiceName(QBluetoothServiceDiscoveryAgent::tr("Serial Port Profile"));
77
78 return serviceInfo;
79}
80
81}
82
83QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
84 QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &)
85 : error(QBluetoothServiceDiscoveryAgent::NoError)
86 , state(Inactive)
87 , mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery)
88 , singleDevice(false)
89 , m_remoteDeviceProxy(QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::instance())
90 , q_ptr(qp)
91{
92 QObject::connect(
93 m_remoteDeviceProxy.get(),
94 &QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::remoteDeviceServicesRead,
95 q_ptr,
96 [this](const QtOhosBluetooth::RemoteDeviceServices &remoteDeviceServices) {
97 reportRemoteDeviceServices(remoteDeviceServices);
98 });
99}
100
101QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate() = default;
102
103void QBluetoothServiceDiscoveryAgentPrivate::reportErrorAsync(
104 QBluetoothServiceDiscoveryAgent::Error discoveryError, const QString &discoveryErrorString)
105{
106 error = discoveryError;
107 errorString = discoveryErrorString;
108 QMetaObject::invokeMethod(
109 q_ptr,
110 [this, discoveryError]() {
111 Q_EMIT q_ptr->errorOccurred(discoveryError);
112 },
113 Qt::QueuedConnection);
114}
115
116void QBluetoothServiceDiscoveryAgentPrivate::finishDeviceDiscoveryAsync()
117{
118 QMetaObject::invokeMethod(
119 q_ptr,
120 [this]() {
121 if (discoveryState() != ServiceDiscovery)
122 return;
123
124 _q_serviceDiscoveryFinished();
125 },
126 Qt::QueuedConnection);
127}
128
129void QBluetoothServiceDiscoveryAgentPrivate::reportRemoteDeviceServices(
130 const QtOhosBluetooth::RemoteDeviceServices &remoteDeviceServices)
131{
132 if (m_optRequestedDeviceId != remoteDeviceServices.deviceId)
133 return;
134
135 m_optRequestedDeviceId.reset();
136
137 const auto addressStr = QString::fromStdString(remoteDeviceServices.deviceId);
138 const QBluetoothDeviceInfo bluetoothDeviceInfo(
139 QBluetoothAddress(addressStr),
140 remoteDeviceServices.optDeviceName
141 ? QString::fromStdString(*remoteDeviceServices.optDeviceName)
142 : QString(),
143 remoteDeviceServices.optClassOfDevice.value_or(0));
144
145 const auto discoveredServicesCountBeforeDevice = discoveredServices.size();
146
147 auto reportServiceForUuid = [&](const QBluetoothUuid &uuid) {
148 const auto serviceInfo = makeRfcommServiceInfo(bluetoothDeviceInfo, uuid);
149 if (isDuplicatedService(serviceInfo))
150 return;
151
152 discoveredServices.append(serviceInfo);
153 QMetaObject::invokeMethod(
154 q_ptr,
155 [this, serviceInfo]() {
156 Q_EMIT q_ptr->serviceDiscovered(serviceInfo);
157 },
158 Qt::QueuedConnection);
159 };
160
161 if (remoteDeviceServices.optProfileUuids) {
162 for (const auto &profileUuid : *remoteDeviceServices.optProfileUuids) {
163 const auto uuid = QBluetoothUuid(QString::fromStdString(profileUuid));
164 if (uuidFilteredOut(uuidFilter, uuid))
165 continue;
166
167 reportServiceForUuid(uuid);
168 }
169 } else {
170 qCWarning(
171 QT_BT_OHOS,
172 "%s: could not read the remote standard profile UUIDs of the device %ls. Continuing...",
173 Q_FUNC_INFO, qUtf16Printable(addressStr));
174 }
175
176 if (singleDevice && !uuidFilter.isEmpty() && !remoteDeviceServices.lowEnergyOnly) {
177 for (const auto &requestedUuid : uuidFilter)
178 reportServiceForUuid(requestedUuid);
179 }
180
181 if (!remoteDeviceServices.optProfileUuids && singleDevice
182 && discoveredServices.size() == discoveredServicesCountBeforeDevice) {
183 reportErrorAsync(
184 QBluetoothServiceDiscoveryAgent::InputOutputError,
185 QBluetoothServiceDiscoveryAgent::tr("Cannot obtain service uuids"));
186 }
187
188 finishDeviceDiscoveryAsync();
189}
190
191void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address)
192{
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();
197 reportErrorAsync(
198 QBluetoothServiceDiscoveryAgent::PoweredOffError,
199 QBluetoothServiceDiscoveryAgent::tr("Device is powered off"));
200 finishDeviceDiscoveryAsync();
201 return;
202 }
203
204 m_optRequestedDeviceId = address.toString().toStdString();
205
206 const auto optErrorCode = m_remoteDeviceProxy->requestRemoteDeviceServices(address.toString());
207 if (!optErrorCode)
208 return;
209
210 m_optRequestedDeviceId.reset();
211
212 qCWarning(
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));
215
216 if (singleDevice) {
217 if (*optErrorCode == QOhosBluetoothErrorCode::PermissionDenied) {
218 reportErrorAsync(
219 QBluetoothServiceDiscoveryAgent::MissingPermissionsError,
220 QBluetoothServiceDiscoveryAgent::tr("Missing bluetooth permission"));
221 } else {
222 reportErrorAsync(
223 QBluetoothServiceDiscoveryAgent::InputOutputError,
224 QBluetoothServiceDiscoveryAgent::tr("Cannot obtain service uuids"));
225 }
226 }
227
228 finishDeviceDiscoveryAsync();
229}
230
231void QBluetoothServiceDiscoveryAgentPrivate::stop()
232{
233 m_optRequestedDeviceId.reset();
234 QMetaObject::invokeMethod(q_ptr, &QBluetoothServiceDiscoveryAgent::canceled, Qt::QueuedConnection);
235}
236
237QT_END_NAMESPACE
\inmodule QtBluetooth