diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/fragments/TerminalFragment.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/fragments/TerminalFragment.java index db2336dbe259b9..660025e76c2a83 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/fragments/TerminalFragment.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/fragments/TerminalFragment.java @@ -22,15 +22,15 @@ public class TerminalFragment extends Fragment { private AppPlatformShellCommands shellCommands; private static String TERMINAL_INSTRUCTIONS = - "add [] Add app with given vendor ID [1, 2, 9050]. Usage: app add 9050\r\n" - + "remove Remove app at given endpoint [6, 7, etc]. Usage: app remove 6\r\n" - + "setpin Set pincode for app with given endpoint ID. Usage: app setpin 6 34567890\r\n" + "add [] Add app with given vendor ID [1, 2, 9050]. Usage: add 9050\r\n" + + "remove Remove app at given endpoint [6, 7, etc]. Usage: remove 6\r\n" + + "setpin Set pincode for app with given endpoint ID. Usage: setpin 6 34567890\r\n" + "commission Commission given udc-entry using given pincode from corresponding app. Usage:" - + "app commission 0\r\n" - + "add-admin-vendor Add vendor ID to list which will receive admin privileges. Usage: app " + + "commission 0\r\n" + + "add-admin-vendor Add vendor ID to list which will receive admin privileges. Usage: " + "add-admin-vendor 65521\r\n" - + "print-app-access Print all ACLs for app platform fabric. Usage: app print-app-access\r\n" - + "remove-app-access Remove all ACLs for app platform fabric. Usage: app remove-app-access\r\n"; + + "print-app-access Print all ACLs for app platform fabric. Usage: print-app-access\r\n" + + "remove-app-access Remove all ACLs for app platform fabric. Usage: remove-app-access\r\n"; public TerminalFragment() { // Required empty public constructor @@ -80,7 +80,7 @@ public void onResume() { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setMessage(response).setTitle("Response").create().show(); + builder.setMessage(response).create().show(); }); } } diff --git a/examples/tv-app/android/BUILD.gn b/examples/tv-app/android/BUILD.gn index 7e0420b81ced6e..2e646454c6fc72 100644 --- a/examples/tv-app/android/BUILD.gn +++ b/examples/tv-app/android/BUILD.gn @@ -35,8 +35,6 @@ shared_library("jni") { "include/cluster-init.cpp", "include/content-launcher/AppContentLauncherManager.cpp", "include/content-launcher/AppContentLauncherManager.h", - "include/endpoint-configuration/EndpointConfigurationStorage.cpp", - "include/endpoint-configuration/EndpointConfigurationStorage.h", "include/target-navigator/TargetNavigatorManager.cpp", "include/target-navigator/TargetNavigatorManager.h", "java/AppImpl.cpp", @@ -115,10 +113,12 @@ android_library("java") { "java/src/com/matter/tv/server/tvapp/Clusters.java", "java/src/com/matter/tv/server/tvapp/ContentAppEndpointManager.java", "java/src/com/matter/tv/server/tvapp/ContentLaunchBrandingInformation.java", + "java/src/com/matter/tv/server/tvapp/ContentLaunchEntry.java", "java/src/com/matter/tv/server/tvapp/ContentLaunchManager.java", "java/src/com/matter/tv/server/tvapp/ContentLaunchManagerStub.java", "java/src/com/matter/tv/server/tvapp/ContentLaunchResponse.java", "java/src/com/matter/tv/server/tvapp/ContentLaunchSearchParameter.java", + "java/src/com/matter/tv/server/tvapp/ContentLaunchSearchParameterType.java", "java/src/com/matter/tv/server/tvapp/DACProvider.java", "java/src/com/matter/tv/server/tvapp/DACProviderStub.java", "java/src/com/matter/tv/server/tvapp/DeviceEventProvider.java", diff --git a/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.cpp b/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.cpp deleted file mode 100644 index af4eb313573713..00000000000000 --- a/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * 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 "EndpointConfigurationStorage.h" -#include -#include - -constexpr const char kEndpointConfigurationPath[] = "/tmp/chip_tv_config.ini"; - -CHIP_ERROR EndpointConfigurationStorage::Init() -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - std::ifstream ifs; - ifs.open(kEndpointConfigurationPath, std::ifstream::in); - if (!ifs.good()) - { - ifs.open(kEndpointConfigurationPath, std::ifstream::in); - } - VerifyOrExit(ifs.is_open(), err = CHIP_ERROR_OPEN_FAILED); - - endpointConfig.parse(ifs); - ifs.close(); - -exit: - return err; -} - -CHIP_ERROR EndpointConfigurationStorage::get(std::string sectionName, const char * key, char * value, uint16_t & size) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - std::string iniValue; - size_t iniValueLength = 0; - - auto section = endpointConfig.sections[sectionName]; - auto it = section.find(key); - VerifyOrExit(it != section.end(), err = CHIP_ERROR_KEY_NOT_FOUND); - VerifyOrExit(inipp::extract(section[key], iniValue), err = CHIP_ERROR_INVALID_ARGUMENT); - - iniValueLength = iniValue.size(); - VerifyOrExit(iniValueLength <= static_cast(size) - 1, err = CHIP_ERROR_BUFFER_TOO_SMALL); - - iniValueLength = iniValue.copy(value, iniValueLength); - value[iniValueLength] = '\0'; - -exit: - return err; -} - -CHIP_ERROR EndpointConfigurationStorage::get(std::string sectionName, const char * key, uint16_t & value) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - auto section = endpointConfig.sections[sectionName]; - auto it = section.find(key); - VerifyOrExit(it != section.end(), err = CHIP_ERROR_KEY_NOT_FOUND); - VerifyOrExit(inipp::extract(section[key], value), err = CHIP_ERROR_INVALID_ARGUMENT); - -exit: - return err; -} diff --git a/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.h b/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.h deleted file mode 100644 index cea787b1bdda0c..00000000000000 --- a/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * 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. - */ - -#pragma once - -#include -#include -#include - -class EndpointConfigurationStorage -{ -public: - CHIP_ERROR Init(); - CHIP_ERROR get(std::string sectionName, const char * key, char * value, uint16_t & size); - CHIP_ERROR get(std::string sectionName, const char * key, uint16_t & value); - - static EndpointConfigurationStorage & GetInstance() - { - static EndpointConfigurationStorage instance; - return instance; - } - -private: - inipp::Ini endpointConfig; -}; diff --git a/examples/tv-app/android/include/endpoint-configuration/chip_tv_config.ini b/examples/tv-app/android/include/endpoint-configuration/chip_tv_config.ini deleted file mode 100644 index 501f26a1b30c04..00000000000000 --- a/examples/tv-app/android/include/endpoint-configuration/chip_tv_config.ini +++ /dev/null @@ -1,46 +0,0 @@ -[endpoint1] -type=videoPlayer -macAddress=00:00:00:00:00 - -[endpoint2] -type=speaker - -[endpoint3] -type=app -vendorName=exampleVendorName1 -vendorId=1 -name=exampleName1 -productId=1 -id=1 -catalogVendorId=1 -version=exampleVersion - -[endpoint4] -type=app -vendorName=exampleVendorName2 -vendorId=2 -name=exampleName2 -productId=2 -id=2 -catalogVendorId=2 -version=exampleVersion - -[endpoint5] -type=app -vendorName=exampleVendorName3 -vendorId=3 -name=exampleName3 -productId=3 -id= 3 -catalogVendorId=3 -version=exampleVersion - -[endpoint6] -type=app -vendorName=exampleVendorName4 -vendorId=4 -name=exampleName4 -productId=4 -id=4 -catalogVendorId=4 -version=exampleVersion \ No newline at end of file diff --git a/examples/tv-app/android/include/level-control/LevelControl.cpp b/examples/tv-app/android/include/level-control/LevelControl.cpp deleted file mode 100644 index 2b53d45a7f737e..00000000000000 --- a/examples/tv-app/android/include/level-control/LevelControl.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * - * 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 - -#include -#include -#include -#include -#include - -using namespace chip; - -#define MAX_LEVEL 99 -#define MIN_LEVEL 1 - -typedef struct -{ - CommandId commandId; - uint16_t storedLevel; - bool increasing; -} EmberAfLevelControlState; - -static EmberAfLevelControlState stateTable[EMBER_AF_LEVEL_CONTROL_CLUSTER_SERVER_ENDPOINT_COUNT]; - -static EmberAfLevelControlState * getState(EndpointId endpoint) -{ - uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_LEVEL_CONTROL_CLUSTER_ID); - return (ep == 0xFF ? NULL : &stateTable[ep]); -} - -static void stepHandler(CommandId commandId, uint8_t stepMode, uint8_t stepSize, uint16_t transitionTimeDs, uint8_t optionMask, - uint8_t optionOverride) -{ - - EndpointId endpoint = emberAfCurrentEndpoint(); - EmberAfLevelControlState * state = getState(endpoint); - EmberAfStatus status; - uint8_t currentLevel; - - status = emberAfReadServerAttribute(endpoint, ZCL_LEVEL_CONTROL_CLUSTER_ID, ZCL_CURRENT_LEVEL_ATTRIBUTE_ID, - (uint8_t *) ¤tLevel, sizeof(currentLevel)); - - if (status != EMBER_ZCL_STATUS_SUCCESS) - { - emberAfLevelControlClusterPrintln("ERR: reading current level %x", status); - goto send_default_response; - } - - switch (stepMode) - { - case EMBER_ZCL_STEP_MODE_UP: - state->increasing = true; - if (MAX_LEVEL >= currentLevel + stepSize) - { - currentLevel = currentLevel + stepSize; - } - break; - case EMBER_ZCL_STEP_MODE_DOWN: - state->increasing = false; - if (MIN_LEVEL <= currentLevel - stepSize) - { - currentLevel = currentLevel - stepSize; - } - break; - default: - status = EMBER_ZCL_STATUS_INVALID_FIELD; - goto send_default_response; - } - - if (currentLevel != state->storedLevel) - { - int volumeIncrementCount = abs(currentLevel - state->storedLevel); - for (int i = 0; i < volumeIncrementCount; ++i) - { - if (state->increasing) - { - ChipLogProgress(Zcl, "Volume UP"); - // TODO: Insert your code here to send volume up command - } - else - { - ChipLogProgress(Zcl, "Volume DOWN"); - // TODO: Insert your code here to send volume down command - } - } - status = emberAfWriteServerAttribute(endpoint, ZCL_LEVEL_CONTROL_CLUSTER_ID, ZCL_CURRENT_LEVEL_ATTRIBUTE_ID, - (uint8_t *) ¤tLevel, ZCL_INT8U_ATTRIBUTE_TYPE); - state->storedLevel = currentLevel; - ChipLogProgress(Zcl, "Setting volume to new level %d", state->storedLevel); - } - -send_default_response: - if (emberAfCurrentCommand()->apsFrame->clusterId == ZCL_LEVEL_CONTROL_CLUSTER_ID) - { - emberAfSendImmediateDefaultResponse(status); - } -} - -bool emberAfLevelControlClusterStepCallback(uint8_t stepMode, uint8_t stepSize, uint16_t transitionTime, uint8_t optionMask, - uint8_t optionOverride) -{ - stepHandler(ZCL_STEP_COMMAND_ID, stepMode, stepSize, transitionTime, optionMask, optionOverride); - return true; -} - -bool emberAfLevelControlClusterMoveCallback(unsigned char, unsigned char, unsigned char, unsigned char) -{ - ChipLogProgress(Zcl, "Not supported"); - return true; -} - -bool emberAfLevelControlClusterMoveToLevelCallback(unsigned char, unsigned short, unsigned char, unsigned char) -{ - ChipLogProgress(Zcl, "Not supported"); - return true; -} - -bool emberAfLevelControlClusterMoveToLevelWithOnOffCallback(unsigned char, unsigned short) -{ - ChipLogProgress(Zcl, "Not supported"); - return true; -} - -bool emberAfLevelControlClusterMoveWithOnOffCallback(unsigned char, unsigned char) -{ - ChipLogProgress(Zcl, "Not supported"); - return true; -} - -bool emberAfLevelControlClusterStopCallback(unsigned char, unsigned char) -{ - ChipLogProgress(Zcl, "Not supported"); - return true; -} - -bool emberAfLevelControlClusterStopWithOnOffCallback() -{ - ChipLogProgress(Zcl, "Not supported"); - return true; -} - -bool emberAfOnOffClusterLevelControlEffectCallback(unsigned char, bool) -{ - ChipLogProgress(Zcl, "Not supported"); - return true; -} - -bool emberAfLevelControlClusterServerInitCallback(unsigned char) -{ - ChipLogProgress(Zcl, "Not supported"); - return true; -} - -bool emberAfLevelControlClusterStepWithOnOffCallback(unsigned char, unsigned char, unsigned short) -{ - ChipLogProgress(Zcl, "Not supported"); - return true; -} - -bool emberAfLevelControlClusterServerTickCallback(unsigned char) -{ - ChipLogProgress(Zcl, "Not supported"); - return true; -} diff --git a/examples/tv-app/android/java/AppPlatformShellCommands-JNI.cpp b/examples/tv-app/android/java/AppPlatformShellCommands-JNI.cpp index 61418c1e6763d2..4a00a3663d62ec 100644 --- a/examples/tv-app/android/java/AppPlatformShellCommands-JNI.cpp +++ b/examples/tv-app/android/java/AppPlatformShellCommands-JNI.cpp @@ -44,12 +44,172 @@ using namespace chip::app::Clusters; static CHIP_ERROR pairApp(bool printHeader, size_t index) { - // TODO: add pair app + + if (printHeader) + { + char str[64]; + sprintf(str, "udc-commission %ld\r\n", (long) index); + strcat(response, str); + } + + DeviceCommissioner * commissioner = GetDeviceCommissioner(); + UDCClientState * state = commissioner->GetUserDirectedCommissioningServer()->GetUDCClients().GetUDCClientState(index); + if (state == nullptr) + { + char str[64]; + sprintf(str, "udc client[%d] null \r\n", index); + strcat(response, str); + } + else + { + ContentApp * app = ContentAppPlatform::GetInstance().LoadContentAppByClient(state->GetVendorId(), state->GetProductId()); + if (app == nullptr) + { + char str[64]; + sprintf(str, "no app found for vendor id=%d \r\n", state->GetVendorId()); + strcat(response, str); + return CHIP_ERROR_BAD_REQUEST; + } + + if (app->GetAccountLoginDelegate() == nullptr) + { + char str[64]; + sprintf(str, "no AccountLogin cluster for app with vendor id=%d \r\n", state->GetVendorId()); + strcat(response, str); + return CHIP_ERROR_BAD_REQUEST; + } + + char rotatingIdString[chip::Dnssd::kMaxRotatingIdLen * 2 + 1] = ""; + Encoding::BytesToUppercaseHexString(state->GetRotatingId(), state->GetRotatingIdLength(), rotatingIdString, + sizeof(rotatingIdString)); + + CharSpan rotatingIdSpan = CharSpan(rotatingIdString, strlen(rotatingIdString)); + + static const size_t kSetupPinSize = 12; + char setupPin[kSetupPinSize]; + + app->GetAccountLoginDelegate()->GetSetupPin(setupPin, kSetupPinSize, rotatingIdSpan); + std::string pinString(setupPin); + + char * eptr; + uint32_t pincode = (uint32_t) strtol(pinString.c_str(), &eptr, 10); + if (pincode == 0) + { + char str[64]; + sprintf(str, "udc no pin returned for vendor id=%d rotating ID=%s \r\n", state->GetVendorId(), rotatingIdString); + strcat(response, str); + return CHIP_ERROR_BAD_REQUEST; + } + + return CommissionerPairUDC(pincode, index); + } return CHIP_NO_ERROR; } +void DumpAccessControlEntry(const Access::AccessControl::Entry & entry) +{ + + CHIP_ERROR err; + + { + FabricIndex fabricIndex; + SuccessOrExit(err = entry.GetFabricIndex(fabricIndex)); + char str[64]; + sprintf(str, "fabricIndex: %u\n", fabricIndex); + strcat(response, str); + } + + { + Privilege privilege; + SuccessOrExit(err = entry.GetPrivilege(privilege)); + char str[64]; + sprintf(str, "privilege: %d\n", to_underlying(privilege)); + strcat(response, str); + } + + { + AuthMode authMode; + SuccessOrExit(err = entry.GetAuthMode(authMode)); + char str[64]; + sprintf(str, "authMode: %d\n", to_underlying(authMode)); + strcat(response, str); + } + + { + size_t count; + SuccessOrExit(err = entry.GetSubjectCount(count)); + if (count) + { + + char str[64]; + sprintf(str, "subjects: %u\n", static_cast(count)); + strcat(response, str); + + for (size_t i = 0; i < count; ++i) + { + NodeId subject; + SuccessOrExit(err = entry.GetSubject(i, subject)); + + char buffer[64]; + sprintf(buffer, " %u: 0x" ChipLogFormatX64, static_cast(i), ChipLogValueX64(subject)); + strcat(response, buffer); + } + } + } + + { + size_t count; + SuccessOrExit(err = entry.GetTargetCount(count)); + if (count) + { + + char str[64]; + sprintf(str, "\ntargets: %u\n", static_cast(count)); + strcat(response, str); + + for (size_t i = 0; i < count; ++i) + { + Access::AccessControl::Entry::Target target; + SuccessOrExit(err = entry.GetTarget(i, target)); + char buffer[64]; + if (target.flags & Access::AccessControl::Entry::Target::kCluster) + { + sprintf(buffer, " %u: cluster: 0x" ChipLogFormatMEI, static_cast(i), + ChipLogValueMEI(target.cluster)); + strcat(buffer, "\n"); + strcat(response, buffer); + } + if (target.flags & Access::AccessControl::Entry::Target::kEndpoint) + { + sprintf(buffer, " %u: endpoint: %u", static_cast(i), target.endpoint); + strcat(buffer, "\n"); + strcat(response, buffer); + } + if (target.flags & Access::AccessControl::Entry::Target::kDeviceType) + { + sprintf(buffer, " %u: deviceType: 0x" ChipLogFormatMEI, static_cast(i), + ChipLogValueMEI(target.deviceType)); + strcat(buffer, "\n"); + strcat(response, buffer); + } + } + } + } + + strcat(response, "----- END ENTRY -----\n"); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "DumpAccessControlEntry: dump failed %" CHIP_ERROR_FORMAT, err.Format()); + strcpy(response, "Error occurred"); + } +} + char * AppPlatformHandler(int argc, char ** argv) { + CHIP_ERROR err; + if (argc == 0 || strcmp(argv[0], "help") == 0) { strcpy(response, "check usage instructions on the UI"); @@ -94,6 +254,19 @@ char * AppPlatformHandler(int argc, char ** argv) return response; } + else if (strcmp(argv[0], "print-app-access") == 0) + { + Access::AccessControl::EntryIterator iterator; + SuccessOrExit(err = Access::GetAccessControl().Entries(GetDeviceCommissioner()->GetFabricIndex(), iterator)); + // clear entry + strcpy(response, ""); + Access::AccessControl::Entry entry; + while (iterator.Next(entry) == CHIP_NO_ERROR) + { + DumpAccessControlEntry(entry); + } + return response; + } else if (strcmp(argv[0], "remove-app-access") == 0) { Access::GetAccessControl().DeleteAllEntriesForFabric(GetDeviceCommissioner()->GetFabricIndex()); @@ -166,8 +339,7 @@ char * AppPlatformHandler(int argc, char ** argv) } char * eptr; size_t index = (size_t) strtol(argv[1], &eptr, 10); - pairApp(true, index); - strcpy(response, "no supported atm"); + SuccessOrExit(err = pairApp(true, index)); return response; } else @@ -176,6 +348,10 @@ char * AppPlatformHandler(int argc, char ** argv) return response; } return response; +exit: + ChipLogError(DeviceLayer, "Error: %" CHIP_ERROR_FORMAT, err.Format()); + strcpy(response, "Error occurred"); + return response; } #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ChannelInfo.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ChannelInfo.java index 4fd5bbf36ddfec..93ad0afef5539d 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ChannelInfo.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ChannelInfo.java @@ -19,9 +19,9 @@ public class ChannelInfo { - public static final int kSuccess = -1; // todo: what will be the value of no error? - public static final int kMultipleMatches = 0; - public static final int kNoMatches = 1; + public static final int kSuccess = 0; + public static final int kMultipleMatches = 1; + public static final int kNoMatches = 2; public int status; public int majorNumber; diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ChannelManagerStub.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ChannelManagerStub.java index 23165c6bd34203..a90e1838778611 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ChannelManagerStub.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ChannelManagerStub.java @@ -18,34 +18,35 @@ package com.matter.tv.server.tvapp; import android.util.Log; +import java.util.ArrayList; +import java.util.List; public class ChannelManagerStub implements ChannelManager { private static final String TAG = ChannelManagerStub.class.getSimpleName(); private int endpoint; - private int mCurrentChannel = 0; + private int currentChannelIndex = 0; + private ChannelInfo currentChannel; + private ChannelInfo[] channelList = { + new ChannelInfo(6, 0, "ABC", "KAAL-TV", "KAAL"), + new ChannelInfo(9, 1, "PBS", "KCTS-TV", "KCTS"), + new ChannelInfo(9, 2, "PBS Kids", "KCTS-TV", "KCTS"), + new ChannelInfo(9, 3, "World Channel", "KCTS-TV", "KCTS") + }; public ChannelManagerStub(int endpoint) { this.endpoint = endpoint; + this.currentChannel = channelList[currentChannelIndex]; } @Override public ChannelInfo[] getChannelList() { - ChannelInfo ChannelInfo1 = new ChannelInfo(1, 11, "HDMI1", "callSign1", "affiliateCallSign1"); - ChannelInfo ChannelInfo2 = new ChannelInfo(2, 22, "HDMI2", null, ""); - Log.d(TAG, "getChannelList at " + endpoint); - return new ChannelInfo[] {ChannelInfo1, ChannelInfo2}; + return channelList; } @Override public ChannelLineupInfo getLineup() { - // for null lineup test - if (mCurrentChannel == 100) { - Log.d(TAG, "getChannelLineup: null at " + endpoint); - return null; - } - - ChannelLineupInfo lineupInfo = new ChannelLineupInfo("operator", "lineup", "postalCode"); + ChannelLineupInfo lineupInfo = new ChannelLineupInfo("Comcast", "Comcast King County", "98052"); Log.d(TAG, "getChannelLineup: " + lineupInfo + " at " + endpoint); return lineupInfo; } @@ -53,23 +54,51 @@ public ChannelLineupInfo getLineup() { @Override public ChannelInfo getCurrentChannel() { Log.d(TAG, "getCurrentChannel: at " + endpoint); - // for null channel test - if (mCurrentChannel == 100) { - return null; - } + return channelList[currentChannelIndex]; + } + + boolean isChannelMatched(ChannelInfo channel, String match) { + String number = channel.majorNumber + "." + channel.minorNumber; + boolean nameMatch = channel.name.equals(match); + boolean affiliateCallSignMatch = channel.affiliateCallSign.equals(match); + boolean callSignMatch = channel.callSign.equals(match); + boolean numberMatch = number.equals(match); - return new ChannelInfo(1, 1, "HDMI", "callSign", "affiliateCallSign"); + return affiliateCallSignMatch || callSignMatch || nameMatch || numberMatch; } @Override public ChannelInfo changeChannel(String match) { Log.d(TAG, "changeChannel: " + match + " at " + endpoint); - if ("no".equals(match)) { - return new ChannelInfo(ChannelInfo.kNoMatches); - } else if ("multiple".equals(match)) { + List matchedList = new ArrayList<>(); + int index = 0; + + for (ChannelInfo channel : channelList) { + // verify if CharSpan matches channel name + // or callSign or affiliateCallSign or majorNumber.minorNumber + if (isChannelMatched(channel, match)) { + matchedList.add(channel); + break; + } + ; + // use index to set current channel at the end + ++index; + } + + if (matchedList.size() > 1) { + // Error: Multiple matches + Log.d(TAG, "multiple matches"); return new ChannelInfo(ChannelInfo.kMultipleMatches); + } else if (matchedList.size() == 0) { + // Error: No match + Log.d(TAG, "no matches"); + return new ChannelInfo(ChannelInfo.kNoMatches); } else { - return new ChannelInfo(1, 1, "HDMI", "callSign", "affiliateCallSign"); + Log.d(TAG, "success 1 match"); + // Success: 1 match + currentChannel = channelList[index]; + currentChannelIndex = index; + return channelList[index]; } } @@ -84,23 +113,33 @@ public boolean changeChannelByNumber(int majorNumber, int minorNumber) { + " at " + endpoint); - mCurrentChannel = majorNumber; + boolean channelChanged = false; + int index = 0; - // for failed test - if (majorNumber == 1 && minorNumber == 1) { - return false; + for (ChannelInfo channel : channelList) { + // verify if major & minor matches one of the channel from the list + if (channel.majorNumber == majorNumber && channel.minorNumber == minorNumber) { + // verify if channel changed by comparing values of current channel with the requested + // channel + if (channel.majorNumber != currentChannel.majorNumber + || channel.minorNumber != currentChannel.minorNumber) { + channelChanged = true; + currentChannelIndex = index; + currentChannel = channelList[index]; + } + } + ++index; } - return true; + return channelChanged; } @Override public boolean skipChannel(int count) { Log.d(TAG, "skipChannel: count = " + count + " at " + endpoint); - // for failed test - if (count == 100) { - return false; - } + int newChannelIndex = (count + currentChannelIndex) % channelList.length; + currentChannelIndex = newChannelIndex; + currentChannel = channelList[newChannelIndex]; return true; } } diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchEntry.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchEntry.java new file mode 100644 index 00000000000000..ea44aa752e652b --- /dev/null +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchEntry.java @@ -0,0 +1,13 @@ +package com.matter.tv.server.tvapp; + +public class ContentLaunchEntry { + /** Name of the content that customer will see on the screen */ + public String name; + /** List of possible query matches */ + public ContentLaunchSearchParameter[] parameters; + + public ContentLaunchEntry(String name, ContentLaunchSearchParameter[] parameters) { + this.name = name; + this.parameters = parameters; + } +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchManagerStub.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchManagerStub.java index d138f12b7be258..4bdee5ed2bfee1 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchManagerStub.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchManagerStub.java @@ -8,6 +8,30 @@ public class ContentLaunchManagerStub implements ContentLaunchManager { private int endpoint; + private ContentLaunchSearchParameter[] tvShowSearchList = { + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.ACTOR, "Gaby sHofmann"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.CHANNEL, "PBS"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.CHARACTER, "Snow White"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.DIRECTOR, "Spike Lee"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.FRANCHISE, "Star Wars"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.GENRE, "Horror"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.POPULARITY, "Popularity"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.PROVIDER, "Netfxlix"), + }; + + private ContentLaunchSearchParameter[] sportsShowSearchList = { + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.EVENT, "Football games"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.LEAGUE, "NCAA"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.SPORT, "football"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.SPORTS_TEAM, "Arsenal"), + new ContentLaunchSearchParameter(ContentLaunchSearchParameterType.TYPE, "TVSeries"), + }; + + private ContentLaunchEntry[] entries = { + new ContentLaunchEntry("Sports Example", sportsShowSearchList), + new ContentLaunchEntry("TV Show Example", tvShowSearchList) + }; + public ContentLaunchManagerStub(int endpoint) { this.endpoint = endpoint; } @@ -33,9 +57,19 @@ public ContentLaunchResponse launchContent( ContentLaunchSearchParameter[] search, boolean autoplay, String data) { Log.d(TAG, "launchContent:" + data + " autoplay=" + autoplay + " at " + endpoint); - if (search != null && search.length > 0) { - Log.d(TAG, " TEST CASE found match=Example TV Show"); - } else { + boolean found = false; + for (ContentLaunchEntry entry : entries) { + for (ContentLaunchSearchParameter parameter : entry.parameters) { + for (ContentLaunchSearchParameter query : search) { + if (query.type == parameter.type && query.data.equals(parameter.data)) { + Log.d(TAG, " TEST CASE found match=" + entry.name); + found = true; + } + } + } + } + + if (!found) { Log.d(TAG, " TEST CASE did not find a match"); } diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchSearchParameter.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchSearchParameter.java index c0e00826de8576..81076bd33d4285 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchSearchParameter.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchSearchParameter.java @@ -4,64 +4,12 @@ public class ContentLaunchSearchParameter { - /** Actor represents an actor credited in video media content; for example, "Gaby sHoffman" */ - public static final int TYPE_ACTOR = 0; - - /** Channel represents the identifying data for a television channel; for example, "PBS" */ - public static final int TYPE_CHANNEL = 1; - - /** A character represented in video media content; for example, "Snow White" */ - public static final int TYPE_CHARACTER = 2; - - /** A director of the video media content; for example, "Spike Lee" */ - public static final int TYPE_DIRECTOR = 3; - - /** - * An event is a reference to a type of event; examples would include sports, music, or other - * types of events. For example, searching for "Football games" would search for a 'game' event - * entity and a 'football' sport entity. - */ - public static final int TYPE_EVENT = 4; - - /** - * A franchise is a video entity which can represent a number of video entities, like movies or TV - * shows. For example, take the fictional franchise "Intergalactic Wars" which represents a - * collection of movie trilogies, as well as animated and live action TV shows. This entity type - * was introduced to account for requests by customers such as "Find Intergalactic Wars movies", - * which would search for all 'Intergalactic Wars' programs of the MOVIE MediaType, rather than - * attempting to match to a single title. - */ - public static final int TYPE_FRANCHISE = 5; - - /** Genre represents the genre of video media content such as action, drama or comedy. */ - public static final int TYPE_GENRE = 6; - - /** League represents the categorical information for a sporting league; for example, "NCAA" */ - public static final int TYPE_LEAGUE = 7; - - /** Popularity indicates whether the user asks for popular content. */ - public static final int TYPE_POPULARITY = 8; - - /** The provider (MSP) the user wants this media to be played on; for example, "Netflix". */ - public static final int TYPE_PROVIDER = 9; - - /** Sport represents the categorical information of a sport; for example, football */ - public static final int TYPE_SPORT = 10; - - /** - * SportsTeam represents the categorical information of a professional sports team; for example, - * "University of Washington Huskies" - */ - public static final int TYPE_SPORTS_TEAM = 11; - - /** - * The type of content requested. Supported types are "Movie", "MovieSeries", "TVSeries", - * "TVSeason", "TVEpisode", "SportsEvent", and "Video" - */ - public static final int TYPE_TYPE = 12; - + public ContentLaunchSearchParameter(ContentLaunchSearchParameterType type, String data) { + this.type = type; + this.data = data; + } /** content data type in TYPE_XXX */ - public int type; + public ContentLaunchSearchParameterType type; /** The entity value, which is a search string, ex. "Manchester by the Sea". */ public String data; diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchSearchParameterType.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchSearchParameterType.java new file mode 100644 index 00000000000000..3e6d1213b4f740 --- /dev/null +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/ContentLaunchSearchParameterType.java @@ -0,0 +1,48 @@ +package com.matter.tv.server.tvapp; + +public enum ContentLaunchSearchParameterType { + /** Actor represents an actor credited in video media content; for example, "Gaby sHoffman" */ + ACTOR, + /** Channel represents the identifying data for a television channel; for example, "PBS" */ + CHANNEL, + /** A character represented in video media content; for example, "Snow White" */ + CHARACTER, + /** A director of the video media content; for example, "Spike Lee" */ + DIRECTOR, + /** + * An event is a reference to a type of event; examples would include sports, music, or other + * types of events. For example, searching for "Football games" would search for a 'game' event + * entity and a 'football' sport entity. + */ + EVENT, + /** + * A franchise is a video entity which can represent a number of video entities, like movies or TV + * shows. For example, take the fictional franchise "Intergalactic Wars" which represents a + * collection of movie trilogies, as well as animated and live action TV shows. This entity type + * was introduced to account for requests by customers such as "Find Intergalactic Wars movies", + * which would search for all 'Intergalactic Wars' programs of the MOVIE MediaType, rather than + * attempting to match to a single title. + */ + FRANCHISE, + /** Genre represents the genre of video media content such as action, drama or comedy. */ + GENRE, + /** League represents the categorical information for a sporting league; for example, "NCAA" */ + LEAGUE, + /** Popularity indicates whether the user asks for popular content. */ + POPULARITY, + /** The provider (MSP) the user wants this media to be played on; for example, "Netflix". */ + PROVIDER, + /** Sport represents the categorical information of a sport; for example, football */ + SPORT, + /** + * SportsTeam represents the categorical information of a professional sports team; for example, + * "University of Washington Huskies" + */ + SPORTS_TEAM, + /** + * The type of content requested. Supported types are "Movie", "MovieSeries", "TVSeries", + * "TVSeason", "TVEpisode", "SportsEvent", and "Video" + */ + TYPE, + UNKNOWN +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MediaInputManagerStub.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MediaInputManagerStub.java index 3f1bf3db1601d3..3064a1b0f5af65 100755 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MediaInputManagerStub.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MediaInputManagerStub.java @@ -32,17 +32,19 @@ public MediaInputManagerStub(int endpoint) { info[0] = new MediaInputInfo(); info[0].name = "HDMI 1"; - info[0].description = "Living room Playstation"; + info[0].description = "High-Definition Multimedia Interface"; info[0].index = 0; info[0].type = MediaInputInfo.INPUT_TYPE_HDMI; info[1] = new MediaInputInfo(); info[1].name = "HDMI 2"; - info[1].description = "Living room XBox"; + info[1].description = "High-Definition Multimedia Interface"; info[1].index = 1; info[1].type = MediaInputInfo.INPUT_TYPE_HDMI; info[2] = new MediaInputInfo(); + info[2].name = "HDMI 3"; + info[2].description = "High-Definition Multimedia Interface"; info[2].index = 2; info[2].type = MediaInputInfo.INPUT_TYPE_HDMI; } diff --git a/examples/tv-app/linux/BUILD.gn b/examples/tv-app/linux/BUILD.gn index e492d26d0a59e4..945473c835c1b4 100644 --- a/examples/tv-app/linux/BUILD.gn +++ b/examples/tv-app/linux/BUILD.gn @@ -58,8 +58,6 @@ executable("chip-tv-app") { "include/cluster-init.cpp", "include/content-launcher/ContentLauncherManager.cpp", "include/content-launcher/ContentLauncherManager.h", - "include/endpoint-configuration/EndpointConfigurationStorage.cpp", - "include/endpoint-configuration/EndpointConfigurationStorage.h", "include/keypad-input/KeypadInputManager.cpp", "include/keypad-input/KeypadInputManager.h", "include/low-power/LowPowerManager.cpp", diff --git a/examples/tv-app/linux/include/endpoint-configuration/EndpointConfigurationStorage.cpp b/examples/tv-app/linux/include/endpoint-configuration/EndpointConfigurationStorage.cpp deleted file mode 100644 index af4eb313573713..00000000000000 --- a/examples/tv-app/linux/include/endpoint-configuration/EndpointConfigurationStorage.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * 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 "EndpointConfigurationStorage.h" -#include -#include - -constexpr const char kEndpointConfigurationPath[] = "/tmp/chip_tv_config.ini"; - -CHIP_ERROR EndpointConfigurationStorage::Init() -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - std::ifstream ifs; - ifs.open(kEndpointConfigurationPath, std::ifstream::in); - if (!ifs.good()) - { - ifs.open(kEndpointConfigurationPath, std::ifstream::in); - } - VerifyOrExit(ifs.is_open(), err = CHIP_ERROR_OPEN_FAILED); - - endpointConfig.parse(ifs); - ifs.close(); - -exit: - return err; -} - -CHIP_ERROR EndpointConfigurationStorage::get(std::string sectionName, const char * key, char * value, uint16_t & size) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - std::string iniValue; - size_t iniValueLength = 0; - - auto section = endpointConfig.sections[sectionName]; - auto it = section.find(key); - VerifyOrExit(it != section.end(), err = CHIP_ERROR_KEY_NOT_FOUND); - VerifyOrExit(inipp::extract(section[key], iniValue), err = CHIP_ERROR_INVALID_ARGUMENT); - - iniValueLength = iniValue.size(); - VerifyOrExit(iniValueLength <= static_cast(size) - 1, err = CHIP_ERROR_BUFFER_TOO_SMALL); - - iniValueLength = iniValue.copy(value, iniValueLength); - value[iniValueLength] = '\0'; - -exit: - return err; -} - -CHIP_ERROR EndpointConfigurationStorage::get(std::string sectionName, const char * key, uint16_t & value) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - auto section = endpointConfig.sections[sectionName]; - auto it = section.find(key); - VerifyOrExit(it != section.end(), err = CHIP_ERROR_KEY_NOT_FOUND); - VerifyOrExit(inipp::extract(section[key], value), err = CHIP_ERROR_INVALID_ARGUMENT); - -exit: - return err; -} diff --git a/examples/tv-app/linux/include/endpoint-configuration/EndpointConfigurationStorage.h b/examples/tv-app/linux/include/endpoint-configuration/EndpointConfigurationStorage.h deleted file mode 100644 index cea787b1bdda0c..00000000000000 --- a/examples/tv-app/linux/include/endpoint-configuration/EndpointConfigurationStorage.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * 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. - */ - -#pragma once - -#include -#include -#include - -class EndpointConfigurationStorage -{ -public: - CHIP_ERROR Init(); - CHIP_ERROR get(std::string sectionName, const char * key, char * value, uint16_t & size); - CHIP_ERROR get(std::string sectionName, const char * key, uint16_t & value); - - static EndpointConfigurationStorage & GetInstance() - { - static EndpointConfigurationStorage instance; - return instance; - } - -private: - inipp::Ini endpointConfig; -}; diff --git a/examples/tv-app/linux/include/endpoint-configuration/chip_tv_config.ini b/examples/tv-app/linux/include/endpoint-configuration/chip_tv_config.ini deleted file mode 100644 index c381df80c6af86..00000000000000 --- a/examples/tv-app/linux/include/endpoint-configuration/chip_tv_config.ini +++ /dev/null @@ -1,46 +0,0 @@ -[endpoint1] -type=videoPlayer -macAddress=00:00:00:00:00 - -[endpoint2] -type=speaker - -[endpoint3] -type=app -vendorName=exampleVendorName1 -version=exampleVersion -vendorId=1 -name=exampleName1 -productId=1 -id=1 -catalogVendorId=1 - -[endpoint4] -type=app -vendorName=exampleVendorName2 -version=exampleVersion -vendorId=2 -name=exampleName2 -productId=2 -id=2 -catalogVendorId=2 - -[endpoint5] -type=app -vendorName=exampleVendorName3 -version=exampleVersion -vendorId=3 -name=exampleName3 -productId=3 -id= 3 -catalogVendorId=3 - -[endpoint6] -type=app -vendorName=exampleVendorName4 -version=exampleVersion -vendorId=4 -name=exampleName4 -productId=4 -id=4 -catalogVendorId=4 \ No newline at end of file diff --git a/scripts/tests/run_test_suite.py b/scripts/tests/run_test_suite.py index 1a9cfd7c58f37f..488bf0fd71beaf 100755 --- a/scripts/tests/run_test_suite.py +++ b/scripts/tests/run_test_suite.py @@ -233,14 +233,6 @@ def cmd_run(context, iterations, all_clusters_app, lock_app, ota_provider_app, o context.obj.in_unshare) paths = chiptest.linux.PathsWithNetworkNamespaces(paths) - # Testing prerequisites: tv app requires a config. Copy it just in case - shutil.copyfile( - os.path.join( - context.obj.root, ('examples/tv-app/linux/include/' - 'endpoint-configuration/chip_tv_config.ini')), - '/tmp/chip_tv_config.ini' - ) - logging.info("Each test will be executed %d times" % iterations) apps_register = AppsRegister()