blob: d33949a5d382d93fa4bdb4ce8f629cc58fe04e56 [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* 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.
*/
/**
* @file Contains Implementation of the ContentApp and the ContentAppPlatform.
*/
#include "AppImpl.h"
#include "ContentAppAttributeDelegate.h"
#include "ContentAppCommandDelegate.h"
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/CommandHandler.h>
#include <app/CommandHandlerInterfaceRegistry.h>
#include <app/reporting/reporting.h>
#include <app/server/Dnssd.h>
#include <app/server/Server.h>
#include <app/util/endpoint-config-api.h>
#include <cstdio>
#include <inttypes.h>
#include <jni.h>
#include <lib/core/CHIPCore.h>
#include <lib/shell/Commands.h>
#include <lib/shell/Engine.h>
#include <lib/shell/commands/Help.h>
#include <lib/support/CHIPArgParser.hpp>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/ZclString.h>
#include <platform/CHIPDeviceLayer.h>
#include <platform/DeviceInstanceInfoProvider.h>
#include <string>
using namespace chip;
using namespace chip::app::Clusters;
using namespace chip::AppPlatform;
using namespace chip::DeviceLayer;
#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
ContentAppFactoryImpl gFactory;
ContentAppFactoryImpl * GetContentAppFactoryImpl()
{
return &gFactory;
}
namespace chip {
namespace AppPlatform {
// BEGIN DYNAMIC ENDPOINTS
// =================================================================================
static const int kNameSize = 32;
// Current ZCL implementation of Struct uses a max-size array of 254 bytes
static const int kDescriptorAttributeArraySize = 254;
// Device types for dynamic endpoints: TODO Need a generated file from ZAP to define these!
// (taken from chip-devices.xml)
#define DEVICE_TYPE_CONTENT_APP 0x0024
// ---------------------------------------------------------------------------
//
// CONTENT APP ENDPOINT: contains the following clusters:
// - Descriptor
// - Application Basic
// - Keypad Input
// - Application Launcher
// - Account Login
// - Content Launcher
// - Target Navigator
// - Channel
// Declare Descriptor cluster attributes
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs)
DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */
DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */
DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */
DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* parts list */
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
// Declare Application Basic information cluster attributes
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(applicationBasicAttrs)
DECLARE_DYNAMIC_ATTRIBUTE(ApplicationBasic::Attributes::VendorName::Id, CHAR_STRING, kNameSize, 0), /* VendorName */
DECLARE_DYNAMIC_ATTRIBUTE(ApplicationBasic::Attributes::VendorID::Id, INT16U, 1, 0), /* VendorID */
DECLARE_DYNAMIC_ATTRIBUTE(ApplicationBasic::Attributes::ApplicationName::Id, CHAR_STRING, kNameSize, 0), /* ApplicationName */
DECLARE_DYNAMIC_ATTRIBUTE(ApplicationBasic::Attributes::ProductID::Id, INT16U, 1, 0), /* ProductID */
DECLARE_DYNAMIC_ATTRIBUTE(ApplicationBasic::Attributes::Status::Id, INT8U, 1, 0), /* ApplicationStatus */
DECLARE_DYNAMIC_ATTRIBUTE(ApplicationBasic::Attributes::ApplicationVersion::Id, CHAR_STRING, kNameSize,
0), /* ApplicationVersion */
DECLARE_DYNAMIC_ATTRIBUTE(ApplicationBasic::Attributes::AllowedVendorList::Id, ARRAY, kDescriptorAttributeArraySize,
0), /* AllowedVendorList */
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
// Declare Keypad Input cluster attributes
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(keypadInputAttrs)
DECLARE_DYNAMIC_ATTRIBUTE(KeypadInput::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* FeatureMap */
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
// Declare Application Launcher cluster attributes
// NOTE: Does not make sense for content app to be able to set the AP feature flag
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(applicationLauncherAttrs)
DECLARE_DYNAMIC_ATTRIBUTE(ApplicationLauncher::Attributes::CatalogList::Id, ARRAY, kDescriptorAttributeArraySize,
0), /* catalog list */
DECLARE_DYNAMIC_ATTRIBUTE(ApplicationLauncher::Attributes::CurrentApp::Id, STRUCT, 1, 0), /* current app */
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
// Declare Account Login cluster attributes
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(accountLoginAttrs)
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
// Declare Content Launcher cluster attributes
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(contentLauncherAttrs)
DECLARE_DYNAMIC_ATTRIBUTE(ContentLauncher::Attributes::AcceptHeader::Id, ARRAY, kDescriptorAttributeArraySize,
0), /* accept header list */
DECLARE_DYNAMIC_ATTRIBUTE(ContentLauncher::Attributes::SupportedStreamingProtocols::Id, BITMAP32, 1,
0), /* streaming protocols */
DECLARE_DYNAMIC_ATTRIBUTE(ContentLauncher::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* FeatureMap */
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
// Declare Media Playback cluster attributes
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(mediaPlaybackAttrs)
DECLARE_DYNAMIC_ATTRIBUTE(MediaPlayback::Attributes::CurrentState::Id, ENUM8, 1, 0), /* current state */
DECLARE_DYNAMIC_ATTRIBUTE(MediaPlayback::Attributes::StartTime::Id, EPOCH_US, 1, 0), /* start time */
DECLARE_DYNAMIC_ATTRIBUTE(MediaPlayback::Attributes::Duration::Id, INT64U, 1, 0), /* duration */
DECLARE_DYNAMIC_ATTRIBUTE(MediaPlayback::Attributes::SampledPosition::Id, STRUCT, 1, 0), /* SampledPosition */
DECLARE_DYNAMIC_ATTRIBUTE(MediaPlayback::Attributes::PlaybackSpeed::Id, SINGLE, 1, 0), /* playback speed */
DECLARE_DYNAMIC_ATTRIBUTE(MediaPlayback::Attributes::SeekRangeEnd::Id, INT64U, 1, 0), /* seek range end */
DECLARE_DYNAMIC_ATTRIBUTE(MediaPlayback::Attributes::SeekRangeStart::Id, INT64U, 1, 0), /* seek range start */
DECLARE_DYNAMIC_ATTRIBUTE(MediaPlayback::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* FeatureMap */
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
// Declare Target Navigator cluster attributes
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(targetNavigatorAttrs)
DECLARE_DYNAMIC_ATTRIBUTE(TargetNavigator::Attributes::TargetList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* target list */
DECLARE_DYNAMIC_ATTRIBUTE(TargetNavigator::Attributes::CurrentTarget::Id, INT8U, 1, 0), /* current target */
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
// Declare Channel cluster attributes
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(channelAttrs)
DECLARE_DYNAMIC_ATTRIBUTE(Channel::Attributes::ChannelList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* channel list */
DECLARE_DYNAMIC_ATTRIBUTE(Channel::Attributes::Lineup::Id, STRUCT, 1, 0), /* lineup */
DECLARE_DYNAMIC_ATTRIBUTE(Channel::Attributes::CurrentChannel::Id, STRUCT, 1, 0), /* current channel */
DECLARE_DYNAMIC_ATTRIBUTE(Channel::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* FeatureMap */
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
constexpr CommandId keypadInputIncomingCommands[] = {
app::Clusters::KeypadInput::Commands::SendKey::Id,
kInvalidCommandId,
};
constexpr CommandId keypadInputOutgoingCommands[] = {
app::Clusters::KeypadInput::Commands::SendKeyResponse::Id,
kInvalidCommandId,
};
constexpr CommandId applicationLauncherIncomingCommands[] = {
app::Clusters::ApplicationLauncher::Commands::LaunchApp::Id,
app::Clusters::ApplicationLauncher::Commands::StopApp::Id,
app::Clusters::ApplicationLauncher::Commands::HideApp::Id,
kInvalidCommandId,
};
constexpr CommandId applicationLauncherOutgoingCommands[] = {
app::Clusters::ApplicationLauncher::Commands::LauncherResponse::Id,
kInvalidCommandId,
};
constexpr CommandId accountLoginIncomingCommands[] = {
app::Clusters::AccountLogin::Commands::GetSetupPIN::Id,
app::Clusters::AccountLogin::Commands::Login::Id,
app::Clusters::AccountLogin::Commands::Logout::Id,
kInvalidCommandId,
};
constexpr CommandId accountLoginOutgoingCommands[] = {
app::Clusters::AccountLogin::Commands::GetSetupPINResponse::Id,
kInvalidCommandId,
};
// TODO: Sort out when the optional commands here should be listed.
constexpr CommandId contentLauncherIncomingCommands[] = {
app::Clusters::ContentLauncher::Commands::LaunchContent::Id,
app::Clusters::ContentLauncher::Commands::LaunchURL::Id,
kInvalidCommandId,
};
constexpr CommandId contentLauncherOutgoingCommands[] = {
app::Clusters::ContentLauncher::Commands::LauncherResponse::Id,
kInvalidCommandId,
};
// TODO: Sort out when the optional commands here should be listed.
constexpr CommandId mediaPlaybackIncomingCommands[] = {
app::Clusters::MediaPlayback::Commands::Play::Id, app::Clusters::MediaPlayback::Commands::Pause::Id,
app::Clusters::MediaPlayback::Commands::Stop::Id, app::Clusters::MediaPlayback::Commands::StartOver::Id,
app::Clusters::MediaPlayback::Commands::Previous::Id, app::Clusters::MediaPlayback::Commands::Next::Id,
app::Clusters::MediaPlayback::Commands::Rewind::Id, app::Clusters::MediaPlayback::Commands::FastForward::Id,
app::Clusters::MediaPlayback::Commands::SkipForward::Id, app::Clusters::MediaPlayback::Commands::SkipBackward::Id,
app::Clusters::MediaPlayback::Commands::Seek::Id, kInvalidCommandId,
};
constexpr CommandId mediaPlaybackOutgoingCommands[] = {
app::Clusters::MediaPlayback::Commands::PlaybackResponse::Id,
kInvalidCommandId,
};
constexpr CommandId targetNavigatorIncomingCommands[] = {
app::Clusters::TargetNavigator::Commands::NavigateTarget::Id,
kInvalidCommandId,
};
constexpr CommandId targetNavigatorOutgoingCommands[] = {
app::Clusters::TargetNavigator::Commands::NavigateTargetResponse::Id,
kInvalidCommandId,
};
// TODO: Sort out when the optional commands here should be listed.
constexpr CommandId channelIncomingCommands[] = {
app::Clusters::Channel::Commands::ChangeChannel::Id,
app::Clusters::Channel::Commands::ChangeChannelByNumber::Id,
app::Clusters::Channel::Commands::SkipChannel::Id,
kInvalidCommandId,
};
constexpr CommandId channelOutgoingCommands[] = {
app::Clusters::Channel::Commands::ChangeChannelResponse::Id,
kInvalidCommandId,
};
// Declare Cluster List for Content App endpoint
DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(contentAppClusters)
DECLARE_DYNAMIC_CLUSTER(app::Clusters::Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
DECLARE_DYNAMIC_CLUSTER(app::Clusters::ApplicationBasic::Id, applicationBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
DECLARE_DYNAMIC_CLUSTER(app::Clusters::KeypadInput::Id, keypadInputAttrs, ZAP_CLUSTER_MASK(SERVER), keypadInputIncomingCommands,
keypadInputOutgoingCommands),
DECLARE_DYNAMIC_CLUSTER(app::Clusters::ApplicationLauncher::Id, applicationLauncherAttrs, ZAP_CLUSTER_MASK(SERVER),
applicationLauncherIncomingCommands, applicationLauncherOutgoingCommands),
DECLARE_DYNAMIC_CLUSTER(app::Clusters::AccountLogin::Id, accountLoginAttrs, ZAP_CLUSTER_MASK(SERVER),
accountLoginIncomingCommands, accountLoginOutgoingCommands),
DECLARE_DYNAMIC_CLUSTER(app::Clusters::ContentLauncher::Id, contentLauncherAttrs, ZAP_CLUSTER_MASK(SERVER),
contentLauncherIncomingCommands, contentLauncherOutgoingCommands),
DECLARE_DYNAMIC_CLUSTER(app::Clusters::MediaPlayback::Id, mediaPlaybackAttrs, ZAP_CLUSTER_MASK(SERVER),
mediaPlaybackIncomingCommands, mediaPlaybackOutgoingCommands),
DECLARE_DYNAMIC_CLUSTER(app::Clusters::TargetNavigator::Id, targetNavigatorAttrs, ZAP_CLUSTER_MASK(SERVER),
targetNavigatorIncomingCommands, targetNavigatorOutgoingCommands),
DECLARE_DYNAMIC_CLUSTER(app::Clusters::Channel::Id, channelAttrs, ZAP_CLUSTER_MASK(SERVER), channelIncomingCommands,
channelOutgoingCommands),
DECLARE_DYNAMIC_CLUSTER_LIST_END;
// Declare Content App endpoint
DECLARE_DYNAMIC_ENDPOINT(contentAppEndpoint, contentAppClusters);
namespace {
DataVersion gDataVersions[APP_LIBRARY_SIZE][ArraySize(contentAppClusters)];
EmberAfDeviceType gContentAppDeviceType[] = { { DEVICE_TYPE_CONTENT_APP, 1 } };
std::vector<SupportedCluster> make_default_supported_clusters()
{
return std::vector<ContentApp::SupportedCluster>{ { Descriptor::Id }, { ApplicationBasic::Id },
{ KeypadInput::Id }, { ApplicationLauncher::Id },
{ AccountLogin::Id }, { ContentLauncher::Id },
{ TargetNavigator::Id }, { Channel::Id } };
}
} // anonymous namespace
ContentAppFactoryImpl::ContentAppFactoryImpl() :
mContentApps{ new ContentAppImpl("Vendor1", 1, "exampleid", 11, "Version1", "20202021", make_default_supported_clusters(),
nullptr, nullptr),
new ContentAppImpl("Vendor2", 65521, "exampleString", 32768, "Version2", "20202021",
make_default_supported_clusters(), nullptr, nullptr),
new ContentAppImpl("Vendor3", 9050, "App3", 22, "Version3", "20202021", make_default_supported_clusters(),
nullptr, nullptr),
new ContentAppImpl("TestSuiteVendor", 1111, "applicationId", 22, "v2", "20202021",
make_default_supported_clusters(), nullptr, nullptr) }
{}
uint16_t ContentAppFactoryImpl::GetPlatformCatalogVendorId()
{
return kCatalogVendorId;
}
void ContentAppFactoryImpl::setContentAppAttributeDelegate(ContentAppAttributeDelegate * attributeDelegate)
{
mAttributeDelegate = attributeDelegate;
}
void ContentAppFactoryImpl::setContentAppCommandDelegate(ContentAppCommandDelegate * commandDelegate)
{
mCommandDelegate = commandDelegate;
}
CHIP_ERROR ContentAppFactoryImpl::LookupCatalogVendorApp(uint16_t vendorId, uint16_t productId, CatalogVendorApp * destinationApp)
{
std::string appId = BuildAppId(vendorId);
destinationApp->catalogVendorId = GetPlatformCatalogVendorId();
Platform::CopyString(destinationApp->applicationId, sizeof(destinationApp->applicationId), appId.c_str());
return CHIP_NO_ERROR;
}
CHIP_ERROR ContentAppFactoryImpl::ConvertToPlatformCatalogVendorApp(const CatalogVendorApp & sourceApp,
CatalogVendorApp * destinationApp)
{
destinationApp->catalogVendorId = GetPlatformCatalogVendorId();
std::string appId(sourceApp.applicationId);
if (appId == "applicationId")
{
// regression test case passes "applicationId", map this to our test suite app
Platform::CopyString(destinationApp->applicationId, sizeof(destinationApp->applicationId), "1111");
}
else if (appId == "exampleid")
{
// cert test case passes "exampleid", map this to our test suite app
Platform::CopyString(destinationApp->applicationId, sizeof(destinationApp->applicationId), "1");
}
else if (appId == "exampleString")
{
// cert test case passes "exampleString", map this to our test suite app
Platform::CopyString(destinationApp->applicationId, sizeof(destinationApp->applicationId), "65521");
}
else
{
// for now, just return the applicationId passed in
Platform::CopyString(destinationApp->applicationId, sizeof(destinationApp->applicationId), sourceApp.applicationId);
}
return CHIP_NO_ERROR;
}
ContentApp * ContentAppFactoryImpl::LoadContentApp(const CatalogVendorApp & vendorApp)
{
ChipLogProgress(DeviceLayer, "ContentAppFactoryImpl: LoadContentAppByAppId catalogVendorId=%d applicationId=%s ",
vendorApp.catalogVendorId, vendorApp.applicationId);
for (size_t i = 0; i < mContentApps.size(); ++i)
{
auto & app = mContentApps.at(i);
ChipLogProgress(DeviceLayer, " Looking next=%s ", app->GetApplicationBasicDelegate()->GetCatalogVendorApp()->applicationId);
if (app->GetApplicationBasicDelegate()->GetCatalogVendorApp()->Matches(vendorApp))
{
// need to think about loading apk here?
ContentAppPlatform::GetInstance().AddContentApp(app, &contentAppEndpoint, Span<DataVersion>(gDataVersions[i]),
Span<const EmberAfDeviceType>(gContentAppDeviceType));
return app;
}
}
ChipLogProgress(DeviceLayer, "LoadContentAppByAppId NOT FOUND catalogVendorId=%d applicationId=%s ", vendorApp.catalogVendorId,
vendorApp.applicationId);
return nullptr;
}
class DevicePairedCommand : public Controller::DevicePairingDelegate
{
public:
struct CallbackContext
{
uint16_t vendorId;
uint16_t productId;
chip::NodeId nodeId;
CallbackContext(uint16_t vId, uint16_t pId, chip::NodeId nId) : vendorId(vId), productId(pId), nodeId(nId) {}
};
DevicePairedCommand(uint16_t vendorId, uint16_t productId, chip::NodeId nodeId) :
mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this)
{
mContext = std::make_shared<CallbackContext>(vendorId, productId, nodeId);
}
static void OnDeviceConnectedFn(void * context, chip::Messaging::ExchangeManager & exchangeMgr,
const chip::SessionHandle & sessionHandle)
{
auto * pairingCommand = static_cast<DevicePairedCommand *>(context);
auto cbContext = pairingCommand->mContext;
if (pairingCommand)
{
ChipLogProgress(DeviceLayer,
"OnDeviceConnectedFn - Updating ACL for node id: " ChipLogFormatX64
" and vendor id: %d and product id: %d",
ChipLogValueX64(cbContext->nodeId), cbContext->vendorId, cbContext->productId);
GetCommissionerDiscoveryController()->CommissioningSucceeded(cbContext->vendorId, cbContext->productId,
cbContext->nodeId, exchangeMgr, sessionHandle);
}
}
static void OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
{
auto * pairingCommand = static_cast<DevicePairedCommand *>(context);
auto cbContext = pairingCommand->mContext;
if (pairingCommand)
{
ChipLogProgress(DeviceLayer,
"OnDeviceConnectionFailureFn - Not updating ACL for node id: " ChipLogFormatX64
" and vendor id: %d and product id: %d",
ChipLogValueX64(cbContext->nodeId), cbContext->vendorId, cbContext->productId);
// TODO: Remove Node Id
}
}
chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
std::shared_ptr<CallbackContext> mContext;
};
void refreshConnectedClientsAcl(uint16_t vendorId, uint16_t productId, ContentAppImpl * app)
{
std::set<NodeId> nodeIds = ContentAppPlatform::GetInstance().GetNodeIdsForContentApp(vendorId, productId);
for (const auto & allowedVendor : app->GetApplicationBasicDelegate()->GetAllowedVendorList())
{
std::set<NodeId> tempNodeIds = ContentAppPlatform::GetInstance().GetNodeIdsForAllowedVendorId(allowedVendor);
nodeIds.insert(tempNodeIds.begin(), tempNodeIds.end());
}
for (const auto & nodeId : nodeIds)
{
ChipLogProgress(DeviceLayer,
"Creating Pairing Command with node id: " ChipLogFormatX64 " and vendor id: %d and product id: %d",
ChipLogValueX64(nodeId), vendorId, productId);
std::shared_ptr<DevicePairedCommand> pairingCommand = std::make_shared<DevicePairedCommand>(vendorId, productId, nodeId);
GetDeviceCommissioner()->GetConnectedDevice(nodeId, &pairingCommand->mOnDeviceConnectedCallback,
&pairingCommand->mOnDeviceConnectionFailureCallback);
}
}
EndpointId ContentAppFactoryImpl::AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName,
uint16_t productId, const char * szApplicationVersion,
std::vector<SupportedCluster> supportedClusters, jobject manager)
{
DataVersion * dataVersionBuf = new DataVersion[ArraySize(contentAppClusters)];
ContentAppImpl * app = new ContentAppImpl(szVendorName, vendorId, szApplicationName, productId, szApplicationVersion, "",
std::move(supportedClusters), mAttributeDelegate, mCommandDelegate);
EndpointId epId = ContentAppPlatform::GetInstance().AddContentApp(
app, &contentAppEndpoint, Span<DataVersion>(dataVersionBuf, ArraySize(contentAppClusters)),
Span<const EmberAfDeviceType>(gContentAppDeviceType));
ChipLogProgress(DeviceLayer, "ContentAppFactoryImpl AddContentApp endpoint returned %d. Endpoint set %d", epId,
app->GetEndpointId());
mContentApps.push_back(app);
mDataVersions.push_back(dataVersionBuf);
refreshConnectedClientsAcl(vendorId, productId, app);
return epId;
}
EndpointId ContentAppFactoryImpl::AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName,
uint16_t productId, const char * szApplicationVersion,
std::vector<SupportedCluster> supportedClusters, EndpointId desiredEndpointId,
jobject manager)
{
DataVersion * dataVersionBuf = new DataVersion[ArraySize(contentAppClusters)];
ContentAppImpl * app = new ContentAppImpl(szVendorName, vendorId, szApplicationName, productId, szApplicationVersion, "",
std::move(supportedClusters), mAttributeDelegate, mCommandDelegate);
EndpointId epId = ContentAppPlatform::GetInstance().AddContentApp(
app, &contentAppEndpoint, Span<DataVersion>(dataVersionBuf, ArraySize(contentAppClusters)),
Span<const EmberAfDeviceType>(gContentAppDeviceType), desiredEndpointId);
ChipLogProgress(DeviceLayer, "ContentAppFactoryImpl AddContentApp endpoint returned %d. Endpoint set %d", epId,
app->GetEndpointId());
mContentApps.push_back(app);
mDataVersions.push_back(dataVersionBuf);
refreshConnectedClientsAcl(vendorId, productId, app);
return epId;
}
EndpointId ContentAppFactoryImpl::RemoveContentApp(EndpointId epId)
{
for (size_t i = 0; i < mContentApps.size(); ++i)
{
auto & app = mContentApps.at(i);
if (app->GetEndpointId() == epId)
{
ChipLogProgress(DeviceLayer, "ContentAppFactoryImpl RemoveContentApp endpointId %d", epId);
EndpointId removedEndpointID = ContentAppPlatform::GetInstance().RemoveContentApp(app);
// Only remove the app from the set of content apps if they were dynamically added and not part of the static list of
// apps
if (removedEndpointID != 0 && i > APP_LIBRARY_SIZE)
{
mContentApps.erase(mContentApps.begin() + static_cast<int>(i));
DataVersion * dataVersionBuf = mDataVersions.at(i - APP_LIBRARY_SIZE);
mDataVersions.erase(mDataVersions.begin() + static_cast<int>(i - APP_LIBRARY_SIZE));
// deallocate memory for objects that were created when adding the content app dynamically.
delete[] dataVersionBuf;
delete app;
}
return removedEndpointID;
}
}
return kInvalidEndpointId;
}
void ContentAppFactoryImpl::LogInstalledApps()
{
for (auto & contentApp : mContentApps)
{
ChipLogProgress(DeviceLayer, "Content app vid=%d pid=%d id=%s is on ep=%d",
contentApp->GetApplicationBasicDelegate()->HandleGetVendorId(),
contentApp->GetApplicationBasicDelegate()->HandleGetProductId(),
contentApp->GetApplicationBasicDelegate()->GetCatalogVendorApp()->GetApplicationId(),
contentApp->GetEndpointId());
}
}
void ContentAppFactoryImpl::AddAdminVendorId(uint16_t vendorId)
{
mAdminVendorIds.push_back(vendorId);
}
Access::Privilege ContentAppFactoryImpl::GetVendorPrivilege(uint16_t vendorId)
{
for (size_t i = 0; i < mAdminVendorIds.size(); ++i)
{
auto & vendor = mAdminVendorIds.at(i);
if (vendorId == vendor)
{
return Access::Privilege::kAdminister;
}
}
return Access::Privilege::kOperate;
}
std::list<ClusterId> ContentAppFactoryImpl::GetAllowedClusterListForStaticEndpoint(EndpointId endpointId, uint16_t vendorId,
uint16_t productId)
{
if (endpointId == kLocalVideoPlayerEndpointId)
{
if (GetVendorPrivilege(vendorId) == Access::Privilege::kAdminister)
{
ChipLogProgress(DeviceLayer,
"ContentAppFactoryImpl GetAllowedClusterListForStaticEndpoint priviledged vendor accessible clusters "
"being returned.");
return { chip::app::Clusters::Descriptor::Id,
chip::app::Clusters::OnOff::Id,
chip::app::Clusters::WakeOnLan::Id,
chip::app::Clusters::MediaPlayback::Id,
chip::app::Clusters::LowPower::Id,
chip::app::Clusters::KeypadInput::Id,
chip::app::Clusters::ContentLauncher::Id,
chip::app::Clusters::AudioOutput::Id,
chip::app::Clusters::ApplicationLauncher::Id,
chip::app::Clusters::Messages::Id };
}
ChipLogProgress(
DeviceLayer,
"ContentAppFactoryImpl GetAllowedClusterListForStaticEndpoint operator vendor accessible clusters being returned.");
return { chip::app::Clusters::Descriptor::Id, chip::app::Clusters::OnOff::Id,
chip::app::Clusters::WakeOnLan::Id, chip::app::Clusters::MediaPlayback::Id,
chip::app::Clusters::LowPower::Id, chip::app::Clusters::KeypadInput::Id,
chip::app::Clusters::ContentLauncher::Id, chip::app::Clusters::AudioOutput::Id,
chip::app::Clusters::Messages::Id };
}
return {};
}
} // namespace AppPlatform
} // namespace chip
#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
CHIP_ERROR InitVideoPlayerPlatform(jobject contentAppEndpointManager)
{
#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
ContentAppPlatform::GetInstance().SetupAppPlatform();
ContentAppPlatform::GetInstance().SetContentAppFactory(&gFactory);
gFactory.setContentAppAttributeDelegate(new ContentAppAttributeDelegate(contentAppEndpointManager));
gFactory.setContentAppCommandDelegate(new ContentAppCommandDelegate(contentAppEndpointManager));
ChipLogProgress(AppServer, "Starting registration of command handler delegates");
for (size_t i = 0; i < ArraySize(contentAppClusters); i++)
{
ContentAppCommandDelegate * delegate =
new ContentAppCommandDelegate(contentAppEndpointManager, contentAppClusters[i].clusterId);
app::CommandHandlerInterfaceRegistry::Instance().RegisterCommandHandler(delegate);
ChipLogProgress(AppServer, "Registered command handler delegate for cluster %d", contentAppClusters[i].clusterId);
}
#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
// Disable last fixed endpoint, which is used as a placeholder for all of the
// supported clusters so that ZAP will generated the requisite code.
ChipLogDetail(DeviceLayer, "TV App: Disabling Fixed Content App Endpoints");
emberAfEndpointEnableDisable(3, false);
return CHIP_NO_ERROR;
}
EndpointId AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, uint16_t productId,
const char * szApplicationVersion, std::vector<SupportedCluster> supportedClusters, jobject manager)
{
#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
ChipLogProgress(DeviceLayer, "AppImpl: AddContentApp vendorId=%d applicationName=%s ", vendorId, szApplicationName);
return gFactory.AddContentApp(szVendorName, vendorId, szApplicationName, productId, szApplicationVersion,
std::move(supportedClusters), manager);
#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
return kInvalidEndpointId;
}
EndpointId AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, uint16_t productId,
const char * szApplicationVersion, std::vector<SupportedCluster> supportedClusters, EndpointId endpointId,
jobject manager)
{
#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
ChipLogProgress(DeviceLayer, "AppImpl: AddContentApp vendorId=%d applicationName=%s ", vendorId, szApplicationName);
return gFactory.AddContentApp(szVendorName, vendorId, szApplicationName, productId, szApplicationVersion,
std::move(supportedClusters), endpointId, manager);
#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
return kInvalidEndpointId;
}
EndpointId RemoveContentApp(EndpointId epId)
{
#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
ChipLogProgress(DeviceLayer, "AppImpl: RemoveContentApp endpointId=%d ", epId);
return gFactory.RemoveContentApp(epId);
#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
return kInvalidEndpointId;
}
void ReportAttributeChange(EndpointId epId, chip::ClusterId clusterId, chip::AttributeId attributeId)
{
MatterReportingAttributeChangeCallback(epId, clusterId, attributeId);
}
void AddSelfVendorAsAdmin()
{
uint16_t value;
if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(value) != CHIP_NO_ERROR)
{
ChipLogDetail(Discovery, "AppImpl addSelfVendorAsAdmin Vendor ID not known");
}
else
{
gFactory.AddAdminVendorId(value);
}
}