blob: 9aacc2d6e56b22f6dbc3c2aa26fc86ab8ea8d292 [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 "ContentLauncherManager.h"
#include "TvApp-JNI.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/util/config.h>
#include <jni.h>
#include <lib/core/CHIPSafeCasts.h>
#include <lib/support/CHIPJNIError.h>
#include <lib/support/JniReferences.h>
#include <lib/support/JniTypeWrappers.h>
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<EndpointId>(endpoint), mgr);
}
void ContentLauncherManager::HandleLaunchContent(CommandResponseHelper<LaunchResponseType> & helper,
const DecodableList<ParameterType> & parameterList, bool autoplay,
const chip::CharSpan & data,
const chip::Optional<PlaybackPreferencesType> playbackPreferences,
bool useCurrentContext)
{
DeviceLayer::StackUnlock unlock;
Commands::LauncherResponse::Type response;
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Could not get JNIEnv for current thread"));
JniLocalReferenceScope scope(env);
ChipLogProgress(Zcl, "Received ContentLauncherManager::LaunchContent");
VerifyOrExit(mContentLauncherManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(mLaunchContentMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
env->ExceptionClear();
{
UtfString jData(env, data);
// Todo: make parameterList java
jobjectArray parameterArray = nullptr;
jobject resp = env->CallObjectMethod(mContentLauncherManagerObject.ObjectRef(), mLaunchContentMethod, parameterArray,
static_cast<jboolean>(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<chip::app::Clusters::ContentLauncher::StatusEnum>(status);
response.data = chip::Optional<CharSpan>(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<LaunchResponseType> & helper, const chip::CharSpan & contentUrl,
const chip::CharSpan & displayString,
const BrandingInformationType & brandingInformation)
{
DeviceLayer::StackUnlock unlock;
Commands::LauncherResponse::Type response;
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Could not get JNIEnv for current thread"));
JniLocalReferenceScope scope(env);
ChipLogProgress(Zcl, "Received ContentLauncherManager::LaunchContentUrl");
VerifyOrExit(mContentLauncherManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(mLaunchUrlMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
env->ExceptionClear();
{
UtfString jContentUrl(env, contentUrl);
UtfString jDisplayString(env, displayString);
// Todo: make brandingInformation java
jobjectArray branding = nullptr;
jobject resp = env->CallObjectMethod(mContentLauncherManagerObject.ObjectRef(), 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<chip::app::Clusters::ContentLauncher::StatusEnum>(status);
response.data = chip::Optional<CharSpan>(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)
{
DeviceLayer::StackUnlock unlock;
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
std::list<std::string> acceptedHeadersList;
VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NO_ENV, ChipLogError(Zcl, "Could not get JNIEnv for current thread"));
JniLocalReferenceScope scope(env);
ChipLogProgress(Zcl, "Received ContentLauncherManager::GetAcceptHeader");
VerifyOrExit(mContentLauncherManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(mGetAcceptHeaderMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
env->ExceptionClear();
return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR {
jobjectArray acceptedHeadersArray =
(jobjectArray) env->CallObjectMethod(mContentLauncherManagerObject.ObjectRef(), 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()
{
DeviceLayer::StackUnlock unlock;
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
uint32_t supportedStreamingProtocols = 0;
VerifyOrReturnValue(env != nullptr, 0, ChipLogError(Zcl, "Could not get JNIEnv for current thread"));
JniLocalReferenceScope scope(env);
ChipLogProgress(Zcl, "Received ContentLauncherManager::GetSupportedStreamingProtocols");
VerifyOrExit(mContentLauncherManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(mGetSupportedStreamingProtocolsMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
env->ExceptionClear();
{
jlong jSupportedStreamingProtocols =
env->CallLongMethod(mContentLauncherManagerObject.ObjectRef(), 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"));
VerifyOrReturn(mContentLauncherManagerObject.Init(managerObject) == CHIP_NO_ERROR,
ChipLogError(Zcl, "Failed to init mContentLauncherManagerObject"));
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;
}
uint16_t ContentLauncherManager::GetClusterRevision(chip::EndpointId endpoint)
{
if (endpoint >= MATTER_DM_CONTENT_LAUNCHER_CLUSTER_SERVER_ENDPOINT_COUNT)
{
return kClusterRevision;
}
uint16_t clusterRevision = 0;
bool success =
(Attributes::ClusterRevision::Get(endpoint, &clusterRevision) == chip::Protocols::InteractionModel::Status::Success);
if (!success)
{
ChipLogError(Zcl, "ContentLauncherManager::GetClusterRevision error reading cluster revision");
}
return clusterRevision;
}