Skip to content

Commit

Permalink
Add functionality to read attributes from content apps (#19924)
Browse files Browse the repository at this point in the history
* Add functionality to read attributes from content apps

* Remove unused code

* Fixed issues identified during review

* restyle

* Failure handling and fixed typo

* restyle fixes.
  • Loading branch information
amitnj authored and pull[bot] committed Aug 20, 2022
1 parent 3fe41db commit 1089933
Show file tree
Hide file tree
Showing 13 changed files with 332 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ public class MatterIntentConstants {

public static final String EXTRA_RESPONSE_PAYLOAD = "EXTRA_RESPONSE_PAYLOAD";

public static final String EXTRA_ATTRIBUTE_ACTION = "EXTRA_ATTRIBUTE_ACTION";

public static final String ATTRIBUTE_ACTION_READ = "ATTRIBUTE_ACTION_READ";

public static final String EXTRA_DIRECTIVE_RESPONSE_PENDING_INTENT =
"EXTRA_DIRECTIVE_RESPONSE_PENDING_INTENT";

public static final String EXTRA_COMMAND_ID = "EXTRA_COMMAND_ID";
public static final String EXTRA_CLUSTER_ID = "EXTRA_CLUSTER_ID";
public static final String EXTRA_ATTRIBUTE_ID = "EXTRA_ATTRIBUTE_ID";
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

public class MatterCommandReceiver extends BroadcastReceiver {
private static final String TAG = "MatterCommandReceiver";
private static final int ACCEPT_HEADER = 0;
private static final int SUPPORTED_STREAMING_PROTOCOLS = 1;

@Override
public void onReceive(Context context, Intent intent) {
Expand All @@ -21,37 +23,48 @@ public void onReceive(Context context, Intent intent) {

switch (intentAction) {
case MatterIntentConstants.ACTION_MATTER_COMMAND:
byte[] commandPayload =
intent.getByteArrayExtra(MatterIntentConstants.EXTRA_COMMAND_PAYLOAD);
int commandId = intent.getIntExtra(MatterIntentConstants.EXTRA_COMMAND_ID, -1);
int clusterId = intent.getIntExtra(MatterIntentConstants.EXTRA_CLUSTER_ID, -1);
Log.d(
TAG,
new StringBuilder()
.append("Received matter command ")
.append(commandId)
.append(" on cluster ")
.append(clusterId)
.append(" with payload : ")
.append(new String(commandPayload))
.toString());

PendingIntent pendingIntent =
intent.getParcelableExtra(
MatterIntentConstants.EXTRA_DIRECTIVE_RESPONSE_PENDING_INTENT);
if (pendingIntent != null) {
final Intent responseIntent =
new Intent()
.putExtra(
MatterIntentConstants.EXTRA_RESPONSE_PAYLOAD,
"{\"value\":{\"0\":1, \"1\":\"custom response from content app\"}}"
.getBytes());
try {
pendingIntent.send(context, 0, responseIntent);
} catch (final PendingIntent.CanceledException ex) {
Log.e(TAG, "Error sending pending intent to the Matter agent", ex);
if (commandId != -1) {
int clusterId = intent.getIntExtra(MatterIntentConstants.EXTRA_CLUSTER_ID, -1);
byte[] commandPayload =
intent.getByteArrayExtra(MatterIntentConstants.EXTRA_COMMAND_PAYLOAD);
Log.d(
TAG,
new StringBuilder()
.append("Received matter command ")
.append(commandId)
.append(" on cluster ")
.append(clusterId)
.append(" with payload : ")
.append(new String(commandPayload))
.toString());
String response = "{\"0\":1, \"1\":\"custom response from content app\"}";
sendResponseViaPendingIntent(context, intent, response);
} else {
int attributeId = intent.getIntExtra(MatterIntentConstants.EXTRA_ATTRIBUTE_ID, -1);
String attributeAction =
intent.getStringExtra(MatterIntentConstants.EXTRA_ATTRIBUTE_ACTION);
if (attributeAction.equals(MatterIntentConstants.ATTRIBUTE_ACTION_READ)) {
String response;
if (attributeId == ACCEPT_HEADER) {
response =
"{\"0\": [\"video/mp4\", \"application/x-mpegURL\", \"application/dash+xml\"] }";
} else if (attributeId == SUPPORTED_STREAMING_PROTOCOLS) {
response = "{\"1\":3}";
} else {
response = "";
}
sendResponseViaPendingIntent(context, intent, response);
} else {
Log.e(
TAG,
new StringBuilder()
.append("Received unknown Attribute Action: ")
.append(intent.getAction())
.toString());
}
}

break;
default:
Log.e(
Expand All @@ -62,4 +75,18 @@ public void onReceive(Context context, Intent intent) {
.toString());
}
}

private void sendResponseViaPendingIntent(Context context, Intent intent, String response) {
PendingIntent pendingIntent =
intent.getParcelableExtra(MatterIntentConstants.EXTRA_DIRECTIVE_RESPONSE_PENDING_INTENT);
if (pendingIntent != null) {
final Intent responseIntent =
new Intent().putExtra(MatterIntentConstants.EXTRA_RESPONSE_PAYLOAD, response.getBytes());
try {
pendingIntent.send(context, 0, responseIntent);
} catch (final PendingIntent.CanceledException ex) {
Log.e(TAG, "Error sending pending intent to the Matter agent", ex);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,24 @@ public String sendCommand(int endpointId, int clusterId, int commandId, String c
}
return "Success";
}

public String readAttribute(int endpointId, int clusterId, int attributeId) {
Log.d(
TAG,
"Received a attribute read request for endpointId "
+ endpointId
+ "clusterId"
+ clusterId
+ " attributeId "
+ attributeId);
for (ContentApp app :
ContentAppDiscoveryService.getReceiverInstance().getDiscoveredContentApps().values()) {
if (app.getEndpointId() == endpointId) {
Log.d(TAG, "Sending attribute read request for endpointId " + endpointId);
return ContentAppAgentService.sendAttributeReadRequest(
context, app.getAppName(), clusterId, attributeId);
}
}
return "";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,33 @@ public static String sendCommand(
return response;
}

public static String sendAttributeReadRequest(
Context context, String packageName, int clusterId, int attributeId) {
Intent in = new Intent(MatterIntentConstants.ACTION_MATTER_COMMAND);
Bundle extras = new Bundle();
extras.putString(
MatterIntentConstants.EXTRA_ATTRIBUTE_ACTION, MatterIntentConstants.ATTRIBUTE_ACTION_READ);
extras.putInt(MatterIntentConstants.EXTRA_ATTRIBUTE_ID, attributeId);
extras.putInt(MatterIntentConstants.EXTRA_CLUSTER_ID, clusterId);
in.putExtras(extras);
in.setPackage(packageName);
int flags = Intent.FLAG_INCLUDE_STOPPED_PACKAGES;
flags |= Intent.FLAG_RECEIVER_FOREGROUND;
in.setFlags(flags);
int messageId = responseRegistry.getNextMessageCounter();
in.putExtra(
MatterIntentConstants.EXTRA_DIRECTIVE_RESPONSE_PENDING_INTENT,
getPendingIntentForResponse(context, packageName, messageId));
context.sendBroadcast(in);
responseRegistry.waitForMessage(messageId, 10, TimeUnit.SECONDS);
String response = responseRegistry.readAndRemoveResponse(messageId);
if (response == null) {
response = "";
}
Log.d(TAG, "Response " + response + " being returned for message " + messageId);
return response;
}

private static PendingIntent getPendingIntentForResponse(
final Context context, final String targetPackage, final int responseId) {
Intent ackBackIntent = new Intent(ACTION_MATTER_RESPONSE);
Expand Down
2 changes: 2 additions & 0 deletions examples/tv-app/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ shared_library("jni") {
"java/ChannelManager.cpp",
"java/ChannelManager.h",
"java/ClusterChangeAttribute.cpp",
"java/ContentAppAttributeDelegate.cpp",
"java/ContentAppAttributeDelegate.h",
"java/ContentAppCommandDelegate.cpp",
"java/ContentAppCommandDelegate.h",
"java/ContentLauncherManager.cpp",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,19 @@
*/

#include "AppContentLauncherManager.h"
#include "../../java/ContentAppCommandDelegate.h"
#include "../../java/ContentAppAttributeDelegate.h"
#include <json/json.h>

using namespace std;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::DataModel;
using namespace chip::app::Clusters::ContentLauncher;
using ContentAppCommandDelegate = chip::AppPlatform::ContentAppCommandDelegate;
using ContentAppAttributeDelegate = chip::AppPlatform::ContentAppAttributeDelegate;

AppContentLauncherManager::AppContentLauncherManager(ContentAppCommandDelegate commandDelegate, list<std::string> acceptHeaderList,
uint32_t supportedStreamingProtocols) :
mCommandDelegate(commandDelegate)
AppContentLauncherManager::AppContentLauncherManager(ContentAppAttributeDelegate attributeDelegate,
list<std::string> acceptHeaderList, uint32_t supportedStreamingProtocols) :
mAttributeDelegate(attributeDelegate)
{
mAcceptHeaderList = acceptHeaderList;
mSupportedStreamingProtocols = supportedStreamingProtocols;
Expand Down Expand Up @@ -73,18 +74,41 @@ void AppContentLauncherManager::HandleLaunchUrl(CommandResponseHelper<LaunchResp
string displayStringString(displayString.data(), displayString.size());

// TODO: Insert code here

const char * resStr = mCommandDelegate.sendCommand(mEndpointId, contentUrlString);

LaunchResponseType response;
response.data = chip::MakeOptional(CharSpan::fromCharString(resStr));
response.data = chip::MakeOptional(CharSpan::fromCharString("Success"));
response.status = ContentLauncher::ContentLaunchStatusEnum::kSuccess;
helper.Success(response);
}

CHIP_ERROR AppContentLauncherManager::HandleGetAcceptHeaderList(AttributeValueEncoder & aEncoder)
{
ChipLogProgress(Zcl, "AppContentLauncherManager::HandleGetAcceptHeaderList");
chip::app::ConcreteReadAttributePath aPath(mEndpointId, chip::app::Clusters::ContentLauncher::Id,
chip::app::Clusters::ContentLauncher::Attributes::AcceptHeader::Id);
const char * resStr = mAttributeDelegate.Read(aPath);
ChipLogProgress(Zcl, "AppContentLauncherManager::HandleGetSupportedStreamingProtocols response %s", resStr);

if (resStr != nullptr && *resStr != 0)
{
Json::Reader reader;
Json::Value value;
if (reader.parse(resStr, value))
{
std::string attrId = to_string(chip::app::Clusters::ContentLauncher::Attributes::AcceptHeader::Id);
ChipLogProgress(
Zcl, "AppContentLauncherManager::HandleGetSupportedStreamingProtocols response parsing done. reading attr %s",
attrId.c_str());
if (value[attrId].isArray())
{
mAcceptHeaderList.clear();
for (Json::Value & entry : value[attrId])
{
mAcceptHeaderList.push_back(entry.asString());
}
}
}
}

return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR {
for (std::string & entry : mAcceptHeaderList)
{
Expand All @@ -98,6 +122,30 @@ CHIP_ERROR AppContentLauncherManager::HandleGetAcceptHeaderList(AttributeValueEn
uint32_t AppContentLauncherManager::HandleGetSupportedStreamingProtocols()
{
ChipLogProgress(Zcl, "AppContentLauncherManager::HandleGetSupportedStreamingProtocols");
chip::app::ConcreteReadAttributePath aPath(mEndpointId, chip::app::Clusters::ContentLauncher::Id,
chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::Id);
const char * resStr = mAttributeDelegate.Read(aPath);
ChipLogProgress(Zcl, "AppContentLauncherManager::HandleGetSupportedStreamingProtocols response %s", resStr);

if (resStr == nullptr || *resStr == 0)
{
return mSupportedStreamingProtocols;
}

Json::Reader reader;
Json::Value value;
if (!reader.parse(resStr, value))
{
return mSupportedStreamingProtocols;
}
std::string attrId = to_string(chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::Id);
ChipLogProgress(Zcl, "AppContentLauncherManager::HandleGetSupportedStreamingProtocols response parsing done. reading attr %s",
attrId.c_str());
if (!value[attrId].empty())
{
uint32_t supportedStreamingProtocols = static_cast<uint32_t>(value[attrId].asInt());
mSupportedStreamingProtocols = supportedStreamingProtocols;
}
return mSupportedStreamingProtocols;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,24 @@

#pragma once

#include "../../java/ContentAppCommandDelegate.h"
#include "../../java/ContentAppAttributeDelegate.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app/clusters/content-launch-server/content-launch-server.h>

using chip::CharSpan;
using chip::EndpointId;
using chip::app::AttributeValueEncoder;
using chip::app::CommandResponseHelper;
using ContentLauncherDelegate = chip::app::Clusters::ContentLauncher::Delegate;
using LaunchResponseType = chip::app::Clusters::ContentLauncher::Commands::LaunchResponse::Type;
using ParameterType = chip::app::Clusters::ContentLauncher::Structs::Parameter::DecodableType;
using BrandingInformationType = chip::app::Clusters::ContentLauncher::Structs::BrandingInformation::Type;
using ContentAppCommandDelegate = chip::AppPlatform::ContentAppCommandDelegate;
using ContentLauncherDelegate = chip::app::Clusters::ContentLauncher::Delegate;
using LaunchResponseType = chip::app::Clusters::ContentLauncher::Commands::LaunchResponse::Type;
using ParameterType = chip::app::Clusters::ContentLauncher::Structs::Parameter::DecodableType;
using BrandingInformationType = chip::app::Clusters::ContentLauncher::Structs::BrandingInformation::Type;
using ContentAppAttributeDelegate = chip::AppPlatform::ContentAppAttributeDelegate;

class AppContentLauncherManager : public ContentLauncherDelegate
{
public:
AppContentLauncherManager(ContentAppCommandDelegate commandDelegate, std::list<std::string> acceptHeaderList,
AppContentLauncherManager(ContentAppAttributeDelegate attributeDelegate, std::list<std::string> acceptHeaderList,
uint32_t supportedStreamingProtocols);

void HandleLaunchContent(CommandResponseHelper<LaunchResponseType> & helper,
Expand All @@ -56,8 +56,9 @@ class AppContentLauncherManager : public ContentLauncherDelegate

private:
EndpointId mEndpointId;
ContentAppCommandDelegate mCommandDelegate;

// TODO: set this based upon meta data from app
uint32_t mDynamicEndpointFeatureMap = 3;

ContentAppAttributeDelegate mAttributeDelegate;
};
4 changes: 2 additions & 2 deletions examples/tv-app/android/java/AppImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ ContentApp * ContentAppFactoryImpl::LoadContentApp(const CatalogVendorApp & vend
return nullptr;
}

EndpointId ContentAppFactoryImpl::AddContentApp(ContentAppImpl * app)
EndpointId ContentAppFactoryImpl::AddContentApp(ContentAppImpl * app, jobject contentAppEndpointManager)
{
DataVersion dataVersionBuf[ArraySize(contentAppClusters)];
EndpointId epId = ContentAppPlatform::GetInstance().AddContentApp(app, &contentAppEndpoint, Span<DataVersion>(dataVersionBuf),
Expand Down Expand Up @@ -471,7 +471,7 @@ EndpointId AddContentApp(const char * szVendorName, uint16_t vendorId, const cha
ContentAppImpl * app =
new ContentAppImpl(szVendorName, vendorId, szApplicationName, productId, szApplicationVersion, "20202021", manager);
ChipLogProgress(DeviceLayer, "AppImpl: AddContentApp vendorId=%d applicationName=%s ", vendorId, szApplicationName);
return gFactory.AddContentApp(app);
return gFactory.AddContentApp(app, manager);
#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
return 0;
}
Expand Down
8 changes: 4 additions & 4 deletions examples/tv-app/android/java/AppImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
#include "../include/target-navigator/TargetNavigatorManager.h"
#include "ChannelManager.h"
#include "CommissionerMain.h"
#include "ContentAppCommandDelegate.h"
#include "ContentAppAttributeDelegate.h"
#include "KeypadInputManager.h"
#include "MediaPlaybackManager.h"
#include "MyUserPrompter-JNI.h"
Expand Down Expand Up @@ -72,7 +72,7 @@ using KeypadInputDelegate = app::Clusters::KeypadInput::Delegate;
using MediaPlaybackDelegate = app::Clusters::MediaPlayback::Delegate;
using TargetNavigatorDelegate = app::Clusters::TargetNavigator::Delegate;
using SupportedStreamingProtocol = app::Clusters::ContentLauncher::SupportedStreamingProtocol;
using ContentAppCommandDelegate = chip::AppPlatform::ContentAppCommandDelegate;
using ContentAppAttributeDelegate = chip::AppPlatform::ContentAppAttributeDelegate;

static const int kCatalogVendorId = CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID;

Expand All @@ -86,7 +86,7 @@ class DLL_EXPORT ContentAppImpl : public ContentApp
const char * szApplicationVersion, const char * setupPIN, jobject manager) :
mApplicationBasicDelegate(kCatalogVendorId, BuildAppId(vendorId), szVendorName, vendorId, szApplicationName, productId,
szApplicationVersion),
mAccountLoginDelegate(setupPIN), mContentLauncherDelegate(ContentAppCommandDelegate(manager), { "image/*", "video/*" },
mAccountLoginDelegate(setupPIN), mContentLauncherDelegate(ContentAppAttributeDelegate(manager), { "image/*", "video/*" },
to_underlying(SupportedStreamingProtocol::kDash) |
to_underlying(SupportedStreamingProtocol::kHls)),
mTargetNavigatorDelegate({ "home", "search", "info", "guide", "menu" }, 0){};
Expand Down Expand Up @@ -131,7 +131,7 @@ class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory
// Lookup ContentApp for this catalog id / app id and load it
ContentApp * LoadContentApp(const CatalogVendorApp & vendorApp) override;

EndpointId AddContentApp(ContentAppImpl * app);
EndpointId AddContentApp(ContentAppImpl * app, jobject contentAppEndpointManager);

void SendTestMessage(EndpointId epID, const char * message);

Expand Down

0 comments on commit 1089933

Please sign in to comment.