/* * Copyright (c) 2023 Project CHIP Authors * All rights reserved. * * 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. * */ #include "DeviceApp-JNI.h" #include "AppImpl.h" #include "JNIDACProvider.h" #include "ColorControlManager.h" #include "DoorLockManager.h" #include "OnOffManager.h" #include "PowerSourceManager.h" #include "credentials/DeviceAttestationCredsProvider.h" #include #include #include #include #include #include #include #include #include using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::AppPlatform; using namespace chip::Credentials; using namespace chip::DeviceLayer; #define JNI_METHOD(RETURN, METHOD_NAME) \ extern "C" JNIEXPORT RETURN JNICALL Java_com_matter_virtual_device_app_DeviceApp_##METHOD_NAME #define DEVICE_VERSION_DEFAULT 1 EmberAfDeviceType gDeviceTypeIds[] = { { 0, DEVICE_VERSION_DEFAULT } }; DeviceAppJNI DeviceAppJNI::sInstance; void DeviceAppJNI::InitializeWithObjects(jobject app) { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for DeviceAppJNI")); VerifyOrReturn(mDeviceAppObject.Init(app) == CHIP_NO_ERROR, ChipLogError(Zcl, "Failed to init mDeviceAppObject")); jclass managerClass = env->GetObjectClass(app); VerifyOrReturn(managerClass != nullptr, ChipLogError(Zcl, "Failed to get DeviceAppJNI Java class")); mPostClusterInitMethod = env->GetMethodID(managerClass, "postClusterInit", "(JI)V"); if (mPostClusterInitMethod == nullptr) { ChipLogError(Zcl, "Failed to access DeviceApp 'postClusterInit' method"); env->ExceptionClear(); } mPostEventMethod = env->GetMethodID(managerClass, "postEvent", "(J)V"); if (mPostEventMethod == nullptr) { ChipLogError(Zcl, "Failed to access DeviceApp 'postEvent' method"); env->ExceptionClear(); } } void DeviceAppJNI::PostClusterInit(int clusterId, int endpoint) { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for DeviceAppJNI::PostClusterInit")); VerifyOrReturn(mDeviceAppObject.HasValidObjectRef(), ChipLogError(Zcl, "DeviceAppJNI::mDeviceAppObject null")); VerifyOrReturn(mPostClusterInitMethod != nullptr, ChipLogError(Zcl, "DeviceAppJNI::mPostClusterInitMethod null")); env->CallVoidMethod(mDeviceAppObject.ObjectRef(), mPostClusterInitMethod, static_cast(clusterId), static_cast(endpoint)); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Failed to call DeviceAppJNI 'postClusterInit' method"); env->ExceptionClear(); } } void DeviceAppJNI::PostEvent(int event) { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for DeviceAppJNI::PostEvent")); VerifyOrReturn(mDeviceAppObject.HasValidObjectRef(), ChipLogError(Zcl, "DeviceAppJNI::mDeviceAppObject null")); VerifyOrReturn(mPostEventMethod != nullptr, ChipLogError(Zcl, "DeviceAppJNI::mPostEventMethod null")); env->CallVoidMethod(mDeviceAppObject.ObjectRef(), mPostEventMethod, static_cast(event)); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Failed to call DeviceAppJNI 'postEventMethod' method"); env->ExceptionClear(); } } jint JNI_OnLoad(JavaVM * jvm, void * reserved) { return AndroidAppServerJNI_OnLoad(jvm, reserved); } void JNI_OnUnload(JavaVM * jvm, void * reserved) { return AndroidAppServerJNI_OnUnload(jvm, reserved); } JNI_METHOD(void, nativeInit)(JNIEnv *, jobject app) { DeviceAppJNIMgr().InitializeWithObjects(app); } JNI_METHOD(void, preServerInit)(JNIEnv *, jobject app) { chip::DeviceLayer::StackLock lock; ChipLogProgress(Zcl, "DeviceAppJNI::preServerInit"); PreServerInit(); } JNI_METHOD(void, postServerInit)(JNIEnv *, jobject app, jint deviceTypeId) { chip::DeviceLayer::StackLock lock; ChipLogProgress(Zcl, "DeviceAppJNI::postServerInit"); gDeviceTypeIds[0].deviceId = static_cast(deviceTypeId); emberAfSetDeviceTypeList(1, Span(gDeviceTypeIds)); } JNI_METHOD(void, setDACProvider)(JNIEnv *, jobject, jobject provider) { if (!chip::Credentials::IsDeviceAttestationCredentialsProviderSet()) { chip::Credentials::SetDeviceAttestationCredentialsProvider(chip::Credentials::Examples::GetExampleDACProvider()); } } /* * On Off Manager */ JNI_METHOD(void, setOnOffManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { OnOffManager::NewManager(endpoint, manager); } JNI_METHOD(jboolean, setOnOff)(JNIEnv *, jobject, jint endpoint, jboolean value) { return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { OnOffManager::SetOnOff(endpoint, value); }) == CHIP_NO_ERROR; } /* * Color Control Manager */ JNI_METHOD(void, setColorControlManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { ColorControlManager::NewManager(endpoint, manager); } /* * Door Lock Manager */ JNI_METHOD(void, setDoorLockManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { DoorLockManager::NewManager(endpoint, manager); } JNI_METHOD(jboolean, setLockType)(JNIEnv *, jobject, jint endpoint, jint value) { return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { DoorLockManager::SetLockType(endpoint, value); }) == CHIP_NO_ERROR; } JNI_METHOD(jboolean, setLockState)(JNIEnv *, jobject, jint endpoint, jint value) { return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { DoorLockManager::SetLockState(endpoint, value); }) == CHIP_NO_ERROR; } JNI_METHOD(jboolean, setActuatorEnabled)(JNIEnv *, jobject, jint endpoint, jboolean value) { return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { DoorLockManager::SetActuatorEnabled(endpoint, value); }) == CHIP_NO_ERROR; } JNI_METHOD(jboolean, setAutoRelockTime)(JNIEnv *, jobject, jint endpoint, jint value) { return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { DoorLockManager::SetAutoRelockTime(endpoint, value); }) == CHIP_NO_ERROR; } JNI_METHOD(jboolean, setOperatingMode)(JNIEnv *, jobject, jint endpoint, jint value) { return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { DoorLockManager::SetOperatingMode(endpoint, value); }) == CHIP_NO_ERROR; } JNI_METHOD(jboolean, setSupportedOperatingModes)(JNIEnv *, jobject, jint endpoint, jint value) { return DeviceLayer::SystemLayer().ScheduleLambda( [endpoint, value] { DoorLockManager::SetSupportedOperatingModes(endpoint, value); }) == CHIP_NO_ERROR; } JNI_METHOD(jboolean, sendLockAlarmEvent)(JNIEnv *, jobject, jint endpoint) { return DeviceLayer::SystemLayer().ScheduleLambda([endpoint] { DoorLockManager::SendLockAlarmEvent(endpoint); }) == CHIP_NO_ERROR; } /* * Power Source Manager */ JNI_METHOD(void, setPowerSourceManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { PowerSourceManager::NewManager(endpoint, manager); } JNI_METHOD(jboolean, setBatPercentRemaining)(JNIEnv *, jobject, jint endpoint, jint value) { return DeviceLayer::SystemLayer().ScheduleLambda( [endpoint, value] { PowerSourceManager::SetBatPercentRemaining(endpoint, value); }) == CHIP_NO_ERROR; }