blob: 52905cf0ba130b54bb3fa467b8de002326dd2652 [file] [log] [blame]
/*
* Copyright (c) 2021 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 "AppImpl.h"
#include <app/app-platform/ContentApp.h>
#include <jni.h>
#include <lib/core/CHIPError.h>
#include <lib/support/CHIPJNIError.h>
#include <lib/support/JniReferences.h>
#include <lib/support/JniTypeWrappers.h>
using namespace chip;
using namespace chip::app;
using namespace chip::AppPlatform;
using namespace chip::Credentials;
/*
* This file provides the native implementation of methods of the
* com.matter.tv.server.tvapp.AppPlatform class.
*/
// Forward declaration
std::vector<ContentApp::SupportedCluster> convert_to_cpp(JNIEnv * env, jobject supportedClusters);
#define JNI_METHOD(RETURN, METHOD_NAME) \
extern "C" JNIEXPORT RETURN JNICALL Java_com_matter_tv_server_tvapp_AppPlatform_##METHOD_NAME
JNI_METHOD(void, nativeInit)(JNIEnv *, jobject app, jobject contentAppEndpointManager)
{
chip::DeviceLayer::StackLock lock;
InitVideoPlayerPlatform(contentAppEndpointManager);
}
JNI_METHOD(jint, addContentApp)
(JNIEnv *, jobject, jstring vendorName, jint vendorId, jstring appName, jint productId, jstring appVersion,
jobject supportedClusters, jobject manager)
{
chip::DeviceLayer::StackLock lock;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
JniUtfString vName(env, vendorName);
JniUtfString aName(env, appName);
JniUtfString aVersion(env, appVersion);
EndpointId epId = AddContentApp(vName.c_str(), static_cast<uint16_t>(vendorId), aName.c_str(), static_cast<uint16_t>(productId),
aVersion.c_str(), convert_to_cpp(env, supportedClusters), manager);
return static_cast<uint16_t>(epId);
}
JNI_METHOD(jint, addContentAppAtEndpoint)
(JNIEnv *, jobject, jstring vendorName, jint vendorId, jstring appName, jint productId, jstring appVersion,
jobject supportedClusters, jint endpointId, jobject manager)
{
chip::DeviceLayer::StackLock lock;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
JniUtfString vName(env, vendorName);
JniUtfString aName(env, appName);
JniUtfString aVersion(env, appVersion);
EndpointId epId =
AddContentApp(vName.c_str(), static_cast<uint16_t>(vendorId), aName.c_str(), static_cast<uint16_t>(productId),
aVersion.c_str(), convert_to_cpp(env, supportedClusters), static_cast<EndpointId>(endpointId), manager);
return static_cast<uint16_t>(epId);
}
JNI_METHOD(jint, removeContentApp)
(JNIEnv *, jobject, jint endpointId)
{
chip::DeviceLayer::StackLock lock;
EndpointId epId = RemoveContentApp(static_cast<EndpointId>(endpointId));
return static_cast<uint16_t>(epId);
}
JNI_METHOD(void, reportAttributeChange)
(JNIEnv *, jobject, jint endpointId, jint clusterId, jint attributeId)
{
chip::DeviceLayer::StackLock lock;
ReportAttributeChange(static_cast<EndpointId>(endpointId), static_cast<chip::ClusterId>(clusterId),
static_cast<chip::AttributeId>(attributeId));
}
JNI_METHOD(void, addSelfVendorAsAdmin)
(JNIEnv *, jobject, jint endpointId, jint clusterId, jint attributeId)
{
AddSelfVendorAsAdmin();
}
std::vector<uint32_t> consume_and_convert_to_cpp(JNIEnv * env, jobject intArrayObject)
{
std::vector<uint32_t> uintVector;
if (intArrayObject != nullptr)
{
jsize length = env->GetArrayLength(static_cast<jintArray>(intArrayObject));
jint * elements = env->GetIntArrayElements(static_cast<jintArray>(intArrayObject), nullptr);
if (elements != nullptr)
{
// OBS: Implicit type ambiguation from int32_t to uint32_t
uintVector.assign(elements, elements + length);
env->ReleaseIntArrayElements(static_cast<jintArray>(intArrayObject), elements, JNI_ABORT);
}
env->DeleteLocalRef(intArrayObject);
}
return uintVector;
}
std::vector<ContentApp::SupportedCluster> convert_to_cpp(JNIEnv * env, jobject supportedClustersObject)
{
if (supportedClustersObject == nullptr || env == nullptr)
{
return {};
}
// Find Java classes. WARNING: Reflection
jclass collectionClass = env->FindClass("java/util/Collection");
jclass iteratorClass = env->FindClass("java/util/Iterator");
jclass clusterClass = env->FindClass("com/matter/tv/server/tvapp/ContentAppSupportedCluster");
if (collectionClass == nullptr || iteratorClass == nullptr || clusterClass == nullptr)
{
return {};
}
// Find Java methods. WARNING: Reflection
jmethodID iteratorMethod = env->GetMethodID(collectionClass, "iterator", "()Ljava/util/Iterator;");
jmethodID hasNextMethod = env->GetMethodID(iteratorClass, "hasNext", "()Z");
jmethodID nextMethod = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
if (iteratorMethod == nullptr || hasNextMethod == nullptr || nextMethod == nullptr)
{
return {};
}
// Find Java SupportedCluster fields. WARNING: Reflection
jfieldID clusterIdentifierField = env->GetFieldID(clusterClass, "clusterIdentifier", "I");
jfieldID featuresField = env->GetFieldID(clusterClass, "features", "I");
jfieldID optionalCommandIdentifiersField = env->GetFieldID(clusterClass, "optionalCommandIdentifiers", "[I");
jfieldID optionalAttributesIdentifiersField = env->GetFieldID(clusterClass, "optionalAttributesIdentifiers", "[I");
if (clusterIdentifierField == nullptr || featuresField == nullptr || optionalCommandIdentifiersField == nullptr ||
optionalAttributesIdentifiersField == nullptr)
{
return {};
}
// Find Set Iterator Object
jobject iteratorObject = env->CallObjectMethod(supportedClustersObject, iteratorMethod);
if (iteratorObject == nullptr)
{
return {};
}
// Iterate over the Java Collection and convert each SupportedCluster
std::vector<SupportedCluster> supportedClusters;
while (env->CallBooleanMethod(iteratorObject, hasNextMethod))
{
jobject clusterObject = env->CallObjectMethod(iteratorObject, nextMethod);
if (clusterObject != nullptr)
{
jint clusterIdentifier = env->GetIntField(clusterObject, clusterIdentifierField);
jint features = env->GetIntField(clusterObject, featuresField);
jobject commandIdsObject = env->GetObjectField(clusterObject, optionalCommandIdentifiersField);
jobject attributeIdsObject = env->GetObjectField(clusterObject, optionalAttributesIdentifiersField);
// OBS: Implicit type ambiguation from int32_t to uint32_t
supportedClusters.emplace_back(clusterIdentifier, features, consume_and_convert_to_cpp(env, commandIdsObject),
consume_and_convert_to_cpp(env, attributeIdsObject));
env->DeleteLocalRef(clusterObject);
}
}
env->DeleteLocalRef(iteratorObject);
return supportedClusters;
}