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 "qohosbluetoothaccess_p.h"
++
++ #include <QtBluetooth/private/qohosbluetoothcommon_p.h>
++
++ #include <QtCore/qloggingcategory.h>
++ #include <QtCore/private/qnapi_p.h>
++ #include <QtCore/private/qohoscommon_p.h>
++ #include <QtCore/private/qohosjstools_p.h>
++ #include <QtCore/private/qohoslogger_p.h>
++
++ #include <memory>
++ #include <optional>
++
++ QT_BEGIN_NAMESPACE
++
++ Q_DECLARE_LOGGING_CATEGORY(QT_BT_OHOS)
++
++ namespace QtOhosBluetooth {
++
++ namespace {
++
++ using BluetoothState = QOhosBluetoothAccessProxy::BluetoothState;
++
++ std::shared_ptr<void> registerBluetoothStateChangeConsumer(
++ QOhosJsState &jsState, QOhosConsumer<std::optional<BluetoothState>> stateChangeConsumer)
++ {
++ return registerQOhosOnOffMethodsBasedEventHandler(
++ jsState.eval<QNapi::Object>("@ohos.bluetooth.access"), "stateChange",
++ [stateChangeConsumer = std::move(stateChangeConsumer)](const QOhosCallbackInfo &cbInfo) {
++ auto ohosBluetoothState = cbInfo.getFirstArg<QNapi::Number>(Q_FUNC_INFO);
++ stateChangeConsumer(
++ cbInfo.jsState().tryMapOhosEnumFromJs<BluetoothState>(ohosBluetoothState));
++ },
++ {
++ .optOnCallExceptionHandler = [](const Napi::Error &error) {
++ if (const auto optErrorCode = tryGetKnownErrorCode(error.Value(), Q_FUNC_INFO)) {
++ qOhosPrintfWarning(
++ "%s: cannot register the bluetooth state change consumer, error code: %u",
++ Q_FUNC_INFO, qToUnderlying(*optErrorCode));
++ }
++ },
++ });
++ }
++
++ QOhosSupplier<std::optional<BluetoothState>> makeBluetoothStateSupplier(
++ QOhosConsumer<std::optional<BluetoothState>> bluetoothStateChangeConsumer)
++ {
++ bool stateChangeEventRegistered = false;
++
++ auto cachedBluetoothStateSupplier = makeQOhosDataSource<std::optional<BluetoothState>>(
++ readBluetoothState,
++ [&](QOhosJsState &jsState, QOhosConsumer<std::optional<BluetoothState>> stateChangeConsumer) {
++ auto stateChangeConsumerHandle =
++ registerBluetoothStateChangeConsumer(jsState, std::move(stateChangeConsumer));
++ stateChangeEventRegistered = stateChangeConsumerHandle != nullptr;
++
++ return stateChangeConsumerHandle;
++ },
++ std::move(bluetoothStateChangeConsumer),
++ QtOhos::invokeInQtThread,
++ Q_FUNC_INFO);
++
++ return [stateChangeEventRegistered,
++ cachedBluetoothStateSupplier = std::move(cachedBluetoothStateSupplier)]() {
++ return stateChangeEventRegistered
++ ? cachedBluetoothStateSupplier()
++ : QOhosJsThreadGateway::eval(readBluetoothState, Q_FUNC_INFO);
++ };
++ }
++
++ }
++
++ QOhosBluetoothAccessProxy::QOhosBluetoothAccessProxy()
++ {
++ m_ohosBluetoothStateSupplier = makeBluetoothStateSupplier(
++ [this](std::optional<BluetoothState> optBluetoothState) {
++ if (optBluetoothState)
++ Q_EMIT stateChanged(*optBluetoothState);
++ });
++ }
++
++ std::shared_ptr<QOhosBluetoothAccessProxy> QOhosBluetoothAccessProxy::instance()
++ {
++ static auto instance = std::shared_ptr<QOhosBluetoothAccessProxy>(new QOhosBluetoothAccessProxy());
++ return instance;
++ }
++
++ std::optional<QOhosBluetoothAccessProxy::BluetoothState> QOhosBluetoothAccessProxy::tryGetBluetoothState() const
++ {
++ return m_ohosBluetoothStateSupplier();
++ }
++
++ std::optional<QOhosBluetoothErrorCode> QOhosBluetoothAccessProxy::trySetBluetoothEnabled(bool enabled)
++ {
++ if (!checkAccessBluetoothPermissionGranted(Q_FUNC_INFO)) {
++ Q_EMIT missingPermission();
++ return QOhosBluetoothErrorCode::PermissionDenied;
++ }
++
++ auto selfRef = QtOhos::makeQThreadSafeRef(this);
++ const auto optErrorCode = QOhosJsThreadGateway::eval(
++ [&](QOhosJsState &jsState) -> std::optional<QOhosBluetoothErrorCode> {
++ try {
++ jsState.evalToPromiseOrRejectOnThrow(
++ enabled ? "@ohos.bluetooth.access.enableBluetoothAsync()"
++ : "@ohos.bluetooth.access.disableBluetoothAsync()")
++ .onCatch(
++ [selfRef](const QOhosCallbackInfo &cbInfo) {
++ const auto errorValue = cbInfo.getFirstArg<QNapi::Value>(Q_FUNC_INFO);
++ const auto errorCode =
++ tryGetKnownErrorCode(errorValue, Q_FUNC_INFO)
++ .value_or(QOhosBluetoothErrorCode::OperationFailed);
++ qOhosPrintfWarning(
++ "%s: the bluetooth switch request was rejected, error code: %u",
++ Q_FUNC_INFO, qToUnderlying(errorCode));
++ selfRef.visitInQtThreadIfAlive(
++ [errorCode](auto &self) {
++ Q_EMIT self.setBluetoothEnabledFailed(errorCode);
++ });
++ });
++ return std::nullopt;
++ } catch (const Napi::Error &error) {
++ return tryGetKnownErrorCode(error.Value(), Q_FUNC_INFO);
++ }
++ },
++ Q_FUNC_INFO);
++
++ if (!optErrorCode)
++ return std::nullopt;
++
++ if (*optErrorCode == QOhosBluetoothErrorCode::PermissionDenied) {
++ qCWarning(
++ QT_BT_OHOS, "%s: no permission to set the bluetooth enabled state %d", Q_FUNC_INFO,
++ enabled);
++ Q_EMIT missingPermission();
++ return optErrorCode;
++ }
++
++ qCWarning(
++ QT_BT_OHOS, "%s: cannot set the bluetooth enabled state %d, error code: %u", Q_FUNC_INFO,
++ enabled, qToUnderlying(*optErrorCode));
++
++ return optErrorCode;
++ }
++
++ }
++
++ QT_END_NAMESPACE
++
++ #include "moc_qohosbluetoothaccess_p.cpp"