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
qbluetoothdevicediscoveryagent_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/qbluetoothdevicediscoveryagent.h>
8#include <QtBluetooth/private/qohosbluetoothaccess_p.h>
9
10#include <QtCore/qloggingcategory.h>
11
12#include <algorithm>
13#include <optional>
14
16
18
19namespace {
20
22 const QtOhosBluetooth::DiscoveryResult &device)
23{
24 const QBluetoothAddress address(QString::fromStdString(device.deviceId));
25 if (address.isNull()) {
26 qCWarning(
27 QT_BT_OHOS, "%s: ignoring the device with an unexpected address: '%s'", Q_FUNC_INFO,
28 device.deviceId.c_str());
29 return std::nullopt;
30 }
31
32 QBluetoothDeviceInfo deviceInfo(
33 address, QString::fromStdString(device.deviceName), device.classOfDevice);
34 deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
35
36 return deviceInfo;
37}
38
40 const std::vector<QtOhosBluetooth::DiscoveryResult> &discoveredDevices)
41{
42 std::vector<QBluetoothDeviceInfo> foundDevicesInfos;
43 foundDevicesInfos.reserve(discoveredDevices.size());
44
45 for (const auto &discoveredDevice : discoveredDevices) {
46 auto optDeviceInfo = tryMakeDeviceInfo(discoveredDevice);
47 if (!optDeviceInfo)
48 continue;
49
50 optDeviceInfo->setRssi(discoveredDevice.rssi);
51
52 foundDevicesInfos.push_back(std::move(*optDeviceInfo));
53 }
54
55 return foundDevicesInfos;
56}
57
59 const std::vector<QtOhosBluetooth::DiscoveryResult> &pairedDevices)
60{
61 std::vector<QBluetoothDeviceInfo> pairedDevicesInfos;
62 pairedDevicesInfos.reserve(pairedDevices.size());
63
64 for (const auto &pairedDevice : pairedDevices) {
65 auto optDeviceInfo = tryMakeDeviceInfo(pairedDevice);
66 if (!optDeviceInfo)
67 continue;
68
69 optDeviceInfo->setCached(true);
70
71 pairedDevicesInfos.push_back(std::move(*optDeviceInfo));
72 }
73
74 return pairedDevicesInfos;
75}
76
78 QBluetoothDeviceInfo &existingDevice, const QBluetoothDeviceInfo &newDevice)
79{
80 QBluetoothDeviceInfo::Fields updatedFields = QBluetoothDeviceInfo::Field::None;
81
82 if (!newDevice.isCached() && existingDevice.rssi() != newDevice.rssi()) {
83 existingDevice.setRssi(newDevice.rssi());
84 updatedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI);
85 }
86
87 if (existingDevice.isCached() && !newDevice.isCached())
88 existingDevice.setCached(false);
89
90 if (existingDevice.name().isEmpty() && !newDevice.name().isEmpty())
91 existingDevice.setName(newDevice.name());
92
93 return updatedFields;
94}
95
96}
97
98QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
99 const QBluetoothAddress &deviceAdapter, QBluetoothDeviceDiscoveryAgent *parent)
100 : lowEnergySearchTimeout(-1)
101 , q_ptr(parent)
102{
103 if (!deviceAdapter.isNull()) {
104 qCWarning(
105 QT_BT_OHOS,
106 "%s: HarmonyOS does not support device adapter setting. Ignoring device adapter.",
107 Q_FUNC_INFO);
108 lastError = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError;
109 errorString = QBluetoothDeviceDiscoveryAgent::tr("Device adapter setting not supported");
110 emitAsyncError();
111 return;
112 }
113
114 m_discoveryAgentProxy = QtOhosBluetooth::QOhosBluetoothDeviceDiscoveryAgentProxy::instance();
115
116 QObject::connect(
117 m_discoveryAgentProxy.get(), &QtOhosBluetooth::QOhosBluetoothDeviceDiscoveryAgentProxy::discoveryStopped,
118 this,
119 [this]() {
120 reportDiscoveryStopped(DiscoveryStopReason::Finished);
121 });
122
123 QObject::connect(
124 m_discoveryAgentProxy.get(), &QtOhosBluetooth::QOhosBluetoothDeviceDiscoveryAgentProxy::discoveryStartFailed,
125 this,
126 [this]() {
127 if (!m_discoveryRequested)
128 return;
129
130 clearDiscoveryState();
131 lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
132 errorString = QBluetoothDeviceDiscoveryAgent::tr("Unable to start the device discovery");
133 emitAsyncError();
134 });
135
136 QObject::connect(
137 m_discoveryAgentProxy.get(), &QtOhosBluetooth::QOhosBluetoothDeviceDiscoveryAgentProxy::discoveryStopFailed,
138 this,
139 [this]() {
140 if (!m_discoveryRequested)
141 return;
142
143 clearDiscoveryState();
144 lastError = QBluetoothDeviceDiscoveryAgent::UnknownError;
145 errorString = QBluetoothDeviceDiscoveryAgent::tr("Timed out waiting for device discovery to stop");
146 emitAsyncError();
147 });
148
149 QObject::connect(
150 m_discoveryAgentProxy.get(), &QtOhosBluetooth::QOhosBluetoothDeviceDiscoveryAgentProxy::bluetoothPoweredOff,
151 this,
152 [this]() {
153 reportDiscoveryStopped(DiscoveryStopReason::BluetoothPoweredOff);
154 });
155
156 QObject::connect(
157 m_discoveryAgentProxy.get(), &QtOhosBluetooth::QOhosBluetoothDeviceDiscoveryAgentProxy::missingPermission,
158 this,
159 [this]() {
160 if (!m_discoveryRequested)
161 return;
162
163 clearDiscoveryState();
164 lastError = QBluetoothDeviceDiscoveryAgent::MissingPermissionsError;
165 errorString = QBluetoothDeviceDiscoveryAgent::tr("Missing permissions for device discovery");
166 emitAsyncError();
167 });
168
169 QObject::connect(
170 m_discoveryAgentProxy.get(), &QtOhosBluetooth::QOhosBluetoothDeviceDiscoveryAgentProxy::bluetoothDevicesFound,
171 this,
172 [this](const std::vector<QtOhosBluetooth::DiscoveryResult> &alreadyDiscoveredDevices) {
173 if (!m_discoveryRequested)
174 return;
175
176 reportDiscoveredDevices(processFoundDevices(alreadyDiscoveredDevices));
177 });
178}
179
180QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
181{
182 if (m_discoveryRequested && m_discoveryAgentProxy)
183 m_discoveryAgentProxy->stopBluetoothDiscovery();
184}
185
186bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
187{
188 if (m_pendingStart)
189 return true;
190
191 if (m_pendingCancel)
192 return false;
193
194 return m_discoveryRequested;
195}
196
197QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
198{
199 return QBluetoothDeviceDiscoveryAgent::ClassicMethod;
200}
201
202void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
203{
204 requestedMethods = methods;
205
206 if (!m_discoveryAgentProxy) {
207 lastError = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError;
208 errorString = QBluetoothDeviceDiscoveryAgent::tr("Device adapter setting not supported");
209 clearDiscoveryState();
210 emitAsyncError();
211 return;
212 }
213
214 auto accessProxy = QtOhosBluetooth::QOhosBluetoothAccessProxy::instance();
215 if (accessProxy->tryGetBluetoothState() != QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState::STATE_ON) {
216 lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
217 errorString = QBluetoothDeviceDiscoveryAgent::tr("Local bluetooth device is powered off");
218 clearDiscoveryState();
219 emitAsyncError();
220 return;
221 }
222
223 if (m_pendingCancel) {
224 m_pendingStart = true;
225 return;
226 }
227
228 lastError = QBluetoothDeviceDiscoveryAgent::NoError;
229 errorString.clear();
230 discoveredDevices.clear();
231
232 m_discoveryRequested = true;
233
234 if (m_discoveryAgentProxy->isForeignDiscoveryOngoing()) {
235 m_pendingStart = true;
236 m_discoveryAgentProxy->stopBluetoothDiscovery();
237 return;
238 }
239
240 reportPairedDevicesAsync();
241
242 m_discoveryAgentProxy->startBluetoothDiscovery();
243}
244
245void QBluetoothDeviceDiscoveryAgentPrivate::stop()
246{
247 if (!m_discoveryAgentProxy) {
248 lastError = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError;
249 errorString = QBluetoothDeviceDiscoveryAgent::tr("Device adapter setting not supported");
250 clearDiscoveryState();
251 emitAsyncError();
252 return;
253 }
254
255 m_pendingCancel = true;
256 m_pendingStart = false;
257 m_discoveryAgentProxy->stopBluetoothDiscovery();
258}
259
260void QBluetoothDeviceDiscoveryAgentPrivate::reportDiscoveryStopped(DiscoveryStopReason reason)
261{
262 if (!m_discoveryRequested)
263 return;
264
265 if (m_pendingStart) {
266 m_pendingStart = false;
267 m_pendingCancel = false;
268 start(requestedMethods);
269 } else if (m_pendingCancel) {
270 m_discoveryRequested = false;
271 m_pendingCancel = false;
272 Q_EMIT q_ptr->canceled();
273 } else if (reason == DiscoveryStopReason::BluetoothPoweredOff) {
274 m_discoveryRequested = false;
275 lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
276 errorString = QBluetoothDeviceDiscoveryAgent::tr("Local bluetooth device is powered off");
277 emitAsyncError();
278 } else {
279 m_discoveryRequested = false;
280 Q_EMIT q_ptr->finished();
281 }
282}
283
284void QBluetoothDeviceDiscoveryAgentPrivate::reportPairedDevicesAsync()
285{
286 QMetaObject::invokeMethod(
287 this,
288 [this]() {
289 if (!m_discoveryRequested)
290 return;
291
292 reportDiscoveredDevices(processPairedDevices(m_discoveryAgentProxy->getPairedDevices()));
293 },
294 Qt::QueuedConnection);
295}
296
297void QBluetoothDeviceDiscoveryAgentPrivate::reportDiscoveredDevices(
298 const std::vector<QBluetoothDeviceInfo> &bluetoothDevicesInfos)
299{
300 for (const auto &device : bluetoothDevicesInfos) {
301 auto alreadyDiscoveredDevice = std::find_if(
302 discoveredDevices.begin(), discoveredDevices.end(),
303 [&](const auto &alreadyDiscoveredDevice) {
304 return alreadyDiscoveredDevice.address() == device.address();
305 });
306
307 if (alreadyDiscoveredDevice != discoveredDevices.end()) {
308 const auto updatedFields = updateDeviceInfoIfNeeded(*alreadyDiscoveredDevice, device);
309 if (updatedFields != QBluetoothDeviceInfo::Field::None)
310 Q_EMIT q_ptr->deviceUpdated(*alreadyDiscoveredDevice, updatedFields);
311 } else {
312 discoveredDevices.append(device);
313 Q_EMIT q_ptr->deviceDiscovered(device);
314 }
315 }
316}
317
318void QBluetoothDeviceDiscoveryAgentPrivate::clearDiscoveryState()
319{
320 m_discoveryRequested = false;
321 m_pendingStart = false;
322 m_pendingCancel = false;
323}
324
325void QBluetoothDeviceDiscoveryAgentPrivate::emitAsyncError()
326{
327 QMetaObject::invokeMethod(
328 q_ptr,
329 [this, reportedError = lastError]() {
330 Q_EMIT q_ptr->errorOccurred(reportedError);
331 },
332 Qt::QueuedConnection);
333}
334
335QT_END_NAMESPACE
std::vector< QBluetoothDeviceInfo > processPairedDevices(const std::vector< QtOhosBluetooth::DiscoveryResult > &pairedDevices)
std::vector< QBluetoothDeviceInfo > processFoundDevices(const std::vector< QtOhosBluetooth::DiscoveryResult > &discoveredDevices)
std::optional< QBluetoothDeviceInfo > tryMakeDeviceInfo(const QtOhosBluetooth::DiscoveryResult &device)
QBluetoothDeviceInfo::Fields updateDeviceInfoIfNeeded(QBluetoothDeviceInfo &existingDevice, const QBluetoothDeviceInfo &newDevice)
QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcQIORing)