/* * 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 #include #include #include #include #include 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 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(vendorId), aName.c_str(), static_cast(productId), aVersion.c_str(), convert_to_cpp(env, supportedClusters), manager); return static_cast(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(vendorId), aName.c_str(), static_cast(productId), aVersion.c_str(), convert_to_cpp(env, supportedClusters), static_cast(endpointId), manager); return static_cast(epId); } JNI_METHOD(jint, removeContentApp) (JNIEnv *, jobject, jint endpointId) { chip::DeviceLayer::StackLock lock; EndpointId epId = RemoveContentApp(static_cast(endpointId)); return static_cast(epId); } JNI_METHOD(void, reportAttributeChange) (JNIEnv *, jobject, jint endpointId, jint clusterId, jint attributeId) { chip::DeviceLayer::StackLock lock; ReportAttributeChange(static_cast(endpointId), static_cast(clusterId), static_cast(attributeId)); } JNI_METHOD(void, addSelfVendorAsAdmin) (JNIEnv *, jobject, jint endpointId, jint clusterId, jint attributeId) { AddSelfVendorAsAdmin(); } std::vector consume_and_convert_to_cpp(JNIEnv * env, jobject intArrayObject) { std::vector uintVector; if (intArrayObject != nullptr) { jsize length = env->GetArrayLength(static_cast(intArrayObject)); jint * elements = env->GetIntArrayElements(static_cast(intArrayObject), nullptr); if (elements != nullptr) { // OBS: Implicit type ambiguation from int32_t to uint32_t uintVector.assign(elements, elements + length); env->ReleaseIntArrayElements(static_cast(intArrayObject), elements, JNI_ABORT); } env->DeleteLocalRef(intArrayObject); } return uintVector; } std::vector 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 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; }