6#include <QtBluetooth/qbluetoothaddress.h>
7#include <QtBluetooth/qbluetoothlocaldevice.h>
8#include <QtBluetooth/private/qohosbluetoothaccess_p.h>
9#include <QtBluetooth/private/qohosbluetoothcommon_p.h>
10#include <QtBluetooth/private/qohosbluetoothlocaldevice_p.h>
11#include <QtBluetooth/private/qohosbluetoothremotedevice_p.h>
13#include <QtCore/qdeadlinetimer.h>
14#include <QtCore/qhash.h>
15#include <QtCore/qloggingcategory.h>
16#include <QtCore/qtimer.h>
25using QtOhosBluetooth::QOhosBluetoothErrorCode;
27Q_DECLARE_LOGGING_CATEGORY(QT_BT_OHOS)
31constexpr auto pairingRequestTimeout = std::chrono::seconds(30);
32constexpr auto hostModeRequestRetryDelay = std::chrono::milliseconds(500);
33constexpr auto hostModeRequestGiveUpDelay = std::chrono::seconds(20);
35QBluetoothLocalDevice::HostMode mapScanModeToQtHostMode(
36 QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::ScanMode scanMode)
38 using ScanMode = QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::ScanMode;
41 case ScanMode::SCAN_MODE_CONNECTABLE:
42 return QBluetoothLocalDevice::HostMode::HostConnectable;
43 case ScanMode::SCAN_MODE_GENERAL_DISCOVERABLE:
44 case ScanMode::SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE:
45 return QBluetoothLocalDevice::HostMode::HostDiscoverable;
46 case ScanMode::SCAN_MODE_LIMITED_DISCOVERABLE:
47 case ScanMode::SCAN_MODE_CONNECTABLE_LIMITED_DISCOVERABLE:
48 return QBluetoothLocalDevice::HostMode::HostDiscoverableLimitedInquiry;
49 case ScanMode::SCAN_MODE_NONE:
50 return QBluetoothLocalDevice::HostMode::HostPoweredOff;
53 qOhosReportFatalErrorAndAbort(
54 "%s: unexpected ScanMode value %d", Q_FUNC_INFO,
static_cast<
int>(scanMode));
57QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::ScanMode mapHostModeToOhosScanMode(
58 QBluetoothLocalDevice::HostMode hostMode)
60 using ScanMode = QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::ScanMode;
63 case QBluetoothLocalDevice::HostMode::HostPoweredOff:
64 return ScanMode::SCAN_MODE_NONE;
65 case QBluetoothLocalDevice::HostMode::HostConnectable:
66 return ScanMode::SCAN_MODE_CONNECTABLE;
67 case QBluetoothLocalDevice::HostMode::HostDiscoverable:
68 return ScanMode::SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE;
69 case QBluetoothLocalDevice::HostMode::HostDiscoverableLimitedInquiry:
70 return ScanMode::SCAN_MODE_CONNECTABLE_LIMITED_DISCOVERABLE;
73 qOhosReportFatalErrorAndAbort(
74 "%s: unexpected HostMode value %d", Q_FUNC_INFO,
static_cast<
int>(hostMode));
77bool isAdapterStateSettled(QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState bluetoothState)
79 using BluetoothState = QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState;
81 switch (bluetoothState) {
82 case BluetoothState::STATE_BLE_TURNING_OFF:
83 case BluetoothState::STATE_BLE_TURNING_ON:
84 case BluetoothState::STATE_TURNING_OFF:
85 case BluetoothState::STATE_TURNING_ON:
87 case BluetoothState::STATE_BLE_ON:
88 case BluetoothState::STATE_OFF:
89 case BluetoothState::STATE_ON:
93 qOhosReportFatalErrorAndAbort(
94 "%s: unexpected BluetoothState value %d", Q_FUNC_INFO,
static_cast<
int>(bluetoothState));
97QBluetoothLocalDevice::HostMode getBluetoothLocalDeviceHostMode(
98 QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState bluetoothLocalAdapterState)
100 if (bluetoothLocalAdapterState != QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState::STATE_ON)
101 return QBluetoothLocalDevice::HostMode::HostPoweredOff;
103 const auto optScanMode = QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::instance()->tryGetScanMode();
105 ? mapScanModeToQtHostMode(*optScanMode)
106 : QBluetoothLocalDevice::HostMode::HostPoweredOff;
109QBluetoothLocalDevice::Pairing mapOhosBondStateToLocalDevicePairing(
110 QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::BondState bondState)
112 return bondState == QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::BondState::BOND_STATE_BONDED
113 ? QBluetoothLocalDevice::Pairing::Paired
114 : QBluetoothLocalDevice::Pairing::Unpaired;
117enum class HostModeUpdateSource { ChangeEvent, LiveRead };
122 QOhosBluetoothLocalDevicePrivate(QBluetoothLocalDevice *qBluetoothLocalDevice,
const QBluetoothAddress &address);
124 bool isValid()
const override;
125 std::optional<QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState> tryGetBluetoothState()
const;
126 std::optional<QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::BondState> tryGetPairState(
127 const QBluetoothAddress &address)
const;
128 void requestHostMode(QBluetoothLocalDevice::HostMode requestedHostMode);
129 void requestPowerOn();
130 void cancelHostModeRequest();
131 void handleAdapterHostModeChanged(
132 QBluetoothLocalDevice::HostMode hostMode,
133 std::optional<QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState> optBluetoothState,
134 HostModeUpdateSource source = HostModeUpdateSource::ChangeEvent);
136 bool pairDevice(
const QBluetoothAddress &address);
137 void cancelPendingPairingRequests();
140 struct HostModeRequest
142 QBluetoothLocalDevice::HostMode target = QBluetoothLocalDevice::HostMode::HostPoweredOff;
143 bool anyPoweredOnAccepted =
false;
144 bool awaitingOutcome =
false;
145 bool powerSwitchIssued =
false;
146 bool scanModeIssued =
false;
147 QDeadlineTimer deadline;
150 void registerHostModeRequest(
151 QBluetoothLocalDevice::HostMode target,
bool anyPoweredOnAccepted);
152 void issueHostModeRequest();
153 void resolveHostModeRequestFromAdapterState();
154 void scheduleHostModeRetry();
155 void awaitHostModeRequestOutcome(
bool powerSwitchIssued);
156 void giveUpHostModeRequest();
157 static bool isRequestSatisfiedBy(
158 const HostModeRequest &request, QBluetoothLocalDevice::HostMode hostMode,
159 bool adapterPoweredOn);
160 static bool isPowerSwitchOutcomePending(
161 const HostModeRequest &request,
bool adapterPoweredOn);
162 void rearmPendingPairingRequestsTimer();
163 void handleExpiredPendingPairingRequests();
164 void emitAsyncError(QBluetoothLocalDevice::Error error);
166 QBluetoothLocalDevice *m_qBluetoothLocalDevice;
167 std::shared_ptr<QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy> m_remoteDeviceProxy;
168 bool m_isValid =
false;
169 QBluetoothLocalDevice::HostMode m_lastHostMode =
170 QBluetoothLocalDevice::HostMode::HostPoweredOff;
171 std::optional<HostModeRequest> m_optHostModeRequest = std::nullopt;
172 QHash<QBluetoothAddress, QDeadlineTimer> m_pendingPairingRequests;
173 QTimer m_pendingPairingRequestsTimer;
174 QTimer m_hostModeRequestTimer;
177QOhosBluetoothLocalDevicePrivate::QOhosBluetoothLocalDevicePrivate(
178 QBluetoothLocalDevice *qBluetoothLocalDevice,
const QBluetoothAddress &address)
179 : m_qBluetoothLocalDevice(qBluetoothLocalDevice)
180 , m_remoteDeviceProxy(QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::instance())
182 if (!address.isNull()) {
184 QT_BT_OHOS,
"%s: HarmonyOS does not support device adapter setting. Ignoring address %ls",
185 Q_FUNC_INFO, qUtf16Printable(address.toString()));
192 if (
const auto optBluetoothState = tryGetBluetoothState())
193 m_lastHostMode = getBluetoothLocalDeviceHostMode(*optBluetoothState);
196 QtOhosBluetooth::QOhosBluetoothAccessProxy::instance().get(),
197 &QtOhosBluetooth::QOhosBluetoothAccessProxy::stateChanged,
200 if (state != QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState::STATE_ON)
201 cancelPendingPairingRequests();
203 handleAdapterHostModeChanged(getBluetoothLocalDeviceHostMode(state), state);
207 QtOhosBluetooth::QOhosBluetoothAccessProxy::instance().get(),
208 &QtOhosBluetooth::QOhosBluetoothAccessProxy::setBluetoothEnabledFailed,
210 [
this](QOhosBluetoothErrorCode errorCode) {
211 if (!m_optHostModeRequest || !m_optHostModeRequest->powerSwitchIssued)
215 QT_BT_OHOS,
"%s: the bluetooth switch was not performed, error code: %u",
216 Q_FUNC_INFO, qToUnderlying(errorCode));
217 giveUpHostModeRequest();
221 QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::instance().get(),
222 &QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::scanModeChanged,
224 [
this](
auto scanMode) {
225 const auto optBluetoothState = tryGetBluetoothState();
226 if (optBluetoothState != QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState::STATE_ON)
229 handleAdapterHostModeChanged(mapScanModeToQtHostMode(scanMode), optBluetoothState);
233 m_remoteDeviceProxy.get(),
234 &QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::bondStateChanged,
236 [
this](
const QString &deviceId, QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::BondState bondState,
237 std::optional<QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::UnbondCause> optUnbondCause) {
238 const QBluetoothAddress deviceAddress(deviceId);
239 if (deviceAddress.isNull()) {
242 "%s: ignoring the bond state change for a device with an unexpected address: '%ls'",
243 Q_FUNC_INFO, qUtf16Printable(deviceId));
247 if (!m_pendingPairingRequests.contains(deviceAddress))
251 case QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::BondState::BOND_STATE_INVALID:
253 QT_BT_OHOS,
"%s: pairing with the device %ls failed with the unbond cause %d",
254 Q_FUNC_INFO, qUtf16Printable(deviceAddress.toString()),
255 optUnbondCause ?
static_cast<
int>(*optUnbondCause) : -1);
256 m_pendingPairingRequests.remove(deviceAddress);
257 rearmPendingPairingRequestsTimer();
258 emitAsyncError(QBluetoothLocalDevice::Error::PairingError);
260 case QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::BondState::BOND_STATE_BONDING:
262 case QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::BondState::BOND_STATE_BONDED:
263 m_pendingPairingRequests.remove(deviceAddress);
264 rearmPendingPairingRequestsTimer();
265 Q_EMIT m_qBluetoothLocalDevice->pairingFinished(
266 deviceAddress, QBluetoothLocalDevice::Paired);
272 m_remoteDeviceProxy.get(),
273 &QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::pairDeviceFailed,
275 [
this](
const QString &deviceId) {
276 const QBluetoothAddress deviceAddress(deviceId);
277 if (!m_pendingPairingRequests.contains(deviceAddress))
281 QT_BT_OHOS,
"%s: the pairing request for the device %ls was rejected", Q_FUNC_INFO,
282 qUtf16Printable(deviceId));
283 m_pendingPairingRequests.remove(deviceAddress);
284 rearmPendingPairingRequestsTimer();
285 emitAsyncError(QBluetoothLocalDevice::Error::PairingError);
288 auto emitMissingPermissionsError = [
this]() {
289 emitAsyncError(QBluetoothLocalDevice::MissingPermissionsError);
292 QtOhosBluetooth::QOhosBluetoothAccessProxy::instance().get(),
293 &QtOhosBluetooth::QOhosBluetoothAccessProxy::missingPermission,
294 this, emitMissingPermissionsError);
296 QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::instance().get(),
297 &QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::missingPermission,
298 this, emitMissingPermissionsError);
300 m_remoteDeviceProxy.get(),
301 &QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::missingPermission,
302 this, emitMissingPermissionsError);
304 m_pendingPairingRequestsTimer.setSingleShot(
true);
306 &m_pendingPairingRequestsTimer, &QTimer::timeout,
this,
308 handleExpiredPendingPairingRequests();
311 m_hostModeRequestTimer.setSingleShot(
true);
313 &m_hostModeRequestTimer, &QTimer::timeout,
this,
315 if (!m_optHostModeRequest)
318 if (m_optHostModeRequest->awaitingOutcome
319 || m_optHostModeRequest->deadline.hasExpired()) {
320 resolveHostModeRequestFromAdapterState();
322 if (m_optHostModeRequest && !m_hostModeRequestTimer.isActive())
323 giveUpHostModeRequest();
328 issueHostModeRequest();
332bool QOhosBluetoothLocalDevicePrivate::isValid()
const
337std::optional<QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState> QOhosBluetoothLocalDevicePrivate::tryGetBluetoothState()
const
339 return QtOhosBluetooth::QOhosBluetoothAccessProxy::instance()->tryGetBluetoothState();
342std::optional<QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::BondState> QOhosBluetoothLocalDevicePrivate::tryGetPairState(
343 const QBluetoothAddress &address)
const
345 return m_remoteDeviceProxy->tryGetPairState(address.toString());
348void QOhosBluetoothLocalDevicePrivate::requestHostMode(
349 QBluetoothLocalDevice::HostMode requestedHostMode)
351 registerHostModeRequest(requestedHostMode,
false);
354void QOhosBluetoothLocalDevicePrivate::requestPowerOn()
356 registerHostModeRequest(QBluetoothLocalDevice::HostMode::HostConnectable,
true);
359void QOhosBluetoothLocalDevicePrivate::registerHostModeRequest(
360 QBluetoothLocalDevice::HostMode target,
bool anyPoweredOnAccepted)
362 m_hostModeRequestTimer.stop();
363 m_optHostModeRequest = HostModeRequest {
365 .anyPoweredOnAccepted = anyPoweredOnAccepted,
366 .awaitingOutcome =
false,
367 .powerSwitchIssued =
false,
368 .scanModeIssued =
false,
369 .deadline = QDeadlineTimer(hostModeRequestGiveUpDelay),
372 issueHostModeRequest();
375bool QOhosBluetoothLocalDevicePrivate::isRequestSatisfiedBy(
376 const HostModeRequest &request, QBluetoothLocalDevice::HostMode hostMode,
377 bool adapterPoweredOn)
379 if (request.anyPoweredOnAccepted)
380 return adapterPoweredOn && hostMode != QBluetoothLocalDevice::HostMode::HostPoweredOff;
382 if (request.target == QBluetoothLocalDevice::HostMode::HostPoweredOff)
383 return !adapterPoweredOn;
385 if (request.target == QBluetoothLocalDevice::HostMode::HostDiscoverableLimitedInquiry)
386 return hostMode == QBluetoothLocalDevice::HostMode::HostDiscoverableLimitedInquiry
387 || hostMode == QBluetoothLocalDevice::HostMode::HostDiscoverable;
389 return hostMode == request.target;
392void QOhosBluetoothLocalDevicePrivate::resolveHostModeRequestFromAdapterState()
394 const auto optBluetoothState = tryGetBluetoothState();
395 if (!optBluetoothState)
398 handleAdapterHostModeChanged(
399 getBluetoothLocalDeviceHostMode(*optBluetoothState), optBluetoothState,
400 HostModeUpdateSource::LiveRead);
403void QOhosBluetoothLocalDevicePrivate::issueHostModeRequest()
405 Q_ASSERT(m_optHostModeRequest);
406 using BluetoothState = QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState;
408 const auto target = m_optHostModeRequest->target;
409 const auto optBluetoothState = tryGetBluetoothState();
411 if (optBluetoothState && isAdapterStateSettled(*optBluetoothState)
412 && isRequestSatisfiedBy(
413 *m_optHostModeRequest, getBluetoothLocalDeviceHostMode(*optBluetoothState),
414 *optBluetoothState == BluetoothState::STATE_ON)) {
415 cancelHostModeRequest();
419 const auto handleOutcome =
420 [
this](std::optional<QOhosBluetoothErrorCode> optErrorCode,
bool isPowerSwitchCall) {
422 if (isPowerSwitchCall) {
423 awaitHostModeRequestOutcome(
true);
427 m_optHostModeRequest->scanModeIssued =
true;
428 resolveHostModeRequestFromAdapterState();
430 if (m_optHostModeRequest && !m_hostModeRequestTimer.isActive())
431 awaitHostModeRequestOutcome(
false);
436 if (*optErrorCode == QOhosBluetoothErrorCode::OperationFailed
437 || *optErrorCode == QOhosBluetoothErrorCode::BluetoothDisabled) {
438 if (isPowerSwitchCall)
439 awaitHostModeRequestOutcome(
true);
441 scheduleHostModeRetry();
446 if (*optErrorCode == QOhosBluetoothErrorCode::PermissionDenied) {
447 cancelHostModeRequest();
452 QT_BT_OHOS,
"%s: the host mode request was rejected with error code: %u",
453 Q_FUNC_INFO, qToUnderlying(*optErrorCode));
454 giveUpHostModeRequest();
457 if (!optBluetoothState) {
458 scheduleHostModeRetry();
462 if (!isAdapterStateSettled(*optBluetoothState)) {
463 awaitHostModeRequestOutcome(
false);
467 m_optHostModeRequest->scanModeIssued =
false;
469 if (target == QBluetoothLocalDevice::HostMode::HostPoweredOff) {
470 Q_ASSERT(*optBluetoothState == BluetoothState::STATE_ON);
472 QtOhosBluetooth::QOhosBluetoothAccessProxy::instance()->trySetBluetoothEnabled(
false),
477 if (*optBluetoothState != BluetoothState::STATE_ON) {
479 QtOhosBluetooth::QOhosBluetoothAccessProxy::instance()->trySetBluetoothEnabled(
true),
485 QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::instance()->trySetBluetoothScanMode(
486 mapHostModeToOhosScanMode(target)),
490void QOhosBluetoothLocalDevicePrivate::scheduleHostModeRetry()
492 Q_ASSERT(m_optHostModeRequest);
493 if (m_optHostModeRequest->deadline.hasExpired()) {
494 giveUpHostModeRequest();
498 m_optHostModeRequest->awaitingOutcome =
false;
499 m_optHostModeRequest->powerSwitchIssued =
false;
500 m_hostModeRequestTimer.start(hostModeRequestRetryDelay);
503bool QOhosBluetoothLocalDevicePrivate::isPowerSwitchOutcomePending(
504 const HostModeRequest &request,
bool adapterPoweredOn)
506 if (!request.powerSwitchIssued)
509 return request.target == QBluetoothLocalDevice::HostMode::HostPoweredOff
514void QOhosBluetoothLocalDevicePrivate::awaitHostModeRequestOutcome(
bool powerSwitchIssued)
516 Q_ASSERT(m_optHostModeRequest);
517 const auto remainingTime = m_optHostModeRequest->deadline.remainingTimeAsDuration();
518 if (remainingTime <= std::chrono::milliseconds::zero()) {
519 giveUpHostModeRequest();
523 m_optHostModeRequest->awaitingOutcome =
true;
524 m_optHostModeRequest->powerSwitchIssued = powerSwitchIssued;
525 m_hostModeRequestTimer.start(
526 std::chrono::ceil<std::chrono::milliseconds>(remainingTime));
529void QOhosBluetoothLocalDevicePrivate::giveUpHostModeRequest()
531 Q_ASSERT(m_optHostModeRequest);
533 QT_BT_OHOS,
"%s: giving up on the requested host mode %d, the adapter stays in %d",
534 Q_FUNC_INFO,
static_cast<
int>(m_optHostModeRequest->target),
535 static_cast<
int>(m_lastHostMode));
537 cancelHostModeRequest();
539 emitAsyncError(QBluetoothLocalDevice::Error::UnknownError);
542void QOhosBluetoothLocalDevicePrivate::cancelHostModeRequest()
544 m_hostModeRequestTimer.stop();
545 m_optHostModeRequest.reset();
548void QOhosBluetoothLocalDevicePrivate::handleAdapterHostModeChanged(
549 QBluetoothLocalDevice::HostMode hostMode,
550 std::optional<QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState> optBluetoothState,
551 HostModeUpdateSource source)
553 const auto hostModeChanged = m_lastHostMode != hostMode;
554 m_lastHostMode = hostMode;
556 const auto adapterSettled = optBluetoothState && isAdapterStateSettled(*optBluetoothState);
557 const auto adapterPoweredOn =
558 optBluetoothState == QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState::STATE_ON;
560 if (m_optHostModeRequest && adapterSettled) {
561 const auto scanModeApplied = source == HostModeUpdateSource::LiveRead
562 || m_optHostModeRequest->anyPoweredOnAccepted
563 || m_optHostModeRequest->target == QBluetoothLocalDevice::HostMode::HostPoweredOff
564 || m_optHostModeRequest->scanModeIssued;
567 && isRequestSatisfiedBy(*m_optHostModeRequest, hostMode, adapterPoweredOn)) {
568 cancelHostModeRequest();
569 }
else if (!isPowerSwitchOutcomePending(*m_optHostModeRequest, adapterPoweredOn)) {
570 if (m_optHostModeRequest->powerSwitchIssued && adapterPoweredOn)
571 m_optHostModeRequest->deadline = QDeadlineTimer(hostModeRequestGiveUpDelay);
573 scheduleHostModeRetry();
577 if (hostModeChanged) {
578 QMetaObject::invokeMethod(
579 m_qBluetoothLocalDevice,
580 [qBluetoothLocalDevice = m_qBluetoothLocalDevice, hostMode]() {
581 Q_EMIT qBluetoothLocalDevice->hostModeStateChanged(hostMode);
583 Qt::QueuedConnection);
587bool QOhosBluetoothLocalDevicePrivate::pairDevice(
const QBluetoothAddress &address)
589 const auto addressStr = address.toString().toStdString();
590 if (m_pendingPairingRequests.contains(address)) {
593 "%s: pairing request ignored due to already pending pairing process to the device with address %s",
594 Q_FUNC_INFO, addressStr.c_str());
598 m_pendingPairingRequests.insert(address, QDeadlineTimer(pairingRequestTimeout));
599 rearmPendingPairingRequestsTimer();
601 if (!m_remoteDeviceProxy->pairDevice(address.toString())) {
602 m_pendingPairingRequests.remove(address);
603 rearmPendingPairingRequestsTimer();
610void QOhosBluetoothLocalDevicePrivate::cancelPendingPairingRequests()
612 if (m_pendingPairingRequests.isEmpty())
615 m_pendingPairingRequests.clear();
616 rearmPendingPairingRequestsTimer();
617 emitAsyncError(QBluetoothLocalDevice::Error::PairingError);
620void QOhosBluetoothLocalDevicePrivate::emitAsyncError(QBluetoothLocalDevice::Error error)
622 QMetaObject::invokeMethod(
623 m_qBluetoothLocalDevice,
625 Q_EMIT m_qBluetoothLocalDevice->errorOccurred(error);
627 Qt::QueuedConnection);
630void QOhosBluetoothLocalDevicePrivate::rearmPendingPairingRequestsTimer()
632 if (m_pendingPairingRequests.isEmpty()) {
633 m_pendingPairingRequestsTimer.stop();
637 const auto earliestDeadline =
std::min_element(
638 m_pendingPairingRequests.cbegin(), m_pendingPairingRequests.cend());
640 m_pendingPairingRequestsTimer.start(
642 std::chrono::ceil<std::chrono::milliseconds>(earliestDeadline->remainingTimeAsDuration()),
643 std::chrono::milliseconds::zero()));
646void QOhosBluetoothLocalDevicePrivate::handleExpiredPendingPairingRequests()
648 QList<QBluetoothAddress> expiredAddresses;
649 for (
auto pendingPairingRequest = m_pendingPairingRequests.cbegin();
650 pendingPairingRequest != m_pendingPairingRequests.cend(); ++pendingPairingRequest) {
651 if (pendingPairingRequest.value().hasExpired())
652 expiredAddresses.append(pendingPairingRequest.key());
655 for (
const auto &expiredAddress : expiredAddresses)
656 m_pendingPairingRequests.remove(expiredAddress);
658 rearmPendingPairingRequestsTimer();
660 for (
const auto &expiredAddress : expiredAddresses) {
661 const auto optPairState = tryGetPairState(expiredAddress);
663 && *optPairState == QtOhosBluetooth::QOhosBluetoothRemoteDeviceProxy::BondState::BOND_STATE_BONDED) {
664 Q_EMIT m_qBluetoothLocalDevice->pairingFinished(
665 expiredAddress, QBluetoothLocalDevice::Paired);
670 QT_BT_OHOS,
"%s: pairing with the device %ls not confirmed by the system in time",
671 Q_FUNC_INFO, qUtf16Printable(expiredAddress.toString()));
672 emitAsyncError(QBluetoothLocalDevice::Error::PairingError);
682QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent)
683 : QBluetoothLocalDevice(QBluetoothAddress(), parent)
687QBluetoothLocalDevice::QBluetoothLocalDevice(
const QBluetoothAddress &address, QObject *parent)
689 , d_ptr(
new QOhosBluetoothLocalDevicePrivate(
this, address))
691 registerQBluetoothLocalDeviceMetaType();
694QString QBluetoothLocalDevice::name()
const
696 if (!d_ptr->isValid()) {
698 QT_BT_OHOS,
"%s: local device is not valid. Can't get local device name.", Q_FUNC_INFO);
702 const auto optLocalDeviceName = QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::instance()->tryGetLocalDeviceName();
704 return optLocalDeviceName
705 ? *optLocalDeviceName
709QBluetoothAddress QBluetoothLocalDevice::address()
const
714void QBluetoothLocalDevice::powerOn()
716 if (!d_ptr->isValid()) {
717 qCWarning(QT_BT_OHOS,
"%s: local device is not valid. Ignoring...", Q_FUNC_INFO);
721 if (hostMode() != HostMode::HostPoweredOff) {
722 qCWarning(QT_BT_OHOS,
"%s: bluetooth is not powered off. Ignoring...", Q_FUNC_INFO);
726 static_cast<QOhosBluetoothLocalDevicePrivate *>(d_ptr)->requestPowerOn();
729void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
731 if (!d_ptr->isValid()) {
732 qCWarning(QT_BT_OHOS,
"%s: local device is not valid. Ignoring...", Q_FUNC_INFO);
736 auto *ohosBluetoothLocalDevicePriv =
static_cast<QOhosBluetoothLocalDevicePrivate *>(d_ptr);
738 const auto optBluetoothState = ohosBluetoothLocalDevicePriv->tryGetBluetoothState();
739 const auto adapterSettled = optBluetoothState && isAdapterStateSettled(*optBluetoothState);
741 if (adapterSettled && mode == QBluetoothLocalDevice::HostMode::HostPoweredOff
742 && *optBluetoothState != QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState::STATE_ON) {
745 "%s: Bluetooth is not in powered on state. Cancelling the pending host mode request.",
747 ohosBluetoothLocalDevicePriv->cancelHostModeRequest();
751 ohosBluetoothLocalDevicePriv->requestHostMode(mode);
754QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode()
const
756 if (!d_ptr->isValid()) {
758 QT_BT_OHOS,
"%s: local device is not valid. Reporting powered off host mode.",
760 return QBluetoothLocalDevice::HostPoweredOff;
763 const auto optBluetoothState =
static_cast<QOhosBluetoothLocalDevicePrivate *>(d_ptr)->tryGetBluetoothState();
764 if (!optBluetoothState)
765 return QBluetoothLocalDevice::HostPoweredOff;
767 return getBluetoothLocalDeviceHostMode(*optBluetoothState);
770QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices()
const
775QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
777 const auto optLocalDeviceName =
778 QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::instance()->tryGetLocalDeviceName();
779 if (!optLocalDeviceName)
782 QBluetoothHostInfo bluetoothHostInfo;
783 bluetoothHostInfo.setName(*optLocalDeviceName);
784 return { bluetoothHostInfo };
787void QBluetoothLocalDevice::requestPairing(
const QBluetoothAddress &address, Pairing pairing)
789 auto emitPairingError = [
this]() {
790 QMetaObject::invokeMethod(
793 Q_EMIT errorOccurred(QBluetoothLocalDevice::PairingError);
795 Qt::QueuedConnection);
798 auto emitPairingFinishedAsync = [
this, address](Pairing finishedPairing) {
799 QMetaObject::invokeMethod(
801 [
this, address, finishedPairing]() {
802 Q_EMIT pairingFinished(address, finishedPairing);
804 Qt::QueuedConnection);
807 if (!isValid() || address.isNull()) {
809 QT_BT_OHOS,
"%s: local device is not valid or the device address is null. Ignoring...",
815 const auto optBluetoothState =
static_cast<QOhosBluetoothLocalDevicePrivate *>(d_ptr)->tryGetBluetoothState();
816 if (optBluetoothState != QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState::STATE_ON) {
817 qCWarning(QT_BT_OHOS,
"%s: bluetooth not in powered on state. Ignoring...", Q_FUNC_INFO);
823 case AuthorizedPaired:
826 "%s: AuthorizedPaired not supported on HarmonyOS. Falling back to Paired.",
830 if (pairingStatus(address) == QBluetoothLocalDevice::Pairing::Paired) {
832 QT_BT_OHOS,
"%s: Already paired with the device %ls. Ignoring pairing request.",
833 Q_FUNC_INFO, qUtf16Printable(address.toString()));
834 emitPairingFinishedAsync(QBluetoothLocalDevice::Pairing::Paired);
838 if (!
static_cast<QOhosBluetoothLocalDevicePrivate *>(d_ptr)->pairDevice(address))
842 if (pairingStatus(address) == QBluetoothLocalDevice::Pairing::Unpaired) {
844 QT_BT_OHOS,
"%s: Not paired with the device %ls. Ignoring unpairing request.",
845 Q_FUNC_INFO, qUtf16Printable(address.toString()));
846 emitPairingFinishedAsync(QBluetoothLocalDevice::Pairing::Unpaired);
851 QT_BT_OHOS,
"%s: Unpairing not supported on HarmonyOS for paired devices.",
858QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
const QBluetoothAddress &address)
const
860 if (!d_ptr->isValid()) {
862 QT_BT_OHOS,
"%s: local device is not valid. Reporting unpaired device.", Q_FUNC_INFO);
866 if (address.isNull()) {
868 QT_BT_OHOS,
"%s: device address is null. Reporting unpaired device.", Q_FUNC_INFO);
872 const auto optBluetoothState =
static_cast<QOhosBluetoothLocalDevicePrivate *>(d_ptr)->tryGetBluetoothState();
873 if (optBluetoothState != QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState::STATE_ON)
876 const auto optPairState =
877 static_cast<QOhosBluetoothLocalDevicePrivate *>(d_ptr)->tryGetPairState(address);
879 return QBluetoothLocalDevice::Pairing::Unpaired;
881 return mapOhosBondStateToLocalDevicePairing(*optPairState);