Revision control
+ // Copyright (C) 2026 The Qt Company Ltd.
+ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+ #include "qohosbluetoothremotedevice_p.h"
+
+ #include <QtBluetooth/private/qohosbluetoothcommon_p.h>
+
+ #include <QtCore/qloggingcategory.h>
+ #include <QtCore/private/qcore_ohos_p.h>
+ #include <QtCore/private/qnapi_p.h>
+ #include <QtCore/private/qohosjstools_p.h>
+ #include <QtCore/private/qohoslogger_p.h>
+
+ #include <optional>
+ #include <string>
+ #include <vector>
+
+ QT_BEGIN_NAMESPACE
+
+ Q_DECLARE_LOGGING_CATEGORY(QT_BT_OHOS)
+
+ namespace QtOhosBluetooth {
+
+ namespace {
+
+ std::shared_ptr<void> registerBondStateChangeConsumer(
+ QOhosJsState &jsState,
+ QOhosConsumer<std::string, std::optional<QOhosBluetoothRemoteDeviceProxy::BondState>, std::optional<QOhosBluetoothRemoteDeviceProxy::UnbondCause>> bondStateChangeConsumer)
+ {
+ return registerQOhosOnOffMethodsBasedEventHandler(
+ jsState.eval<QNapi::Object>("@ohos.bluetooth.connection"), "bondStateChange",
+ [bondStateChangeConsumer = std::move(bondStateChangeConsumer)](const QOhosCallbackInfo &cbInfo) {
+ auto bondStateObject = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
+
+ auto deviceId = bondStateObject.get<QNapi::String>("deviceId").Utf8Value();
+ const auto optBondState = cbInfo.jsState().tryMapOhosEnumFromJs<QOhosBluetoothRemoteDeviceProxy::BondState>(
+ bondStateObject.get<QNapi::Number>("state"));
+ const auto unbondCauseValue =
+ QNapi::getOptionalPropOrEmpty<QNapi::Number>(bondStateObject, "cause");
+ const auto optUnbondCause = unbondCauseValue.IsEmpty()
+ ? std::optional<QOhosBluetoothRemoteDeviceProxy::UnbondCause>()
+ : cbInfo.jsState().tryMapOhosEnumFromJs<QOhosBluetoothRemoteDeviceProxy::UnbondCause>(
+ unbondCauseValue);
+
+ bondStateChangeConsumer(deviceId, optBondState, optUnbondCause);
+ },
+ {
+ .optOnCallExceptionHandler = [](const Napi::Error &error) {
+ if (const auto optErrorCode = tryGetKnownErrorCode(error.Value(), Q_FUNC_INFO)) {
+ qOhosPrintfWarning(
+ "%s: cannot register the bond state change consumer, error code: %u",
+ Q_FUNC_INFO, qToUnderlying(*optErrorCode));
+ }
+ },
+ });
+ }
+
+ std::optional<QOhosBluetoothRemoteDeviceProxy::BondState> readPairState(
+ QOhosJsState &jsState, const std::string &deviceId)
+ {
+ if (!isBluetoothEnabled(jsState))
+ return std::nullopt;
+
+ try {
+ return jsState.tryMapOhosEnumFromJs<QOhosBluetoothRemoteDeviceProxy::BondState>(
+ jsState.eval<QNapi::Number>(
+ "@ohos.bluetooth.connection.getPairState(*)", {deviceId}));
+ } catch (const Napi::Error &error) {
+ if (const auto optErrorCode = tryGetKnownErrorCode(error.Value(), Q_FUNC_INFO)) {
+ qOhosPrintfWarning(
+ "%s: cannot read the pair state of the device %s, error code: %u", Q_FUNC_INFO,
+ deviceId.c_str(), qToUnderlying(*optErrorCode));
+ }
+ return std::nullopt;
+ }
+ }
+
+ }
+
+ QOhosBluetoothRemoteDeviceProxy::QOhosBluetoothRemoteDeviceProxy()
+ {
+ ensureBondStateChangeConsumerRegistered();
+ }
+
+ bool QOhosBluetoothRemoteDeviceProxy::ensureBondStateChangeConsumerRegistered()
+ {
+ if (m_bondStateChangeConsumerHandle)
+ return true;
+
+ if (!checkAccessBluetoothPermissionGranted(Q_FUNC_INFO))
+ return false;
+
+ auto selfRef = QtOhos::makeQThreadSafeRef(this);
+ m_bondStateChangeConsumerHandle = QOhosJsThreadGateway::eval(
+ [&](QOhosJsState &jsState) -> std::shared_ptr<void> {
+ auto bondStateChangeConsumerHandle = registerBondStateChangeConsumer(
+ jsState,
+ [selfRef](std::string deviceId, std::optional<BondState> optBondState, std::optional<UnbondCause> optUnbondCause) {
+ if (!optBondState)
+ return;
+
+ selfRef.visitInQtThreadIfAlive(
+ [deviceId = QString::fromStdString(deviceId), bondState = *optBondState, optUnbondCause](auto &self) {
+ Q_EMIT self.bondStateChanged(deviceId, bondState, optUnbondCause);
+ });
+ });
+
+ if (!bondStateChangeConsumerHandle)
+ return {};
+
+ return QtOhos::makeProxyWithJsThreadDeleter(std::move(bondStateChangeConsumerHandle));
+ },
+ Q_FUNC_INFO);
+
+ return m_bondStateChangeConsumerHandle != nullptr;
+ }
+
+ std::shared_ptr<QOhosBluetoothRemoteDeviceProxy> QOhosBluetoothRemoteDeviceProxy::instance()
+ {
+ static std::weak_ptr<QOhosBluetoothRemoteDeviceProxy> weakInstance;
+
+ auto instance = weakInstance.lock();
+ if (!instance) {
+ instance = std::shared_ptr<QOhosBluetoothRemoteDeviceProxy>(
+ new QOhosBluetoothRemoteDeviceProxy());
+ weakInstance = instance;
+ }
+
+ return instance;
+ }
+
+ std::optional<QOhosBluetoothRemoteDeviceProxy::BondState> QOhosBluetoothRemoteDeviceProxy::tryGetPairState(
+ const QString &deviceId)
+ {
+ if (!checkAccessBluetoothPermissionGranted(Q_FUNC_INFO))
+ return std::nullopt;
+
+ return QOhosJsThreadGateway::eval(
+ [&](QOhosJsState &jsState) {
+ return readPairState(jsState, deviceId.toStdString());
+ },
+ Q_FUNC_INFO);
+ }
+
+ bool QOhosBluetoothRemoteDeviceProxy::pairDevice(const QString &deviceId)
+ {
+ if (!checkAccessBluetoothPermissionGranted(Q_FUNC_INFO)) {
+ Q_EMIT missingPermission();
+ return false;
+ }
+
+ if (!ensureBondStateChangeConsumerRegistered()) {
+ qCCritical(
+ QT_BT_OHOS,
+ "%s: bond state change consumer not registered. Pairing result will not be reported.",
+ Q_FUNC_INFO);
+ }
+
+ auto selfRef = QtOhos::makeQThreadSafeRef(this);
+ const auto optErrorCode = QOhosJsThreadGateway::eval(
+ [&](QOhosJsState &jsState) -> std::optional<QOhosBluetoothErrorCode> {
+ try {
+ jsState.evalToPromiseOrRejectOnThrow(
+ "@ohos.bluetooth.connection.pairDevice(*)", {deviceId.toStdString()})
+ .onCatch(
+ [selfRef, pairedDeviceId = deviceId.toStdString()](
+ const QOhosCallbackInfo &cbInfo) {
+ QtOhos::logJsCallbackError(cbInfo, "Got error from pairDevice()");
+ selfRef.visitInQtThreadIfAlive(
+ [pairedDeviceId](auto &self) {
+ Q_EMIT self.pairDeviceFailed(QString::fromStdString(pairedDeviceId));
+ });
+ });
+ return std::nullopt;
+ } catch (const Napi::Error &error) {
+ return tryGetKnownErrorCode(error.Value(), Q_FUNC_INFO);
+ }
+ },
+ Q_FUNC_INFO);
+
+ if (!optErrorCode)
+ return true;
+
+ qCWarning(
+ QT_BT_OHOS, "%s: cannot start pairing with the device %ls, error code: %u", Q_FUNC_INFO,
+ qUtf16Printable(deviceId), qToUnderlying(*optErrorCode));
+
+ return false;
+ }
+
+ }
+
+ QT_END_NAMESPACE
+
+ #include "moc_qohosbluetoothremotedevice_p.cpp"