[Examples] Create common tv-app sources (#27408)

Move cluster handlers, app platform and shell command implementations,
ZCL callbacks from Linux to tv-common directory.
Create source set with tv-app source files.
Create cmake macro to add common tv-app sources to the
specific target.
Use common tv-app sources in Linux tv-app example.

Sources can now be easily shared across platform implementations.

Signed-off-by: ATmobica <artur.tynecki@arm.com>
diff --git a/examples/tv-app/linux/BUILD.gn b/examples/tv-app/linux/BUILD.gn
index c77a4fe..7483868 100644
--- a/examples/tv-app/linux/BUILD.gn
+++ b/examples/tv-app/linux/BUILD.gn
@@ -20,43 +20,12 @@
 assert(chip_build_tools)
 
 executable("chip-tv-app") {
-  sources = [
-    "${chip_root}/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h",
-    "AppImpl.cpp",
-    "AppImpl.h",
-    "ZclCallbacks.cpp",
-    "include/account-login/AccountLoginManager.cpp",
-    "include/account-login/AccountLoginManager.h",
-    "include/application-basic/ApplicationBasicManager.cpp",
-    "include/application-basic/ApplicationBasicManager.h",
-    "include/application-launcher/ApplicationLauncherManager.cpp",
-    "include/application-launcher/ApplicationLauncherManager.h",
-    "include/audio-output/AudioOutputManager.cpp",
-    "include/audio-output/AudioOutputManager.h",
-    "include/channel/ChannelManager.cpp",
-    "include/channel/ChannelManager.h",
-    "include/cluster-change-attribute.cpp",
-    "include/cluster-init.cpp",
-    "include/content-launcher/ContentLauncherManager.cpp",
-    "include/content-launcher/ContentLauncherManager.h",
-    "include/keypad-input/KeypadInputManager.cpp",
-    "include/keypad-input/KeypadInputManager.h",
-    "include/low-power/LowPowerManager.cpp",
-    "include/low-power/LowPowerManager.h",
-    "include/media-input/MediaInputManager.cpp",
-    "include/media-input/MediaInputManager.h",
-    "include/media-playback/MediaPlaybackManager.cpp",
-    "include/media-playback/MediaPlaybackManager.h",
-    "include/target-navigator/TargetNavigatorManager.cpp",
-    "include/target-navigator/TargetNavigatorManager.h",
-    "include/wake-on-lan/WakeOnLanManager.cpp",
-    "include/wake-on-lan/WakeOnLanManager.h",
-    "main.cpp",
-  ]
+  sources = [ "main.cpp" ]
 
   deps = [
     "${chip_root}/examples/platform/linux:app-main",
     "${chip_root}/examples/tv-app/tv-common",
+    "${chip_root}/examples/tv-app/tv-common:tv-common-sources",
     "${chip_root}/src/lib",
     "${chip_root}/third_party/inipp",
   ]
@@ -71,7 +40,6 @@
 
   if (chip_build_libshell) {
     defines += [ "ENABLE_CHIP_SHELL" ]
-    sources += [ "AppPlatformShellCommands.cpp" ]
   }
 
   output_dir = root_out_dir
diff --git a/examples/tv-app/linux/README.md b/examples/tv-app/linux/README.md
index 547069f..46e0456 100644
--- a/examples/tv-app/linux/README.md
+++ b/examples/tv-app/linux/README.md
@@ -74,14 +74,15 @@
 following (see Video Player Architecture in the Device Library spec).
 
 There is a dummy app platform included in the linux tv-app which includes a
-small number of hardcoded apps. See AppImpl.h/.cpp for this dummy
-implementation. These apps have hardcoded values for many operations - on a real
-device, these apps would usually be developed by streaming video content
-providers and the native platform may or may not provide Matter interfaces to
-these apps. In some cases, the video player platform will bridge its existing
-internal interfaces to Matter, allowing apps to continue to not be Matter-aware,
-while other platforms may provide Matter interfaces to Content Apps so that they
-can directly respond to each Matter cluster.
+small number of hardcoded apps. See `examples/tv-app/tv-common/src/AppTv.h` and
+`examples/tv-app/tv-common/src/AppTv.cpp` for this dummy implementation. These
+apps have hardcoded values for many operations - on a real device, these apps
+would usually be developed by streaming video content providers and the native
+platform may or may not provide Matter interfaces to these apps. In some cases,
+the video player platform will bridge its existing internal interfaces to
+Matter, allowing apps to continue to not be Matter-aware, while other platforms
+may provide Matter interfaces to Content Apps so that they can directly respond
+to each Matter cluster.
 
 On Linux, there are shell commands to start and stop the dummy apps (by vendor
 id):
diff --git a/examples/tv-app/linux/ZclCallbacks.cpp b/examples/tv-app/linux/ZclCallbacks.cpp
deleted file mode 100644
index 0fe95c9..0000000
--- a/examples/tv-app/linux/ZclCallbacks.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *
- *    Copyright (c) 2020 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
- *   This file implements the handler for data model messages.
- */
-
-#include <app-common/zap-generated/ids/Attributes.h>
-#include <app-common/zap-generated/ids/Clusters.h>
-#include <app/ConcreteAttributePath.h>
-#include <lib/support/logging/CHIPLogging.h>
-
-using namespace ::chip;
-using namespace ::chip::app::Clusters;
-
-void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size,
-                                       uint8_t * value)
-{
-    ClusterId clusterId     = attributePath.mClusterId;
-    AttributeId attributeId = attributePath.mAttributeId;
-    ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId));
-
-    if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id)
-    {
-        ChipLogProgress(Zcl, "OnOff attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", ChipLogValueMEI(attributeId),
-                        type, *value, size);
-    }
-    else if (clusterId == LevelControl::Id)
-    {
-        ChipLogProgress(Zcl, "Level Control attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u",
-                        ChipLogValueMEI(attributeId), type, *value, size);
-
-        // WIP Apply attribute change to Light
-    }
-}
-
-/** @brief OnOff Cluster Init
- *
- * This function is called when a specific cluster is initialized. It gives the
- * application an opportunity to take care of cluster initialization procedures.
- * It is called exactly once for each endpoint where cluster is present.
- *
- * @param endpoint   Ver.: always
- *
- * TODO Issue #3841
- * emberAfOnOffClusterInitCallback happens before the stack initialize the cluster
- * attributes to the default value.
- * The logic here expects something similar to the deprecated Plugins callback
- * emberAfPluginOnOffClusterServerPostInitCallback.
- *
- */
-void emberAfOnOffClusterInitCallback(EndpointId endpoint)
-{
-    // TODO: implement any additional Cluster Server init actions
-}
diff --git a/examples/tv-app/linux/include/cluster-change-attribute.cpp b/examples/tv-app/linux/include/cluster-change-attribute.cpp
deleted file mode 100644
index 0a6c8de..0000000
--- a/examples/tv-app/linux/include/cluster-change-attribute.cpp
+++ /dev/null
@@ -1,67 +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 <app-common/zap-generated/ids/Attributes.h>
-#include <app-common/zap-generated/ids/Clusters.h>
-#include <app/ConcreteAttributePath.h>
-#include <lib/support/logging/CHIPLogging.h>
-
-using namespace chip;
-using namespace ::chip::app::Clusters;
-
-enum TvCommand
-{
-    PowerToggle,
-    MuteToggle
-};
-
-void runTvCommand(TvCommand command)
-{
-    switch (command)
-    {
-    case PowerToggle:
-        // TODO: Insert your code here to send power toggle command
-        break;
-    case MuteToggle:
-        // TODO: Insert your code here to send mute toggle command
-        break;
-
-    default:
-        break;
-    }
-}
-
-void MatterAfPostAttributeChangeCallback(const app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size,
-                                         uint8_t * value)
-{
-    if (attributePath.mClusterId == OnOff::Id && attributePath.mAttributeId == OnOff::Attributes::OnOff::Id)
-    {
-        ChipLogProgress(Zcl, "Received on/off command for cluster id: " ChipLogFormatMEI, ChipLogValueMEI(OnOff::Id));
-
-        if (attributePath.mEndpointId == 0)
-        {
-            ChipLogProgress(Zcl, "Execute POWER_TOGGLE");
-            runTvCommand(PowerToggle);
-        }
-        else if (attributePath.mEndpointId == 1)
-        {
-            ChipLogProgress(Zcl, "Execute MUTE_TOGGLE");
-            runTvCommand(MuteToggle);
-        }
-    }
-}
diff --git a/examples/tv-app/linux/include/cluster-init.cpp b/examples/tv-app/linux/include/cluster-init.cpp
deleted file mode 100644
index 496aa1c..0000000
--- a/examples/tv-app/linux/include/cluster-init.cpp
+++ /dev/null
@@ -1,54 +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 "application-basic/ApplicationBasicManager.h"
-#include "application-launcher/ApplicationLauncherManager.h"
-#include "audio-output/AudioOutputManager.h"
-#include "channel/ChannelManager.h"
-#include "content-launcher/ContentLauncherManager.h"
-#include "media-input/MediaInputManager.h"
-#include "target-navigator/TargetNavigatorManager.h"
-#include "wake-on-lan/WakeOnLanManager.h"
-
-#include <app-common/zap-generated/cluster-objects.h>
-#include <app-common/zap-generated/ids/Attributes.h>
-#include <app-common/zap-generated/ids/Clusters.h>
-#include <app/AttributeAccessInterface.h>
-#include <app/util/attribute-storage.h>
-
-using namespace chip;
-
-namespace {
-template <typename Manager, typename AttrTypeInfo, CHIP_ERROR (Manager::*Getter)(uint16_t, app::AttributeValueEncoder &)>
-class TvAttrAccess : public app::AttributeAccessInterface
-{
-public:
-    TvAttrAccess() : app::AttributeAccessInterface(Optional<EndpointId>::Missing(), AttrTypeInfo::GetClusterId()) {}
-
-    CHIP_ERROR Read(const app::ConcreteReadAttributePath & aPath, app::AttributeValueEncoder & aEncoder) override
-    {
-        if (aPath.mAttributeId == AttrTypeInfo::GetAttributeId())
-        {
-            return (Manager().*Getter)(aPath.mEndpointId, aEncoder);
-        }
-
-        return CHIP_NO_ERROR;
-    }
-};
-
-} // anonymous namespace
diff --git a/examples/tv-app/linux/main.cpp b/examples/tv-app/linux/main.cpp
index 2609d9a..ffdd5e0 100644
--- a/examples/tv-app/linux/main.cpp
+++ b/examples/tv-app/linux/main.cpp
@@ -16,9 +16,8 @@
  *    limitations under the License.
  */
 
-#include "AppImpl.h"
 #include "AppMain.h"
-#include "AppPlatformShellCommands.h"
+#include "AppTv.h"
 
 #include <access/AccessControl.h>
 #include <app-common/zap-generated/ids/Attributes.h>
@@ -27,21 +26,8 @@
 #include <app/app-platform/ContentAppPlatform.h>
 #include <app/util/af.h>
 
-#include "include/account-login/AccountLoginManager.h"
-#include "include/application-basic/ApplicationBasicManager.h"
-#include "include/application-launcher/ApplicationLauncherManager.h"
-#include "include/audio-output/AudioOutputManager.h"
-#include "include/channel/ChannelManager.h"
-#include "include/content-launcher/ContentLauncherManager.h"
-#include "include/keypad-input/KeypadInputManager.h"
-#include "include/low-power/LowPowerManager.h"
-#include "include/media-input/MediaInputManager.h"
-#include "include/media-playback/MediaPlaybackManager.h"
-#include "include/target-navigator/TargetNavigatorManager.h"
-#include "include/wake-on-lan/WakeOnLanManager.h"
-
 #if defined(ENABLE_CHIP_SHELL)
-#include <lib/shell/Engine.h> // nogncheck
+#include "AppTvShellCommands.h"
 #endif
 
 using namespace chip;
@@ -50,25 +36,6 @@
 using namespace chip::AppPlatform;
 using namespace chip::app::Clusters;
 
-namespace {
-static AccountLoginManager accountLoginManager;
-static ApplicationBasicManager applicationBasicManager;
-#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
-static ApplicationLauncherManager applicationLauncherManager(true);
-#else  // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
-static ApplicationLauncherManager applicationLauncherManager(false);
-#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
-static AudioOutputManager audioOutputManager;
-static ChannelManager channelManager;
-static ContentLauncherManager contentLauncherManager;
-static KeypadInputManager keypadInputManager;
-static LowPowerManager lowPowerManager;
-static MediaInputManager mediaInputManager;
-static MediaPlaybackManager mediaPlaybackManager;
-static TargetNavigatorManager targetNavigatorManager;
-static WakeOnLanManager wakeOnLanManager;
-} // namespace
-
 void ApplicationInit()
 {
     ChipLogProgress(Zcl, "TV Linux App: ApplicationInit()");
@@ -85,11 +52,11 @@
 
     VerifyOrDie(ChipLinuxAppInit(argc, argv) == 0);
 
-    InitVideoPlayerPlatform();
+    AppTvInit();
 
 #if defined(ENABLE_CHIP_SHELL)
 #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
-    Shell::RegisterAppPlatformCommands();
+    Shell::RegisterAppTvCommands();
 #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
 #endif
 
@@ -97,75 +64,3 @@
 
     return 0;
 }
-
-void emberAfContentLauncherClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: ContentLauncher::SetDefaultDelegate");
-    ContentLauncher::SetDefaultDelegate(endpoint, &contentLauncherManager);
-}
-
-void emberAfAccountLoginClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: AccountLogin::SetDefaultDelegate");
-    AccountLogin::SetDefaultDelegate(endpoint, &accountLoginManager);
-}
-
-void emberAfApplicationBasicClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: ApplicationBasic::SetDefaultDelegate");
-    ApplicationBasic::SetDefaultDelegate(endpoint, &applicationBasicManager);
-}
-
-void emberAfApplicationLauncherClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: ApplicationLauncher::SetDefaultDelegate");
-    ApplicationLauncher::SetDefaultDelegate(endpoint, &applicationLauncherManager);
-}
-
-void emberAfAudioOutputClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: AudioOutput::SetDefaultDelegate");
-    AudioOutput::SetDefaultDelegate(endpoint, &audioOutputManager);
-}
-
-void emberAfChannelClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: Channel::SetDefaultDelegate");
-    Channel::SetDefaultDelegate(endpoint, &channelManager);
-}
-
-void emberAfKeypadInputClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: KeypadInput::SetDefaultDelegate");
-    KeypadInput::SetDefaultDelegate(endpoint, &keypadInputManager);
-}
-
-void emberAfLowPowerClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: LowPower::SetDefaultDelegate");
-    LowPower::SetDefaultDelegate(endpoint, &lowPowerManager);
-}
-
-void emberAfMediaInputClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: MediaInput::SetDefaultDelegate");
-    MediaInput::SetDefaultDelegate(endpoint, &mediaInputManager);
-}
-
-void emberAfMediaPlaybackClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: MediaPlayback::SetDefaultDelegate");
-    MediaPlayback::SetDefaultDelegate(endpoint, &mediaPlaybackManager);
-}
-
-void emberAfTargetNavigatorClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: TargetNavigator::SetDefaultDelegate");
-    TargetNavigator::SetDefaultDelegate(endpoint, &targetNavigatorManager);
-}
-
-void emberAfWakeOnLanClusterInitCallback(EndpointId endpoint)
-{
-    ChipLogProgress(Zcl, "TV Linux App: WakeOnLanManager::SetDefaultDelegate");
-    WakeOnLan::SetDefaultDelegate(endpoint, &wakeOnLanManager);
-}
diff --git a/examples/tv-app/tv-common/BUILD.gn b/examples/tv-app/tv-common/BUILD.gn
index f723e6f..03d98b3 100644
--- a/examples/tv-app/tv-common/BUILD.gn
+++ b/examples/tv-app/tv-common/BUILD.gn
@@ -15,6 +15,7 @@
 import("//build_overrides/chip.gni")
 
 import("${chip_root}/src/app/chip_data_model.gni")
+import("${chip_root}/src/lib/lib.gni")
 
 chip_data_model("tv-common") {
   zap_file = "tv-app.zap"
@@ -22,3 +23,59 @@
   zap_pregenerated_dir = "${chip_root}/zzz_generated/tv-app/zap-generated"
   is_server = true
 }
+
+config("config") {
+  include_dirs = [
+    "include",
+    "clusters",
+  ]
+  if (chip_build_libshell) {
+    include_dirs += [ "shell" ]
+  }
+}
+
+source_set("tv-common-sources") {
+  deps = [
+    "${chip_root}/examples/platform/linux:app-main",
+    "${chip_root}/examples/tv-app/tv-common",
+    "${chip_root}/src/lib",
+  ]
+  public_configs = [ ":config" ]
+  sources = [
+    "clusters/account-login/AccountLoginManager.cpp",
+    "clusters/account-login/AccountLoginManager.h",
+    "clusters/application-basic/ApplicationBasicManager.cpp",
+    "clusters/application-basic/ApplicationBasicManager.h",
+    "clusters/application-launcher/ApplicationLauncherManager.cpp",
+    "clusters/application-launcher/ApplicationLauncherManager.h",
+    "clusters/audio-output/AudioOutputManager.cpp",
+    "clusters/audio-output/AudioOutputManager.h",
+    "clusters/channel/ChannelManager.cpp",
+    "clusters/channel/ChannelManager.h",
+    "clusters/content-launcher/ContentLauncherManager.cpp",
+    "clusters/content-launcher/ContentLauncherManager.h",
+    "clusters/keypad-input/KeypadInputManager.cpp",
+    "clusters/keypad-input/KeypadInputManager.h",
+    "clusters/low-power/LowPowerManager.cpp",
+    "clusters/low-power/LowPowerManager.h",
+    "clusters/media-input/MediaInputManager.cpp",
+    "clusters/media-input/MediaInputManager.h",
+    "clusters/media-playback/MediaPlaybackManager.cpp",
+    "clusters/media-playback/MediaPlaybackManager.h",
+    "clusters/target-navigator/TargetNavigatorManager.cpp",
+    "clusters/target-navigator/TargetNavigatorManager.h",
+    "clusters/wake-on-lan/WakeOnLanManager.cpp",
+    "clusters/wake-on-lan/WakeOnLanManager.h",
+    "include/AppTv.h",
+    "include/CHIPProjectAppConfig.h",
+    "src/AppTv.cpp",
+    "src/ZCLCallbacks.cpp",
+  ]
+
+  if (chip_build_libshell) {
+    sources += [
+      "shell/AppTvShellCommands.cpp",
+      "shell/AppTvShellCommands.h",
+    ]
+  }
+}
diff --git a/examples/tv-app/linux/include/account-login/AccountLoginManager.cpp b/examples/tv-app/tv-common/clusters/account-login/AccountLoginManager.cpp
similarity index 96%
rename from examples/tv-app/linux/include/account-login/AccountLoginManager.cpp
rename to examples/tv-app/tv-common/clusters/account-login/AccountLoginManager.cpp
index 7a27ce2..d5f7030 100644
--- a/examples/tv-app/linux/include/account-login/AccountLoginManager.cpp
+++ b/examples/tv-app/tv-common/clusters/account-login/AccountLoginManager.cpp
@@ -48,6 +48,7 @@
 bool AccountLoginManager::HandleLogout()
 {
     // TODO: Insert your code here to send logout request
+    ChipLogProgress(Zcl, "AccountLoginManager::HandleLogout success");
     return true;
 }
 
diff --git a/examples/tv-app/linux/include/account-login/AccountLoginManager.h b/examples/tv-app/tv-common/clusters/account-login/AccountLoginManager.h
similarity index 100%
rename from examples/tv-app/linux/include/account-login/AccountLoginManager.h
rename to examples/tv-app/tv-common/clusters/account-login/AccountLoginManager.h
diff --git a/examples/tv-app/linux/include/application-basic/ApplicationBasicManager.cpp b/examples/tv-app/tv-common/clusters/application-basic/ApplicationBasicManager.cpp
similarity index 100%
rename from examples/tv-app/linux/include/application-basic/ApplicationBasicManager.cpp
rename to examples/tv-app/tv-common/clusters/application-basic/ApplicationBasicManager.cpp
diff --git a/examples/tv-app/linux/include/application-basic/ApplicationBasicManager.h b/examples/tv-app/tv-common/clusters/application-basic/ApplicationBasicManager.h
similarity index 100%
rename from examples/tv-app/linux/include/application-basic/ApplicationBasicManager.h
rename to examples/tv-app/tv-common/clusters/application-basic/ApplicationBasicManager.h
diff --git a/examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.cpp b/examples/tv-app/tv-common/clusters/application-launcher/ApplicationLauncherManager.cpp
similarity index 100%
rename from examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.cpp
rename to examples/tv-app/tv-common/clusters/application-launcher/ApplicationLauncherManager.cpp
diff --git a/examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.h b/examples/tv-app/tv-common/clusters/application-launcher/ApplicationLauncherManager.h
similarity index 100%
rename from examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.h
rename to examples/tv-app/tv-common/clusters/application-launcher/ApplicationLauncherManager.h
diff --git a/examples/tv-app/linux/include/audio-output/AudioOutputManager.cpp b/examples/tv-app/tv-common/clusters/audio-output/AudioOutputManager.cpp
similarity index 100%
rename from examples/tv-app/linux/include/audio-output/AudioOutputManager.cpp
rename to examples/tv-app/tv-common/clusters/audio-output/AudioOutputManager.cpp
diff --git a/examples/tv-app/linux/include/audio-output/AudioOutputManager.h b/examples/tv-app/tv-common/clusters/audio-output/AudioOutputManager.h
similarity index 100%
rename from examples/tv-app/linux/include/audio-output/AudioOutputManager.h
rename to examples/tv-app/tv-common/clusters/audio-output/AudioOutputManager.h
diff --git a/examples/tv-app/linux/include/channel/ChannelManager.cpp b/examples/tv-app/tv-common/clusters/channel/ChannelManager.cpp
similarity index 100%
rename from examples/tv-app/linux/include/channel/ChannelManager.cpp
rename to examples/tv-app/tv-common/clusters/channel/ChannelManager.cpp
diff --git a/examples/tv-app/linux/include/channel/ChannelManager.h b/examples/tv-app/tv-common/clusters/channel/ChannelManager.h
similarity index 100%
rename from examples/tv-app/linux/include/channel/ChannelManager.h
rename to examples/tv-app/tv-common/clusters/channel/ChannelManager.h
diff --git a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp b/examples/tv-app/tv-common/clusters/content-launcher/ContentLauncherManager.cpp
similarity index 97%
rename from examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp
rename to examples/tv-app/tv-common/clusters/content-launcher/ContentLauncherManager.cpp
index 79ae11b..60d38f5 100644
--- a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp
+++ b/examples/tv-app/tv-common/clusters/content-launcher/ContentLauncherManager.cpp
@@ -97,10 +97,10 @@
                                                  const DecodableList<ParameterType> & parameterList, bool autoplay,
                                                  const CharSpan & data)
 {
-    ChipLogProgress(Zcl, "ContentLauncherManager::HandleLaunchContent for endpoint %d", mEndpointId);
+    ChipLogProgress(Zcl, "ContentLauncherManager::HandleLaunchContent");
     string dataString(data.data(), data.size());
 
-    ChipLogProgress(Zcl, "ContentLauncherManager::HandleLaunchUrl TEST CASE autoplay=%d data=%s ", (autoplay ? 1 : 0),
+    ChipLogProgress(Zcl, "ContentLauncherManager::HandleLaunchContent TEST CASE autoplay=%d data=%s ", (autoplay ? 1 : 0),
                     dataString.c_str());
 
     bool foundMatch = false;
diff --git a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h b/examples/tv-app/tv-common/clusters/content-launcher/ContentLauncherManager.h
similarity index 98%
rename from examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h
rename to examples/tv-app/tv-common/clusters/content-launcher/ContentLauncherManager.h
index b19663d..d08e708 100644
--- a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h
+++ b/examples/tv-app/tv-common/clusters/content-launcher/ContentLauncherManager.h
@@ -59,7 +59,6 @@
     std::vector<ContentEntry> mContentList;
 
 private:
-    EndpointId mEndpointId;
     // TODO: set this based upon meta data from app
     uint32_t mDynamicEndpointFeatureMap = 3;
 };
diff --git a/examples/tv-app/linux/include/keypad-input/KeypadInputManager.cpp b/examples/tv-app/tv-common/clusters/keypad-input/KeypadInputManager.cpp
similarity index 100%
rename from examples/tv-app/linux/include/keypad-input/KeypadInputManager.cpp
rename to examples/tv-app/tv-common/clusters/keypad-input/KeypadInputManager.cpp
diff --git a/examples/tv-app/linux/include/keypad-input/KeypadInputManager.h b/examples/tv-app/tv-common/clusters/keypad-input/KeypadInputManager.h
similarity index 100%
rename from examples/tv-app/linux/include/keypad-input/KeypadInputManager.h
rename to examples/tv-app/tv-common/clusters/keypad-input/KeypadInputManager.h
diff --git a/examples/tv-app/linux/include/low-power/LowPowerManager.cpp b/examples/tv-app/tv-common/clusters/low-power/LowPowerManager.cpp
similarity index 92%
rename from examples/tv-app/linux/include/low-power/LowPowerManager.cpp
rename to examples/tv-app/tv-common/clusters/low-power/LowPowerManager.cpp
index 57399c0..7f11971 100644
--- a/examples/tv-app/linux/include/low-power/LowPowerManager.cpp
+++ b/examples/tv-app/tv-common/clusters/low-power/LowPowerManager.cpp
@@ -21,5 +21,6 @@
 bool LowPowerManager::HandleSleep()
 {
     // TODO: Insert code here
+    ChipLogProgress(Zcl, "LowPowerManager::HandleSleep");
     return true;
 }
diff --git a/examples/tv-app/linux/include/low-power/LowPowerManager.h b/examples/tv-app/tv-common/clusters/low-power/LowPowerManager.h
similarity index 100%
rename from examples/tv-app/linux/include/low-power/LowPowerManager.h
rename to examples/tv-app/tv-common/clusters/low-power/LowPowerManager.h
diff --git a/examples/tv-app/linux/include/media-input/MediaInputManager.cpp b/examples/tv-app/tv-common/clusters/media-input/MediaInputManager.cpp
similarity index 100%
rename from examples/tv-app/linux/include/media-input/MediaInputManager.cpp
rename to examples/tv-app/tv-common/clusters/media-input/MediaInputManager.cpp
diff --git a/examples/tv-app/linux/include/media-input/MediaInputManager.h b/examples/tv-app/tv-common/clusters/media-input/MediaInputManager.h
similarity index 100%
rename from examples/tv-app/linux/include/media-input/MediaInputManager.h
rename to examples/tv-app/tv-common/clusters/media-input/MediaInputManager.h
diff --git a/examples/tv-app/linux/include/media-playback/MediaPlaybackManager.cpp b/examples/tv-app/tv-common/clusters/media-playback/MediaPlaybackManager.cpp
similarity index 100%
rename from examples/tv-app/linux/include/media-playback/MediaPlaybackManager.cpp
rename to examples/tv-app/tv-common/clusters/media-playback/MediaPlaybackManager.cpp
diff --git a/examples/tv-app/linux/include/media-playback/MediaPlaybackManager.h b/examples/tv-app/tv-common/clusters/media-playback/MediaPlaybackManager.h
similarity index 100%
rename from examples/tv-app/linux/include/media-playback/MediaPlaybackManager.h
rename to examples/tv-app/tv-common/clusters/media-playback/MediaPlaybackManager.h
diff --git a/examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.cpp b/examples/tv-app/tv-common/clusters/target-navigator/TargetNavigatorManager.cpp
similarity index 100%
rename from examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.cpp
rename to examples/tv-app/tv-common/clusters/target-navigator/TargetNavigatorManager.cpp
diff --git a/examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.h b/examples/tv-app/tv-common/clusters/target-navigator/TargetNavigatorManager.h
similarity index 100%
rename from examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.h
rename to examples/tv-app/tv-common/clusters/target-navigator/TargetNavigatorManager.h
diff --git a/examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.cpp b/examples/tv-app/tv-common/clusters/wake-on-lan/WakeOnLanManager.cpp
similarity index 100%
rename from examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.cpp
rename to examples/tv-app/tv-common/clusters/wake-on-lan/WakeOnLanManager.cpp
diff --git a/examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.h b/examples/tv-app/tv-common/clusters/wake-on-lan/WakeOnLanManager.h
similarity index 100%
rename from examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.h
rename to examples/tv-app/tv-common/clusters/wake-on-lan/WakeOnLanManager.h
diff --git a/examples/tv-app/linux/AppImpl.h b/examples/tv-app/tv-common/include/AppTv.h
similarity index 92%
rename from examples/tv-app/linux/AppImpl.h
rename to examples/tv-app/tv-common/include/AppTv.h
index 46cdb65..e63a4ff 100644
--- a/examples/tv-app/linux/AppImpl.h
+++ b/examples/tv-app/tv-common/include/AppTv.h
@@ -30,15 +30,15 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-#include "CommissionerMain.h"
-#include "include/account-login/AccountLoginManager.h"
-#include "include/application-basic/ApplicationBasicManager.h"
-#include "include/application-launcher/ApplicationLauncherManager.h"
-#include "include/channel/ChannelManager.h"
-#include "include/content-launcher/ContentLauncherManager.h"
-#include "include/keypad-input/KeypadInputManager.h"
-#include "include/media-playback/MediaPlaybackManager.h"
-#include "include/target-navigator/TargetNavigatorManager.h"
+#include "account-login/AccountLoginManager.h"
+#include "application-basic/ApplicationBasicManager.h"
+#include "application-launcher/ApplicationLauncherManager.h"
+#include "channel/ChannelManager.h"
+#include "content-launcher/ContentLauncherManager.h"
+#include "keypad-input/KeypadInputManager.h"
+#include "media-playback/MediaPlaybackManager.h"
+#include "target-navigator/TargetNavigatorManager.h"
+
 #include <app/clusters/account-login-server/account-login-delegate.h>
 #include <app/clusters/application-basic-server/application-basic-delegate.h>
 #include <app/clusters/application-launcher-server/application-launcher-delegate.h>
@@ -48,8 +48,6 @@
 #include <app/clusters/media-playback-server/media-playback-delegate.h>
 #include <app/clusters/target-navigator-server/target-navigator-delegate.h>
 
-CHIP_ERROR InitVideoPlayerPlatform();
-
 #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
 
 namespace chip {
@@ -155,3 +153,5 @@
 chip::AppPlatform::ContentAppFactoryImpl * GetContentAppFactoryImpl();
 
 #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
+
+CHIP_ERROR AppTvInit(void);
diff --git a/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h b/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h
index 395be25..99274da 100644
--- a/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h
+++ b/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h
@@ -70,8 +70,5 @@
 // Change port to make it easy to run against tv-casting-app
 #define CHIP_PORT 5640
 
-// Create a dedicated file for storage to make it easy to run against other apps
-// #define CHIP_CONFIG_KVS_PATH "/tmp/chip_tv_kvs"
-
-// include the CHIPProjectConfig from config/standalone
+// Include the CHIPProjectConfig from platform implementation config
 #include <CHIPProjectConfig.h>
diff --git a/examples/tv-app/linux/AppPlatformShellCommands.cpp b/examples/tv-app/tv-common/shell/AppTvShellCommands.cpp
similarity index 87%
rename from examples/tv-app/linux/AppPlatformShellCommands.cpp
rename to examples/tv-app/tv-common/shell/AppTvShellCommands.cpp
index b70c7b6..c66beb9 100644
--- a/examples/tv-app/linux/AppPlatformShellCommands.cpp
+++ b/examples/tv-app/tv-common/shell/AppTvShellCommands.cpp
@@ -19,10 +19,9 @@
  * @file Contains shell commands for a ContentApp relating to Content App platform of the Video Player.
  */
 
-#include "AppPlatformShellCommands.h"
-#include "AppImpl.h"
-#include "ControllerShellCommands.h"
-#include <AppMain.h>
+#include "AppTvShellCommands.h"
+#include "AppTv.h"
+
 #include <access/AccessControl.h>
 #include <inttypes.h>
 #include <lib/core/CHIPCore.h>
@@ -36,20 +35,24 @@
 
 #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
 #include <app/app-platform/ContentAppPlatform.h>
-#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
-
-using namespace ::chip::Controller;
-#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
 using namespace chip::AppPlatform;
 using namespace chip::Access;
 #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
-using namespace chip::app::Clusters;
 
-#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
+#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
+#include <controller/CHIPDeviceController.h>
+#include <controller/CommissionerDiscoveryController.h>
+using namespace ::chip::Controller;
+extern DeviceCommissioner * GetDeviceCommissioner();
+extern CHIP_ERROR CommissionerPairUDC(uint32_t pincode, size_t index);
+#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
+
+using namespace chip::app::Clusters;
 
 namespace chip {
 namespace Shell {
 
+#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
 static CHIP_ERROR pairApp(bool printHeader, size_t index)
 {
     streamer_t * sout = streamer_get();
@@ -181,23 +184,28 @@
     ChipLogError(DeviceLayer, "DumpAccessControlEntry: dump failed %" CHIP_ERROR_FORMAT, err.Format());
     return err;
 }
+#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
 
 static CHIP_ERROR PrintAllCommands()
 {
     streamer_t * sout = streamer_get();
-    streamer_printf(sout, "  help                 Usage: app <subcommand>\r\n");
-    streamer_printf(sout, "  add <vid> [<pid>]    Add app with given vendor ID [1, 2, 9050]. Usage: app add 9050\r\n");
-    streamer_printf(sout, "  remove <endpoint>    Remove app at given endpoint [6, 7, etc]. Usage: app remove 6\r\n");
+    streamer_printf(sout, "  help                           Usage: app <subcommand>\r\n");
+#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
+    streamer_printf(sout, "  add <vid> [<pid>]              Add app with given vendor ID [1, 2, 9050]. Usage: app add 9050\r\n");
+    streamer_printf(sout, "  remove <endpoint>              Remove app at given endpoint [6, 7, etc]. Usage: app remove 6\r\n");
+    streamer_printf(
+        sout, "  setpin <endpoint> <pincode>    Set pincode for app with given endpoint ID. Usage: app setpin 6 34567890\r\n");
     streamer_printf(sout,
-                    "  setpin <endpoint> <pincode>  Set pincode for app with given endpoint ID. Usage: app setpin 6 34567890\r\n");
+                    "  add-admin-vendor <vid>         Add vendor ID to list which will receive admin privileges. Usage: app "
+                    "add-admin-vendor 65521\r\n");
+#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
+#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
+    streamer_printf(sout, "  print-app-access     Print all ACLs for app platform fabric. Usage: app print-app-access\r\n");
+    streamer_printf(sout, "  remove-app-access    Remove all ACLs for app platform fabric. Usage: app remove-app-access\r\n");
     streamer_printf(sout,
                     "  commission <udc-entry>     Commission given udc-entry using given pincode from corresponding app. Usage: "
                     "app commission 0\r\n");
-    streamer_printf(sout,
-                    "  add-admin-vendor <vid> Add vendor ID to list which will receive admin privileges. Usage: app "
-                    "add-admin-vendor 65521\r\n");
-    streamer_printf(sout, "  print-app-access     Print all ACLs for app platform fabric. Usage: app print-app-access\r\n");
-    streamer_printf(sout, "  remove-app-access    Remove all ACLs for app platform fabric. Usage: app remove-app-access\r\n");
+#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
     streamer_printf(sout, "\r\n");
 
     return CHIP_NO_ERROR;
@@ -211,6 +219,7 @@
     {
         return PrintAllCommands();
     }
+#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
     else if (strcmp(argv[0], "add-admin-vendor") == 0)
     {
         if (argc < 2)
@@ -295,16 +304,8 @@
 
         return CHIP_NO_ERROR;
     }
-    else if (strcmp(argv[0], "commission") == 0)
-    {
-        if (argc < 2)
-        {
-            return PrintAllCommands();
-        }
-        char * eptr;
-        size_t index = (size_t) strtol(argv[1], &eptr, 10);
-        return error = pairApp(true, index);
-    }
+#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
+#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
     else if (strcmp(argv[0], "print-app-access") == 0)
     {
         Access::AccessControl::EntryIterator iterator;
@@ -322,6 +323,17 @@
         Access::GetAccessControl().DeleteAllEntriesForFabric(GetDeviceCommissioner()->GetFabricIndex());
         return CHIP_NO_ERROR;
     }
+    else if (strcmp(argv[0], "commission") == 0)
+    {
+        if (argc < 2)
+        {
+            return PrintAllCommands();
+        }
+        char * eptr;
+        size_t index = (size_t) strtol(argv[1], &eptr, 10);
+        return error = pairApp(true, index);
+    }
+#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
     else
     {
         return CHIP_ERROR_INVALID_ARGUMENT;
@@ -329,7 +341,7 @@
     return error;
 }
 
-void RegisterAppPlatformCommands()
+void RegisterAppTvCommands()
 {
 
     static const shell_command_t sDeviceComand = { &AppPlatformHandler, "app", "App commands. Usage: app [command_name]" };
@@ -341,5 +353,3 @@
 
 } // namespace Shell
 } // namespace chip
-
-#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
diff --git a/examples/tv-app/linux/AppPlatformShellCommands.h b/examples/tv-app/tv-common/shell/AppTvShellCommands.h
similarity index 86%
rename from examples/tv-app/linux/AppPlatformShellCommands.h
rename to examples/tv-app/tv-common/shell/AppTvShellCommands.h
index bee8900..4be0bae 100644
--- a/examples/tv-app/linux/AppPlatformShellCommands.h
+++ b/examples/tv-app/tv-common/shell/AppTvShellCommands.h
@@ -22,12 +22,10 @@
 
 #include <platform/CHIPDeviceLayer.h>
 
-#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
 namespace chip {
 namespace Shell {
 
-void RegisterAppPlatformCommands();
+void RegisterAppTvCommands();
 
 } // namespace Shell
 } // namespace chip
-#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
diff --git a/examples/tv-app/linux/AppImpl.cpp b/examples/tv-app/tv-common/src/AppTv.cpp
similarity index 97%
rename from examples/tv-app/linux/AppImpl.cpp
rename to examples/tv-app/tv-common/src/AppTv.cpp
index a07eead..9dc840a 100644
--- a/examples/tv-app/linux/AppImpl.cpp
+++ b/examples/tv-app/tv-common/src/AppTv.cpp
@@ -19,7 +19,7 @@
  * @file Contains Implementation of the ContentApp and the ContentAppPlatform.
  */
 
-#include "AppImpl.h"
+#include "AppTv.h"
 
 #include <app-common/zap-generated/attributes/Accessors.h>
 #include <app-common/zap-generated/ids/Attributes.h>
@@ -40,6 +40,14 @@
 #include <platform/DeviceInstanceInfoProvider.h>
 #include <zap-generated/CHIPClusters.h>
 
+#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
+#include <controller/CHIPDeviceController.h>
+#include <controller/CommissionerDiscoveryController.h>
+using namespace ::chip::Controller;
+extern DeviceCommissioner * GetDeviceCommissioner();
+extern CommissionerDiscoveryController * GetCommissionerDiscoveryController();
+#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
+
 using namespace chip;
 using namespace chip::AppPlatform;
 using namespace chip::app::Clusters;
@@ -70,9 +78,7 @@
 };
 
 MyUserPrompter gMyUserPrompter;
-#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
 
-#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
 class MyPincodeService : public PincodeService
 {
     uint32_t FetchCommissionPincodeFromContentApp(uint16_t vendorId, uint16_t productId, CharSpan rotatingId) override
@@ -205,6 +211,9 @@
 };
 
 MyPostCommissioningListener gMyPostCommissioningListener;
+#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
+
+#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
 ContentAppFactoryImpl gFactory;
 
 ContentAppFactoryImpl * GetContentAppFactoryImpl()
@@ -528,7 +537,7 @@
 
 #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
 
-CHIP_ERROR InitVideoPlayerPlatform()
+CHIP_ERROR AppTvInit()
 {
 #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
     ContentAppPlatform::GetInstance().SetupAppPlatform();
@@ -536,7 +545,7 @@
     uint16_t value;
     if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(value) != CHIP_NO_ERROR)
     {
-        ChipLogDetail(Discovery, "AppImpl InitVideoPlayerPlatform Vendor ID not known");
+        ChipLogDetail(Discovery, "AppTvInit Vendor ID not known");
     }
     else
     {
diff --git a/examples/tv-app/tv-common/src/ZCLCallbacks.cpp b/examples/tv-app/tv-common/src/ZCLCallbacks.cpp
new file mode 100644
index 0000000..d980811
--- /dev/null
+++ b/examples/tv-app/tv-common/src/ZCLCallbacks.cpp
@@ -0,0 +1,174 @@
+/*
+ *
+ *    Copyright (c) 2020 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
+ *   This file implements the handler for data model messages.
+ */
+
+#include <app-common/zap-generated/ids/Attributes.h>
+#include <app-common/zap-generated/ids/Clusters.h>
+#include <app/ConcreteAttributePath.h>
+#include <lib/support/logging/CHIPLogging.h>
+
+#include "account-login/AccountLoginManager.h"
+#include "application-basic/ApplicationBasicManager.h"
+#include "application-launcher/ApplicationLauncherManager.h"
+#include "audio-output/AudioOutputManager.h"
+#include "channel/ChannelManager.h"
+#include "content-launcher/ContentLauncherManager.h"
+#include "keypad-input/KeypadInputManager.h"
+#include "low-power/LowPowerManager.h"
+#include "media-input/MediaInputManager.h"
+#include "media-playback/MediaPlaybackManager.h"
+#include "target-navigator/TargetNavigatorManager.h"
+#include "wake-on-lan/WakeOnLanManager.h"
+
+namespace {
+static AccountLoginManager accountLoginManager;
+static ApplicationBasicManager applicationBasicManager;
+#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
+static ApplicationLauncherManager applicationLauncherManager(true);
+#else  // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
+static ApplicationLauncherManager applicationLauncherManager(false);
+#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
+static AudioOutputManager audioOutputManager;
+static ChannelManager channelManager;
+static ContentLauncherManager contentLauncherManager;
+static KeypadInputManager keypadInputManager;
+static LowPowerManager lowPowerManager;
+static MediaInputManager mediaInputManager;
+static MediaPlaybackManager mediaPlaybackManager;
+static TargetNavigatorManager targetNavigatorManager;
+static WakeOnLanManager wakeOnLanManager;
+} // namespace
+
+using namespace ::chip;
+using namespace ::chip::app::Clusters;
+
+void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size,
+                                       uint8_t * value)
+{
+    ClusterId clusterId     = attributePath.mClusterId;
+    AttributeId attributeId = attributePath.mAttributeId;
+    ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId));
+
+    if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id)
+    {
+        ChipLogProgress(Zcl, "OnOff attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", ChipLogValueMEI(attributeId),
+                        type, *value, size);
+    }
+    else if (clusterId == LevelControl::Id)
+    {
+        ChipLogProgress(Zcl, "Level Control attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u",
+                        ChipLogValueMEI(attributeId), type, *value, size);
+
+        // WIP Apply attribute change to Light
+    }
+}
+
+/** @brief OnOff Cluster Init
+ *
+ * This function is called when a specific cluster is initialized. It gives the
+ * application an opportunity to take care of cluster initialization procedures.
+ * It is called exactly once for each endpoint where cluster is present.
+ *
+ * @param endpoint   Ver.: always
+ *
+ * TODO Issue #3841
+ * emberAfOnOffClusterInitCallback happens before the stack initialize the cluster
+ * attributes to the default value.
+ * The logic here expects something similar to the deprecated Plugins callback
+ * emberAfPluginOnOffClusterServerPostInitCallback.
+ *
+ */
+void emberAfOnOffClusterInitCallback(EndpointId endpoint)
+{
+    // TODO: implement any additional Cluster Server init actions
+}
+
+void emberAfContentLauncherClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: ContentLauncher::SetDefaultDelegate");
+    ContentLauncher::SetDefaultDelegate(endpoint, &contentLauncherManager);
+}
+
+void emberAfAccountLoginClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: AccountLogin::SetDefaultDelegate");
+    AccountLogin::SetDefaultDelegate(endpoint, &accountLoginManager);
+}
+
+void emberAfApplicationBasicClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: ApplicationBasic::SetDefaultDelegate");
+    ApplicationBasic::SetDefaultDelegate(endpoint, &applicationBasicManager);
+}
+
+void emberAfApplicationLauncherClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: ApplicationLauncher::SetDefaultDelegate");
+    ApplicationLauncher::SetDefaultDelegate(endpoint, &applicationLauncherManager);
+}
+
+void emberAfAudioOutputClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: AudioOutput::SetDefaultDelegate");
+    AudioOutput::SetDefaultDelegate(endpoint, &audioOutputManager);
+}
+
+void emberAfChannelClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: Channel::SetDefaultDelegate");
+    Channel::SetDefaultDelegate(endpoint, &channelManager);
+}
+
+void emberAfKeypadInputClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: KeypadInput::SetDefaultDelegate");
+    KeypadInput::SetDefaultDelegate(endpoint, &keypadInputManager);
+}
+
+void emberAfLowPowerClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: LowPower::SetDefaultDelegate");
+    LowPower::SetDefaultDelegate(endpoint, &lowPowerManager);
+}
+
+void emberAfMediaInputClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: MediaInput::SetDefaultDelegate");
+    MediaInput::SetDefaultDelegate(endpoint, &mediaInputManager);
+}
+
+void emberAfMediaPlaybackClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: MediaPlayback::SetDefaultDelegate");
+    MediaPlayback::SetDefaultDelegate(endpoint, &mediaPlaybackManager);
+}
+
+void emberAfTargetNavigatorClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: TargetNavigator::SetDefaultDelegate");
+    TargetNavigator::SetDefaultDelegate(endpoint, &targetNavigatorManager);
+}
+
+void emberAfWakeOnLanClusterInitCallback(EndpointId endpoint)
+{
+    ChipLogProgress(Zcl, "TV Linux App: WakeOnLanManager::SetDefaultDelegate");
+    WakeOnLan::SetDefaultDelegate(endpoint, &wakeOnLanManager);
+}
diff --git a/examples/tv-app/tv-common/tv-app.cmake b/examples/tv-app/tv-common/tv-app.cmake
new file mode 100644
index 0000000..cf257b8
--- /dev/null
+++ b/examples/tv-app/tv-common/tv-app.cmake
@@ -0,0 +1,86 @@
+#
+#   Copyright (c) 2023 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.
+#
+
+cmake_minimum_required(VERSION 3.21)
+
+set(CHIP_TV_COMMON_BASE_DIR ${CMAKE_CURRENT_LIST_DIR})
+if (NOT CHIP_ROOT)
+    get_filename_component(CHIP_ROOT ${CHIP_TV_COMMON_BASE_DIR}/../../.. REALPATH)
+endif()
+
+# Add common lock sources to the specific target
+# [Args]:
+#   target - target name
+    # Available options are:
+#   SCOPE   sources scope for the target, PRIVATE as default
+#   SHELL_CMD add shell commands support
+macro(chip_add_tv_app_common target)
+    set(SCOPE PRIVATE)
+    set(oneValueArgs
+        SCOPE
+        SHELL_CMD
+    )
+    cmake_parse_arguments(ARG "" "${oneValueArgs}" "" ${ARGN})
+    if (ARG_SCOPE)
+        set(SCOPE ${ARG_SCOPE})
+    endif()
+
+    target_include_directories(${target}
+        ${SCOPE}
+            ${CHIP_TV_COMMON_BASE_DIR}/include
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters
+            ${CHIP_ROOT}/src/app/app-platform
+    )
+
+    target_sources(${target}
+        ${SCOPE}
+            ${CHIP_TV_COMMON_BASE_DIR}/src/AppTv.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/src/ZCLCallbacks.cpp
+
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/account-login/AccountLoginManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/application-basic/ApplicationBasicManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/application-launcher/ApplicationLauncherManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/audio-output/AudioOutputManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/channel/ChannelManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/content-launcher/ContentLauncherManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/keypad-input/KeypadInputManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/low-power/LowPowerManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/media-input/MediaInputManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/media-playback/MediaPlaybackManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/target-navigator/TargetNavigatorManager.cpp
+            ${CHIP_TV_COMMON_BASE_DIR}/clusters/wake-on-lan/WakeOnLanManager.cpp
+
+            ${CHIP_ROOT}/src/app/app-platform/ContentAppPlatform.cpp
+            ${CHIP_ROOT}/src/app/app-platform/ContentApp.cpp
+    )
+
+    if (${ARG_SHELL_CMD})
+        target_include_directories(${target}
+            ${SCOPE}
+                ${CHIP_TV_COMMON_BASE_DIR}/shell
+        )
+
+        target_sources(${target}
+            ${SCOPE}
+                ${CHIP_TV_COMMON_BASE_DIR}/shell/AppTvShellCommands.cpp
+        )
+
+        target_compile_definitions(${target}
+            ${SCOPE}
+                CHIP_TV_APP_SHELL_CMD_ENABLE
+        )
+    endif()
+endmacro()