/* * * 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 "ContentLauncherManager.h" #include "TvApp-JNI.h" #include #include #include #include #include #include #include using namespace std; using namespace chip; using namespace chip::app::DataModel; using namespace chip::app::Clusters::ContentLauncher; void emberAfContentLauncherClusterInitCallback(EndpointId endpoint) { ChipLogProgress(Zcl, "TV Android App: ContentLauncher::PostClusterInit"); TvAppJNIMgr().PostClusterInit(chip::app::Clusters::ContentLauncher::Id, endpoint); } void ContentLauncherManager::NewManager(jint endpoint, jobject manager) { ChipLogProgress(Zcl, "TV Android App: ContentLauncher::SetDefaultDelegate"); ContentLauncherManager * mgr = new ContentLauncherManager(); mgr->InitializeWithObjects(manager); chip::app::Clusters::ContentLauncher::SetDefaultDelegate(static_cast(endpoint), mgr); } void ContentLauncherManager::HandleLaunchContent(CommandResponseHelper & helper, const DecodableList & parameterList, bool autoplay, const chip::CharSpan & data) { Commands::LauncherResponse::Type response; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); ChipLogProgress(Zcl, "Received ContentLauncherManager::LaunchContent"); VerifyOrExit(mContentLauncherManagerObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mLaunchContentMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); { UtfString jData(env, data); // Todo: make parameterList java jobjectArray parameterArray = nullptr; jobject resp = env->CallObjectMethod(mContentLauncherManagerObject, mLaunchContentMethod, parameterArray, static_cast(autoplay), jData.jniValue()); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Java exception in ContentLauncherManager::LaunchContent"); env->ExceptionDescribe(); env->ExceptionClear(); err = CHIP_ERROR_INCORRECT_STATE; goto exit; } VerifyOrExit(resp != nullptr, err = CHIP_JNI_ERROR_NULL_OBJECT); jclass respCls = env->GetObjectClass(resp); jfieldID statusFid = env->GetFieldID(respCls, "status", "I"); VerifyOrExit(statusFid != nullptr, err = CHIP_JNI_ERROR_FIELD_NOT_FOUND); jint status = env->GetIntField(resp, statusFid); jfieldID dataFid = env->GetFieldID(respCls, "data", "Ljava/lang/String;"); VerifyOrExit(dataFid != nullptr, err = CHIP_JNI_ERROR_FIELD_NOT_FOUND); jstring jdataStr = (jstring) env->GetObjectField(resp, dataFid); JniUtfString dataStr(env, jdataStr); response.status = static_cast(status); response.data = chip::Optional(dataStr.charSpan()); err = helper.Success(response); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Zcl, "ContentLauncherManager::LaunchContent status error: %s", err.AsString()); } } void ContentLauncherManager::HandleLaunchUrl(CommandResponseHelper & helper, const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, const BrandingInformationType & brandingInformation) { Commands::LauncherResponse::Type response; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); ChipLogProgress(Zcl, "Received ContentLauncherManager::LaunchContentUrl"); VerifyOrExit(mContentLauncherManagerObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mLaunchUrlMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); { UtfString jContentUrl(env, contentUrl); UtfString jDisplayString(env, displayString); // Todo: make brandingInformation java jobjectArray branding = nullptr; jobject resp = env->CallObjectMethod(mContentLauncherManagerObject, mLaunchUrlMethod, jContentUrl.jniValue(), jDisplayString.jniValue(), branding); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Java exception in ContentLauncherManager::LaunchUrl"); env->ExceptionDescribe(); env->ExceptionClear(); err = CHIP_ERROR_INCORRECT_STATE; goto exit; } VerifyOrExit(resp != nullptr, err = CHIP_JNI_ERROR_NULL_OBJECT); jclass respCls = env->GetObjectClass(resp); jfieldID statusFid = env->GetFieldID(respCls, "status", "I"); VerifyOrExit(statusFid != nullptr, err = CHIP_JNI_ERROR_FIELD_NOT_FOUND); jint status = env->GetIntField(resp, statusFid); jfieldID dataFid = env->GetFieldID(respCls, "data", "Ljava/lang/String;"); VerifyOrExit(dataFid != nullptr, err = CHIP_JNI_ERROR_FIELD_NOT_FOUND); jstring jdataStr = (jstring) env->GetObjectField(resp, dataFid); JniUtfString dataStr(env, jdataStr); response.status = static_cast(status); response.data = chip::Optional(dataStr.charSpan()); err = helper.Success(response); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Zcl, "ContentLauncherManager::LaunchUrl status error: %s", err.AsString()); } } CHIP_ERROR ContentLauncherManager::HandleGetAcceptHeaderList(AttributeValueEncoder & aEncoder) { CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); std::list acceptedHeadersList; ChipLogProgress(Zcl, "Received ContentLauncherManager::GetAcceptHeader"); VerifyOrExit(mContentLauncherManagerObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetAcceptHeaderMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray acceptedHeadersArray = (jobjectArray) env->CallObjectMethod(mContentLauncherManagerObject, mGetAcceptHeaderMethod); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Java exception in ContentLauncherManager::GetAcceptHeader"); env->ExceptionDescribe(); env->ExceptionClear(); return CHIP_ERROR_INCORRECT_STATE; } jint size = env->GetArrayLength(acceptedHeadersArray); for (int i = 0; i < size; i++) { jstring jAcceptedHeader = (jstring) env->GetObjectArrayElement(acceptedHeadersArray, i); JniUtfString acceptedHeader(env, jAcceptedHeader); ReturnErrorOnFailure(encoder.Encode(acceptedHeader.charSpan())); } return CHIP_NO_ERROR; }); exit: if (err != CHIP_NO_ERROR) { ChipLogError(Zcl, "ContentLauncherManager::GetAcceptHeader status error: %s", err.AsString()); } return err; } uint32_t ContentLauncherManager::HandleGetSupportedStreamingProtocols() { CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); uint32_t supportedStreamingProtocols = 0; ChipLogProgress(Zcl, "Received ContentLauncherManager::GetSupportedStreamingProtocols"); VerifyOrExit(mContentLauncherManagerObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetSupportedStreamingProtocolsMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); { jlong jSupportedStreamingProtocols = env->CallLongMethod(mContentLauncherManagerObject, mGetSupportedStreamingProtocolsMethod); supportedStreamingProtocols = (uint32_t) jSupportedStreamingProtocols; if (env->ExceptionCheck()) { ChipLogError(Zcl, "Java exception in ContentLauncherManager::GetAcceptHeader"); env->ExceptionDescribe(); env->ExceptionClear(); err = CHIP_ERROR_INCORRECT_STATE; goto exit; } } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Zcl, "ContentLauncherManager::GetSupportedStreamingProtocols status error: %s", err.AsString()); } return supportedStreamingProtocols; } void ContentLauncherManager::InitializeWithObjects(jobject managerObject) { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for ContentLauncherManager")); mContentLauncherManagerObject = env->NewGlobalRef(managerObject); VerifyOrReturn(mContentLauncherManagerObject != nullptr, ChipLogError(Zcl, "Failed to NewGlobalRef ContentLauncherManager")); jclass ContentLauncherClass = env->GetObjectClass(managerObject); VerifyOrReturn(ContentLauncherClass != nullptr, ChipLogError(Zcl, "Failed to get ContentLauncherManager Java class")); mGetAcceptHeaderMethod = env->GetMethodID(ContentLauncherClass, "getAcceptHeader", "()[Ljava/lang/String;"); if (mGetAcceptHeaderMethod == nullptr) { ChipLogError(Zcl, "Failed to access ContentLauncherManager 'getInputList' method"); env->ExceptionClear(); } mGetSupportedStreamingProtocolsMethod = env->GetMethodID(ContentLauncherClass, "getSupportedStreamingProtocols", "()J"); if (mGetSupportedStreamingProtocolsMethod == nullptr) { ChipLogError(Zcl, "Failed to access ContentLauncherManager 'getSupportedStreamingProtocols' method"); env->ExceptionClear(); } mLaunchContentMethod = env->GetMethodID(ContentLauncherClass, "launchContent", "([Lcom/matter/tv/server/tvapp/ContentLaunchSearchParameter;ZLjava/lang/String;)Lcom/" "matter/tv/server/tvapp/ContentLaunchResponse;"); if (mLaunchContentMethod == nullptr) { ChipLogError(Zcl, "Failed to access ContentLauncherManager 'launchContent' method"); env->ExceptionClear(); } mLaunchUrlMethod = env->GetMethodID(ContentLauncherClass, "launchUrl", "(Ljava/lang/String;Ljava/lang/String;Lcom/matter/tv/server/tvapp/" "ContentLaunchBrandingInformation;)Lcom/matter/tv/server/tvapp/ContentLaunchResponse;"); if (mLaunchUrlMethod == nullptr) { ChipLogError(AppServer, "Failed to access 'launchUrl' method"); env->ExceptionClear(); } } uint32_t ContentLauncherManager::GetFeatureMap(chip::EndpointId endpoint) { uint32_t featureMap = 0; Attributes::FeatureMap::Get(endpoint, &featureMap); return featureMap; }