/*
 *
 *    Copyright (c) 2020-2021 Project CHIP Authors
 *    Copyright (c) 2018 Nest Labs, Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/**
 *    @file
 *          Provides an implementation of the BLEManager singleton object
 *          for Linux platforms.
 */
#include <platform/internal/CHIPDeviceLayerInternal.h>

#include <ble/Ble.h>
#include <lib/support/CHIPJNIError.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/JniReferences.h>
#include <lib/support/SafeInt.h>
#include <platform/internal/BLEManager.h>

#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE

using namespace chip;
using namespace ::nl;
using namespace ::chip::Ble;

namespace chip {
namespace DeviceLayer {
namespace Internal {

namespace {} // namespace

BLEManagerImpl BLEManagerImpl::sInstance;

CHIP_ERROR BLEManagerImpl::ConfigureBle(uint32_t aAdapterId, bool aIsCentral)
{
    return CHIP_ERROR_NOT_IMPLEMENTED;
}

void BLEManagerImpl::InitializeWithObject(jobject manager)
{
    JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
    VerifyOrReturn(env != nullptr, ChipLogError(DeviceLayer, "Failed to GetEnvForCurrentThread for BLEManager"));

    VerifyOrReturn(mBLEManagerObject.Init(manager) == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "Failed to Init BLEManager"));

    jclass BLEManagerClass = env->GetObjectClass(manager);
    VerifyOrReturn(BLEManagerClass != nullptr, ChipLogError(DeviceLayer, "Failed to get BLEManager Java class"));

    mInitMethod = env->GetMethodID(BLEManagerClass, "init", "()I");
    if (mInitMethod == nullptr)
    {
        ChipLogError(DeviceLayer, "Failed to access BLEManager 'init' method");
        env->ExceptionClear();
    }

    mSetFlagMethod = env->GetMethodID(BLEManagerClass, "setFlag", "(JZ)J");
    if (mSetFlagMethod == nullptr)
    {
        ChipLogError(DeviceLayer, "Failed to access BLEManager 'setFlag' method");
        env->ExceptionClear();
    }

    mHasFlagMethod = env->GetMethodID(BLEManagerClass, "hasFlag", "(J)Z");
    if (mHasFlagMethod == nullptr)
    {
        ChipLogError(DeviceLayer, "Failed to access BLEManager 'hasFlag' method");
        env->ExceptionClear();
    }

    mOnSubscribeCharacteristicMethod = env->GetMethodID(BLEManagerClass, "onSubscribeCharacteristic", "(I[B[B)Z");
    if (mOnSubscribeCharacteristicMethod == nullptr)
    {
        ChipLogError(DeviceLayer, "Failed to access BLEManager 'onSubscribeCharacteristic' method");
        env->ExceptionClear();
    }

    mOnUnsubscribeCharacteristicMethod = env->GetMethodID(BLEManagerClass, "onUnsubscribeCharacteristic", "(I[B[B)Z");
    if (mOnUnsubscribeCharacteristicMethod == nullptr)
    {
        ChipLogError(DeviceLayer, "Failed to access BLEManager 'onUnsubscribeCharacteristic' method");
        env->ExceptionClear();
    }

    mOnCloseConnectionMethod = env->GetMethodID(BLEManagerClass, "onCloseConnection", "(I)Z");
    if (mOnCloseConnectionMethod == nullptr)
    {
        ChipLogError(DeviceLayer, "Failed to access BLEManager 'onCloseConnection' method");
        env->ExceptionClear();
    }

    mOnGetMTUMethod = env->GetMethodID(BLEManagerClass, "onGetMTU", "(I)I");
    if (mOnGetMTUMethod == nullptr)
    {
        ChipLogError(DeviceLayer, "Failed to access BLEManager 'onGetMTU' method");
        env->ExceptionClear();
    }

    mOnSendWriteRequestMethod = env->GetMethodID(BLEManagerClass, "onSendWriteRequest", "(I[B[B[B)Z");
    if (mOnSendWriteRequestMethod == nullptr)
    {
        ChipLogError(DeviceLayer, "Failed to access BLEManager 'onSendWriteRequest' method");
        env->ExceptionClear();
    }

    mOnNotifyChipConnectionClosedMethod = env->GetMethodID(BLEManagerClass, "onNotifyChipConnectionClosed", "(I)V");
    if (mOnNotifyChipConnectionClosedMethod == nullptr)
    {
        ChipLogError(DeviceLayer, "Failed to access BLEManager 'onNotifyChipConnectionClosed' method");
        env->ExceptionClear();
    }

    mOnNewConnectionMethod = env->GetMethodID(BLEManagerClass, "onNewConnection", "(IZJJ)V");
    if (mOnNewConnectionMethod == nullptr)
    {
        ChipLogError(DeviceLayer, "Failed to access BLEManager 'onNewConnection' method");
        env->ExceptionClear();
    }
}

// ===== start impl of BLEManager internal interface, ref BLEManager.h

CHIP_ERROR BLEManagerImpl::_Init()
{
    CHIP_ERROR err;

    // SystemLayer is defined in platform::Globals.cpp
    err = BleLayer::Init(this, this, this, &DeviceLayer::SystemLayer());
    ReturnLogErrorOnFailure(err);

    VerifyOrReturnLogError(mBLEManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE);
    VerifyOrReturnLogError(mInitMethod != nullptr, CHIP_ERROR_INCORRECT_STATE);

    JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
    VerifyOrReturnLogError(env != nullptr, CHIP_JNI_ERROR_NO_ENV);

    jint ret = env->CallIntMethod(mBLEManagerObject.ObjectRef(), mInitMethod);
    if (env->ExceptionCheck())
    {
        ChipLogError(DeviceLayer, "Java exception in BLEManager::init");
        env->ExceptionDescribe();
        return CHIP_JNI_ERROR_EXCEPTION_THROWN;
    }
    VerifyOrReturnLogError(ret == 0, CHIP_JNI_ERROR_JAVA_ERROR);

    return err;
}

bool BLEManagerImpl::_IsAdvertisingEnabled()
{
    bool has       = false;
    CHIP_ERROR err = HasFlag(Flags::kAdvertisingEnabled, has);

    VerifyOrReturnError(err == CHIP_NO_ERROR, false);
    return has;
}

CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val)
{
    return SetFlag(Flags::kAdvertisingEnabled, val);
}

bool BLEManagerImpl::_IsAdvertising()
{
    bool has       = false;
    CHIP_ERROR err = HasFlag(Flags::kAdvertising, has);

    VerifyOrReturnError(err == CHIP_NO_ERROR, false);
    return has;
}

CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode)
{
    ChipLogDetail(DeviceLayer, "%s, %u", __FUNCTION__, static_cast<uint8_t>(mode));
    return CHIP_ERROR_NOT_IMPLEMENTED;
}

CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize)
{
    ChipLogDetail(DeviceLayer, "%s, %s", __FUNCTION__, buf);
    return CHIP_ERROR_NOT_IMPLEMENTED;
}

CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName)
{
    ChipLogDetail(DeviceLayer, "%s, %s", __FUNCTION__, deviceName);
    return CHIP_ERROR_NOT_IMPLEMENTED;
}

uint16_t BLEManagerImpl::_NumConnections()
{
    uint16_t numCons = 0;
    return numCons;
}

void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
{
    ChipLogDetail(DeviceLayer, "%s", __FUNCTION__);
}

BleLayer * BLEManagerImpl::_GetBleLayer()
{
    return this;
}
// ===== end impl of BLEManager internal interface

// ===== start implement virtual methods on BlePlatformDelegate.

bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
    chip::DeviceLayer::StackUnlock unlock;
    CHIP_ERROR err = CHIP_NO_ERROR;
    JNIEnv * env   = JniReferences::GetInstance().GetEnvForCurrentThread();
    jbyteArray svcIdObj;
    jbyteArray charIdObj;
    intptr_t tmpConnObj;
    bool rc = false;

    ChipLogProgress(DeviceLayer, "Received SubscribeCharacteristic");

    VerifyOrExit(mBLEManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mOnSubscribeCharacteristicMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

    err = JniReferences::GetInstance().N2J_ByteArray(env, static_cast<const uint8_t *>(svcId->bytes), 16, svcIdObj);
    SuccessOrExit(err);

    err = JniReferences::GetInstance().N2J_ByteArray(env, static_cast<const uint8_t *>(charId->bytes), 16, charIdObj);
    SuccessOrExit(err);

    env->ExceptionClear();
    tmpConnObj = reinterpret_cast<intptr_t>(conId);
    rc         = (bool) env->CallBooleanMethod(mBLEManagerObject.ObjectRef(), mOnSubscribeCharacteristicMethod,
                                               static_cast<jint>(tmpConnObj), svcIdObj, charIdObj);
    VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);

exit:
    if (err != CHIP_NO_ERROR)
    {
        JniReferences::GetInstance().ReportError(env, err, __FUNCTION__);
        rc = false;
    }
    env->ExceptionClear();

    return rc;
}

bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
    chip::DeviceLayer::StackUnlock unlock;
    CHIP_ERROR err = CHIP_NO_ERROR;
    JNIEnv * env   = JniReferences::GetInstance().GetEnvForCurrentThread();
    jbyteArray svcIdObj;
    jbyteArray charIdObj;
    intptr_t tmpConnObj;
    bool rc = false;

    ChipLogProgress(DeviceLayer, "Received UnsubscribeCharacteristic");

    VerifyOrExit(mBLEManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mOnUnsubscribeCharacteristicMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

    err = JniReferences::GetInstance().N2J_ByteArray(env, static_cast<const uint8_t *>(svcId->bytes), 16, svcIdObj);
    SuccessOrExit(err);

    err = JniReferences::GetInstance().N2J_ByteArray(env, static_cast<const uint8_t *>(charId->bytes), 16, charIdObj);
    SuccessOrExit(err);

    env->ExceptionClear();
    tmpConnObj = reinterpret_cast<intptr_t>(conId);
    rc         = (bool) env->CallBooleanMethod(mBLEManagerObject.ObjectRef(), mOnUnsubscribeCharacteristicMethod,
                                               static_cast<jint>(tmpConnObj), svcIdObj, charIdObj);
    VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);

exit:
    if (err != CHIP_NO_ERROR)
    {
        JniReferences::GetInstance().ReportError(env, err, __FUNCTION__);
        rc = false;
    }
    env->ExceptionClear();

    return rc;
}

bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId)
{
    chip::DeviceLayer::StackUnlock unlock;
    CHIP_ERROR err = CHIP_NO_ERROR;
    JNIEnv * env   = JniReferences::GetInstance().GetEnvForCurrentThread();
    intptr_t tmpConnObj;
    bool rc = false;

    ChipLogProgress(DeviceLayer, "Received CloseConnection");

    VerifyOrExit(mBLEManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mOnCloseConnectionMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

    env->ExceptionClear();
    tmpConnObj = reinterpret_cast<intptr_t>(conId);
    rc = (bool) env->CallBooleanMethod(mBLEManagerObject.ObjectRef(), mOnCloseConnectionMethod, static_cast<jint>(tmpConnObj));
    VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);

exit:
    if (err != CHIP_NO_ERROR)
    {
        JniReferences::GetInstance().ReportError(env, err, __FUNCTION__);
        rc = false;
    }
    env->ExceptionClear();
    return rc;
}

uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const
{
    chip::DeviceLayer::StackUnlock unlock;
    CHIP_ERROR err = CHIP_NO_ERROR;
    JNIEnv * env   = JniReferences::GetInstance().GetEnvForCurrentThread();
    intptr_t tmpConnObj;
    uint16_t mtu = 0;

    ChipLogProgress(DeviceLayer, "Received GetMTU");
    VerifyOrExit(mBLEManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mOnGetMTUMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);
    ;

    env->ExceptionClear();
    tmpConnObj = reinterpret_cast<intptr_t>(conId);
    mtu        = (int16_t) env->CallIntMethod(mBLEManagerObject.ObjectRef(), mOnGetMTUMethod, static_cast<jint>(tmpConnObj));
    VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);

exit:
    if (err != CHIP_NO_ERROR)
    {
        JniReferences::GetInstance().ReportError(env, err, __FUNCTION__);
        mtu = 0;
    }
    env->ExceptionClear();

    return mtu;
}

bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
                                    chip::System::PacketBufferHandle pBuf)
{
    return false;
}

bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
                                      chip::System::PacketBufferHandle pBuf)
{
    chip::DeviceLayer::StackUnlock unlock;
    CHIP_ERROR err = CHIP_NO_ERROR;
    JNIEnv * env   = JniReferences::GetInstance().GetEnvForCurrentThread();
    jbyteArray svcIdObj;
    jbyteArray charIdObj;
    jbyteArray characteristicDataObj;
    intptr_t tmpConnObj;
    bool rc = false;

    ChipLogProgress(DeviceLayer, "Received SendWriteRequest");
    VerifyOrExit(mBLEManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mOnSendWriteRequestMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

    err = JniReferences::GetInstance().N2J_ByteArray(env, static_cast<const uint8_t *>(svcId->bytes), 16, svcIdObj);
    SuccessOrExit(err);

    err = JniReferences::GetInstance().N2J_ByteArray(env, static_cast<const uint8_t *>(charId->bytes), 16, charIdObj);
    SuccessOrExit(err);

    err = JniReferences::GetInstance().N2J_ByteArray(env, pBuf->Start(), pBuf->DataLength(), characteristicDataObj);
    SuccessOrExit(err);

    env->ExceptionClear();
    tmpConnObj = reinterpret_cast<intptr_t>(conId);
    rc = (bool) env->CallBooleanMethod(mBLEManagerObject.ObjectRef(), mOnSendWriteRequestMethod, static_cast<jint>(tmpConnObj),
                                       svcIdObj, charIdObj, characteristicDataObj);
    VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);

exit:
    if (err != CHIP_NO_ERROR)
    {
        JniReferences::GetInstance().ReportError(env, err, __FUNCTION__);
        rc = false;
    }
    env->ExceptionClear();

    return rc;
}

bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
                                     chip::System::PacketBufferHandle pBuf)
{
    ChipLogError(DeviceLayer, "SendReadRequest: Not implemented");
    return true;
}

bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext,
                                      const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId)
{
    ChipLogError(DeviceLayer, "SendReadRBluezonse: Not implemented");
    return true;
}

// ===== end implement virtual methods on BlePlatformDelegate.

// ===== start implement virtual methods on BleApplicationDelegate.

void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
{
    chip::DeviceLayer::StackUnlock unlock;
    CHIP_ERROR err = CHIP_NO_ERROR;
    JNIEnv * env   = JniReferences::GetInstance().GetEnvForCurrentThread();
    intptr_t tmpConnObj;

    ChipLogProgress(DeviceLayer, "Received NotifyChipConnectionClosed");
    VerifyOrExit(mBLEManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mOnNotifyChipConnectionClosedMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

    env->ExceptionClear();
    tmpConnObj = reinterpret_cast<intptr_t>(conId);
    env->CallVoidMethod(mBLEManagerObject.ObjectRef(), mOnNotifyChipConnectionClosedMethod, static_cast<jint>(tmpConnObj));
    VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);

exit:
    if (err != CHIP_NO_ERROR)
    {
        JniReferences::GetInstance().ReportError(env, err, __FUNCTION__);
    }
    env->ExceptionClear();
}

// ===== start implement virtual methods on BleConnectionDelegate.

void BLEManagerImpl::OnConnectSuccess(void * appState, BLE_CONNECTION_OBJECT connObj)
{
    chip::DeviceLayer::StackLock lock;
    BleConnectionDelegate::OnConnectionComplete(appState, connObj);
}

void BLEManagerImpl::OnConnectFailed(void * appState, CHIP_ERROR err)
{
    chip::DeviceLayer::StackLock lock;
    BleConnectionDelegate::OnConnectionError(appState, err);
}

void BLEManagerImpl::NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator)
{
    chip::DeviceLayer::StackUnlock unlock;
    CHIP_ERROR err = CHIP_NO_ERROR;
    JNIEnv * env   = JniReferences::GetInstance().GetEnvForCurrentThread();

    ChipLogProgress(Controller, "Received New Connection");
    VerifyOrExit(mBLEManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mOnNewConnectionMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

    env->ExceptionClear();
    // TODO: The API we have here does not handle short discriminators in any
    // sane way.  Just do what we used to do, which is pretend that a short
    // discriminator is actually a long discriminator with the low bits all 0.
    uint16_t discriminator;
    if (connDiscriminator.IsShortDiscriminator())
    {
        discriminator = static_cast<uint16_t>(connDiscriminator.GetShortValue())
            << (SetupDiscriminator::kLongBits - SetupDiscriminator::kShortBits);
    }
    else
    {
        discriminator = connDiscriminator.GetLongValue();
    }

    env->CallVoidMethod(mBLEManagerObject.ObjectRef(), mOnNewConnectionMethod, static_cast<jint>(discriminator),
                        static_cast<jboolean>(connDiscriminator.IsShortDiscriminator()), reinterpret_cast<jlong>(this),
                        reinterpret_cast<jlong>(appState));
    VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);

exit:
    if (err != CHIP_NO_ERROR)
    {
        JniReferences::GetInstance().ReportError(env, err, __FUNCTION__);
    }
    env->ExceptionClear();
}

CHIP_ERROR BLEManagerImpl::CancelConnection()
{
    return CHIP_ERROR_NOT_IMPLEMENTED;
}

// ===== end implement virtual methods on BleConnectionDelegate.

//== helpers

CHIP_ERROR BLEManagerImpl::HasFlag(BLEManagerImpl::Flags flag, bool & has)
{
    chip::DeviceLayer::StackUnlock unlock;
    jlong f = static_cast<jlong>(flag);

    VerifyOrReturnLogError(mBLEManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE);
    VerifyOrReturnLogError(mHasFlagMethod != nullptr, CHIP_ERROR_INCORRECT_STATE);

    JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
    VerifyOrReturnLogError(env != nullptr, CHIP_JNI_ERROR_NO_ENV);

    jboolean jret = env->CallBooleanMethod(mBLEManagerObject.ObjectRef(), mHasFlagMethod, f);
    if (env->ExceptionCheck())
    {
        ChipLogError(DeviceLayer, "Java exception in BLEManager::hasFlag");
        env->ExceptionDescribe();
        return CHIP_JNI_ERROR_EXCEPTION_THROWN;
    }

    has = static_cast<bool>(jret);
    return CHIP_NO_ERROR;
}

CHIP_ERROR BLEManagerImpl::SetFlag(BLEManagerImpl::Flags flag, bool isSet)
{
    chip::DeviceLayer::StackUnlock unlock;
    jlong jFlag     = static_cast<jlong>(flag);
    jboolean jIsSet = static_cast<jboolean>(isSet);

    VerifyOrReturnLogError(mBLEManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE);
    VerifyOrReturnLogError(mSetFlagMethod != nullptr, CHIP_ERROR_INCORRECT_STATE);

    JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
    VerifyOrReturnLogError(env != nullptr, CHIP_JNI_ERROR_NO_ENV);

    env->CallLongMethod(mBLEManagerObject.ObjectRef(), mSetFlagMethod, jFlag, jIsSet);
    if (env->ExceptionCheck())
    {
        ChipLogError(DeviceLayer, "Java exception in BLEManager::satFlag");
        env->ExceptionDescribe();
        return CHIP_JNI_ERROR_EXCEPTION_THROWN;
    }

    return CHIP_NO_ERROR;
}

} // namespace Internal
} // namespace DeviceLayer
} // namespace chip

#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
