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 "qohosbluetoothcommon_p.h"
++
++ #include <QtBluetooth/private/qohosbluetoothenums_p.h>
++
++ #include <QtCore/qcoreapplication.h>
++ #include <QtCore/qloggingcategory.h>
++ #include <QtCore/qpermissions.h>
++ #include <QtCore/qstring.h>
++ #include <QtCore/private/qnapi_p.h>
++ #include <QtCore/private/qohoscommon_p.h>
++ #include <QtCore/private/qohoslogger_p.h>
++
++ #include <optional>
++
++ QT_BEGIN_NAMESPACE
++
++ Q_DECLARE_LOGGING_CATEGORY(QT_BT_OHOS)
++
++ namespace QtOhosBluetooth {
++
++ namespace {
++
++ std::optional<std::uint32_t> tryGetCodeFromJsBusinessError(const QNapi::Value &errorValue)
++ {
++ if (!errorValue.IsObject())
++ return std::nullopt;
++
++ auto errorObject = QNapi::checkedCast<QNapi::Object>(errorValue);
++ auto errorCodeValue = QNapi::getOptionalPropOrEmpty<QNapi::Value>(errorObject, "code");
++
++ if (errorCodeValue.IsNumber())
++ return QNapi::checkedCast<QNapi::Number>(errorCodeValue).Uint32Value();
++
++ if (errorCodeValue.IsString()) {
++ const auto codeText =
++ QString::fromStdString(QNapi::checkedCast<QNapi::String>(errorCodeValue));
++ bool parsed = false;
++ const auto code = codeText.toUInt(&parsed);
++ if (parsed)
++ return code;
++
++ qOhosPrintfWarning(
++ "%s: non-numeric 'code' property in JS business error object: %s", Q_FUNC_INFO,
++ qUtf8Printable(codeText));
++ }
++
++ return std::nullopt;
++ }
++
++ }
++
++ std::optional<QOhosBluetoothErrorCode> tryGetKnownErrorCode(
++ const QNapi::Value &errorValue, const char *callerContextName)
++ {
++ const auto optErrorCodeValue = tryGetCodeFromJsBusinessError(errorValue);
++ if (!optErrorCodeValue) {
++ qOhosPrintfError(
++ "%s: no numeric 'code' property in JS business error object", callerContextName);
++ return std::nullopt;
++ }
++
++ const auto errorCode = static_cast<QOhosBluetoothErrorCode>(*optErrorCodeValue);
++ switch (errorCode) {
++ case QOhosBluetoothErrorCode::PermissionDenied:
++ case QOhosBluetoothErrorCode::InvalidParameter:
++ case QOhosBluetoothErrorCode::CapabilityNotSupported:
++ case QOhosBluetoothErrorCode::ServiceStopped:
++ case QOhosBluetoothErrorCode::BluetoothDisabled:
++ case QOhosBluetoothErrorCode::ProfileNotSupported:
++ case QOhosBluetoothErrorCode::UserDidNotRespond:
++ case QOhosBluetoothErrorCode::UserRefused:
++ case QOhosBluetoothErrorCode::OperationFailed:
++ case QOhosBluetoothErrorCode::InputOutput:
++ return errorCode;
++ }
++
++ qOhosPrintfError(
++ "%s: unexpected JS business error %u", callerContextName, *optErrorCodeValue);
++ return std::nullopt;
++ }
++
++ bool checkAccessBluetoothPermissionGranted(const char *callerContextName)
++ {
++ if (!qApp) {
++ qOhosPrintfWarning("%s: no application instance to check the permission on", callerContextName);
++ return false;
++ }
++
++ if (qApp->checkPermission(QBluetoothPermission{}) == Qt::PermissionStatus::Granted)
++ return true;
++
++ qCWarning(QT_BT_OHOS, "%s: access bluetooth permission not granted", callerContextName);
++ return false;
++ }
++
++ std::optional<QtOhosBluetooth::enums::ohos::bluetooth::access::BluetoothState> readBluetoothState(
++ QOhosJsState &jsState)
++ {
++ using QtOhosBluetooth::enums::ohos::bluetooth::access::BluetoothState;
++
++ try {
++ return jsState.tryMapOhosEnumFromJs<BluetoothState>(
++ jsState.eval<QNapi::Number>("@ohos.bluetooth.access.getState()"));
++ } catch (const Napi::Error &error) {
++ if (const auto optErrorCode = tryGetKnownErrorCode(error.Value(), Q_FUNC_INFO)) {
++ qOhosPrintfWarning(
++ "%s: cannot read the bluetooth state, error code: %u", Q_FUNC_INFO,
++ qToUnderlying(*optErrorCode));
++ }
++ return std::nullopt;
++ }
++ }
++
++ bool isBluetoothEnabled(QOhosJsState &jsState)
++ {
++ using QtOhosBluetooth::enums::ohos::bluetooth::access::BluetoothState;
++
++ return readBluetoothState(jsState) == BluetoothState::STATE_ON;
++ }
++
++ }
++
++ QT_END_NAMESPACE