From feca44a50fcee9a8f8e501a1e685e2929bd65f05 Mon Sep 17 00:00:00 2001 From: amitnj <74272437+amitnj@users.noreply.github.com> Date: Mon, 9 Jan 2023 07:09:44 -0800 Subject: [PATCH] Implement UI affordance to run cert tests from the android casting app. (#24321) * Implement UI affordance to run cert tests from the android casting app. * Restyled by google-java-format * Restyled by clang-format * Restyled by gn Co-authored-by: Restyled.io --- .../tv/server/service/AppPlatformService.java | 4 + .../server/service/MatterServantService.java | 1 + examples/tv-app/android/java/AppImpl.cpp | 29 ++ examples/tv-app/android/java/AppImpl.h | 2 + .../tv-app/android/java/AppPlatform-JNI.cpp | 6 + .../matter/tv/server/tvapp/AppPlatform.java | 4 + examples/tv-app/linux/AppImpl.cpp | 24 ++ .../android/App/app/build.gradle | 4 + .../chip/casting/app/CertTestFragment.java | 401 ++++++++++++++++++ .../casting/app/ContentLauncherFragment.java | 10 +- .../com/chip/casting/app/MainActivity.java | 5 + .../casting/app/SelectClusterFragment.java | 15 + .../jni/com/chip/casting/TvCastingApp.java | 8 +- .../App/app/src/main/jni/cpp/Constants.h | 3 + .../app/src/main/jni/cpp/TvCastingApp-JNI.cpp | 115 ++++- .../main/res/layout/cert_test_status_item.xml | 13 + .../layout/fragment_cert_test_launcher.xml | 50 +++ .../res/layout/fragment_select_cluster.xml | 9 + .../App/app/src/main/res/values/strings.xml | 4 + .../tv-casting-app/tv-casting-common/BUILD.gn | 2 + .../tv-casting-common/include/CastingServer.h | 15 + .../tv-casting-common/include/OnOff.h | 49 +++ .../tv-casting-common/src/CastingServer.cpp | 21 + .../tv-casting-common/src/OnOff.cpp | 40 ++ 24 files changed, 819 insertions(+), 15 deletions(-) create mode 100644 examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CertTestFragment.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/res/layout/cert_test_status_item.xml create mode 100644 examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_cert_test_launcher.xml create mode 100644 examples/tv-casting-app/tv-casting-common/include/OnOff.h create mode 100644 examples/tv-casting-app/tv-casting-common/src/OnOff.cpp diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/AppPlatformService.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/AppPlatformService.java index d5d634015366c5..f5f54d2ff81bcd 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/AppPlatformService.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/AppPlatformService.java @@ -72,6 +72,10 @@ public void init(@NonNull Context context) { registerContentAppUpdatesReceiver(); } + public void addSelfVendorAsAdmin() { + mAppPlatform.addSelfVendorAsAdmin(); + } + private void initializeContentAppEndpoints() { // Read the metadada of previously discovered endpoints. diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServantService.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServantService.java index 978ce7dfd039ef..0d135e71d698be 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServantService.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServantService.java @@ -24,6 +24,7 @@ public void onCreate() { MatterServant.get().initCommissioner(); AppPlatformService.get().init(this.getApplicationContext()); + AppPlatformService.get().addSelfVendorAsAdmin(); } @Nullable diff --git a/examples/tv-app/android/java/AppImpl.cpp b/examples/tv-app/android/java/AppImpl.cpp index 90fc6b5d50d991..d0280edd92c074 100644 --- a/examples/tv-app/android/java/AppImpl.cpp +++ b/examples/tv-app/android/java/AppImpl.cpp @@ -44,9 +44,11 @@ #include #include #include +#include using namespace chip; using namespace chip::AppPlatform; +using namespace chip::DeviceLayer; #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED ContentAppFactoryImpl gFactory; @@ -407,6 +409,20 @@ std::list ContentAppFactoryImpl::GetAllowedClusterListForStaticEndpoi { if (endpointId == kLocalVideoPlayerEndpointId) { + if (GetVendorPrivilege(vendorId) == Access::Privilege::kAdminister) + { + ChipLogProgress(DeviceLayer, + "ContentAppFactoryImpl GetAllowedClusterListForStaticEndpoint priviledged vendor accessible clusters " + "being returned."); + return { chip::app::Clusters::Descriptor::Id, chip::app::Clusters::OnOff::Id, + chip::app::Clusters::WakeOnLan::Id, chip::app::Clusters::MediaPlayback::Id, + chip::app::Clusters::LowPower::Id, chip::app::Clusters::KeypadInput::Id, + chip::app::Clusters::ContentLauncher::Id, chip::app::Clusters::AudioOutput::Id, + chip::app::Clusters::ApplicationLauncher::Id }; + } + ChipLogProgress( + DeviceLayer, + "ContentAppFactoryImpl GetAllowedClusterListForStaticEndpoint operator vendor accessible clusters being returned."); return { chip::app::Clusters::Descriptor::Id, chip::app::Clusters::OnOff::Id, chip::app::Clusters::WakeOnLan::Id, chip::app::Clusters::MediaPlayback::Id, chip::app::Clusters::LowPower::Id, chip::app::Clusters::KeypadInput::Id, @@ -478,3 +494,16 @@ void ReportAttributeChange(EndpointId epId, chip::ClusterId clusterId, chip::Att { MatterReportingAttributeChangeCallback(epId, clusterId, attributeId); } + +void AddSelfVendorAsAdmin() +{ + uint16_t value; + if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(value) != CHIP_NO_ERROR) + { + ChipLogDetail(Discovery, "AppImpl addSelfVendorAsAdmin Vendor ID not known"); + } + else + { + gFactory.AddAdminVendorId(value); + } +} diff --git a/examples/tv-app/android/java/AppImpl.h b/examples/tv-app/android/java/AppImpl.h index df257e081577dc..fb11ee33529f70 100644 --- a/examples/tv-app/android/java/AppImpl.h +++ b/examples/tv-app/android/java/AppImpl.h @@ -60,6 +60,8 @@ EndpointId AddContentApp(const char * szVendorName, uint16_t vendorId, const cha EndpointId RemoveContentApp(EndpointId epId); void ReportAttributeChange(EndpointId epId, chip::ClusterId clusterId, chip::AttributeId attributeId); +void AddSelfVendorAsAdmin(); + #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED namespace chip { diff --git a/examples/tv-app/android/java/AppPlatform-JNI.cpp b/examples/tv-app/android/java/AppPlatform-JNI.cpp index 3675c33852bd0f..cf0ee2450cc982 100644 --- a/examples/tv-app/android/java/AppPlatform-JNI.cpp +++ b/examples/tv-app/android/java/AppPlatform-JNI.cpp @@ -87,3 +87,9 @@ JNI_METHOD(void, reportAttributeChange) ReportAttributeChange(static_cast(endpointId), static_cast(clusterId), static_cast(attributeId)); } + +JNI_METHOD(void, addSelfVendorAsAdmin) +(JNIEnv *, jobject, jint endpointId, jint clusterId, jint attributeId) +{ + AddSelfVendorAsAdmin(); +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/AppPlatform.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/AppPlatform.java index a01a50fe253361..cc8356f5be0323 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/AppPlatform.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/AppPlatform.java @@ -55,6 +55,10 @@ public native int addContentAppAtEndpoint( // Method to report attribute change for content app endpoints to the SDK public native void reportAttributeChange(int endpointId, int clusterId, int attributeId); + // Method to add the current vendorId of the node as an admin to enable clients from same vendor + // to be admins + public native void addSelfVendorAsAdmin(); + static { System.loadLibrary("TvApp"); } diff --git a/examples/tv-app/linux/AppImpl.cpp b/examples/tv-app/linux/AppImpl.cpp index d6496acdb1ad9e..75e4786f33afa6 100644 --- a/examples/tv-app/linux/AppImpl.cpp +++ b/examples/tv-app/linux/AppImpl.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include using namespace chip; @@ -502,6 +503,20 @@ std::list ContentAppFactoryImpl::GetAllowedClusterListForStaticEndpoi { if (endpointId == kLocalVideoPlayerEndpointId) { + if (GetVendorPrivilege(vendorId) == Access::Privilege::kAdminister) + { + ChipLogProgress(DeviceLayer, + "ContentAppFactoryImpl GetAllowedClusterListForStaticEndpoint priviledged vendor accessible clusters " + "being returned."); + return { chip::app::Clusters::Descriptor::Id, chip::app::Clusters::OnOff::Id, + chip::app::Clusters::WakeOnLan::Id, chip::app::Clusters::MediaPlayback::Id, + chip::app::Clusters::LowPower::Id, chip::app::Clusters::KeypadInput::Id, + chip::app::Clusters::ContentLauncher::Id, chip::app::Clusters::AudioOutput::Id, + chip::app::Clusters::ApplicationLauncher::Id }; + } + ChipLogProgress( + DeviceLayer, + "ContentAppFactoryImpl GetAllowedClusterListForStaticEndpoint operator vendor accessible clusters being returned."); return { chip::app::Clusters::Descriptor::Id, chip::app::Clusters::OnOff::Id, chip::app::Clusters::WakeOnLan::Id, chip::app::Clusters::MediaPlayback::Id, chip::app::Clusters::LowPower::Id, chip::app::Clusters::KeypadInput::Id, @@ -520,6 +535,15 @@ CHIP_ERROR InitVideoPlayerPlatform() #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED ContentAppPlatform::GetInstance().SetupAppPlatform(); ContentAppPlatform::GetInstance().SetContentAppFactory(&gFactory); + uint16_t value; + if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(value) != CHIP_NO_ERROR) + { + ChipLogDetail(Discovery, "AppImpl InitVideoPlayerPlatform Vendor ID not known"); + } + else + { + gFactory.AddAdminVendorId(value); + } #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE diff --git a/examples/tv-casting-app/android/App/app/build.gradle b/examples/tv-casting-app/android/App/app/build.gradle index b697bf8b6369d4..3dcdad715e6393 100644 --- a/examples/tv-casting-app/android/App/app/build.gradle +++ b/examples/tv-casting-app/android/App/app/build.gradle @@ -44,6 +44,10 @@ android { sourceSets { main { jniLibs.srcDirs = ['libs/jniLibs'] + java.srcDirs = [ + 'src/main/java', + 'src/main/jni', + ] // uncomment this code to debug // java.srcDirs = [ diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CertTestFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CertTestFragment.java new file mode 100644 index 00000000000000..3f7d05197a9f04 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CertTestFragment.java @@ -0,0 +1,401 @@ +package com.chip.casting.app; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import com.chip.casting.ContentApp; +import com.chip.casting.ContentLauncherTypes; +import com.chip.casting.FailureCallback; +import com.chip.casting.MatterCallbackHandler; +import com.chip.casting.MatterError; +import com.chip.casting.SuccessCallback; +import com.chip.casting.TvCastingApp; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** A {@link Fragment} to send Content Launcher commands from the TV Casting App. */ +public class CertTestFragment extends Fragment { + private static final String TAG = CertTestFragment.class.getSimpleName(); + + private final TvCastingApp tvCastingApp; + + private View.OnClickListener launchTestButtonClickListener; + private List certTestStatuses = new ArrayList(); + + private static final ContentApp kTVApp = new ContentApp((short) 1, null); + private static final ContentApp kTVAppSpeaker = new ContentApp((short) 2, null); + + private static final ContentApp kContentApp = new ContentApp((short) 4, null); + private ArrayAdapter certTestStatusesAdapter; + + public CertTestFragment(TvCastingApp tvCastingApp) { + this.tvCastingApp = tvCastingApp; + } + + /** + * Use this factory method to create a new instance of this fragment using the provided + * parameters. + * + * @param tvCastingApp TV Casting App (JNI) + * @return A new instance of fragment ContentLauncherFragment. + */ + public static CertTestFragment newInstance(TvCastingApp tvCastingApp) { + return new CertTestFragment(tvCastingApp); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + this.launchTestButtonClickListener = + new View.OnClickListener() { + @Override + public void onClick(View v) { + Activity activity = getActivity(); + certTestStatuses.clear(); + certTestStatusesAdapter.notifyDataSetChanged(); + + runCertTests(activity); + } + }; + + return inflater.inflate(R.layout.fragment_cert_test_launcher, container, false); + } + + private void runCertTests(Activity activity) { + CertTestMatterSuccessFailureCallback successFailureCallback = + new CertTestMatterSuccessFailureCallback(activity); + CertTestMatterSuccessFailureCallbackInteger successFailureCallbackInteger = + new CertTestMatterSuccessFailureCallbackInteger(successFailureCallback); + CertTestMatterCallbackHandler callback = + new CertTestMatterCallbackHandler(successFailureCallback); + + runAndWait( + "keypadInput_sendKey", + successFailureCallback, + () -> { + // 3.3.1. [TC-KEYPADINPUT-3.1] Send Key Command Verification (DUT as Client) + tvCastingApp.keypadInput_sendKey(kTVApp, (byte) 10, callback); + }); + + runAndWait( + "applicationLauncher_launchApp", + successFailureCallback, + () -> { + // 3.4.4. [TC-APPLAUNCHER-3.7.1] Launch Application Verification (DUT as Client) + tvCastingApp.applicationLauncher_launchApp( + kTVApp, (short) 123, "exampleid", new byte[] {}, callback); + }); + + runAndWait( + "applicationLauncher_stopApp", + successFailureCallback, + () -> { + // [TC-APPLAUNCHER-3.8.1] Stop Application Verification (DUT as Client) + tvCastingApp.applicationLauncher_stopApp(kTVApp, (short) 123, "exampleid", callback); + }); + + runAndWait( + "applicationLauncher_hideApp", + successFailureCallback, + () -> { + // [TC-APPLAUNCHER-3.9.1] Hide Application Verification (DUT as Client) + tvCastingApp.applicationLauncher_hideApp(kTVApp, (short) 123, "exampleid", callback); + }); + + runAndWait( + "targetNavigator_navigateTarget", + successFailureCallback, + () -> { + // 3.10.2. [TC-TGTNAV-8.2] Navigate Target Verification (DUT as Client) + tvCastingApp.targetNavigator_navigateTarget(kTVApp, (byte) 1, "", callback); + }); + + ArrayList list = new ArrayList<>(); + list.add(new ContentLauncherTypes.AdditionalInfo("imdb", "dummyId")); + + ArrayList paramList = new ArrayList<>(); + paramList.add(new ContentLauncherTypes.Parameter(13, "Dummy Video", Optional.of(list))); + + runAndWait( + "contentLauncher_launchContent", + successFailureCallback, + () -> { + // 3.12.3. [TC-CONTENTLAUNCHER-10.4] Launch Content Verification (DUT as Client) + tvCastingApp.contentLauncher_launchContent( + kTVApp, new ContentLauncherTypes.ContentSearch(paramList), true, "", callback); + }); + + runAndWait( + "contentLauncherLaunchURL", + successFailureCallback, + () -> { + // 3.12.5. [TC-CONTENTLAUNCHER-10.6] Launch URL Verification (DUT as Client) + tvCastingApp.contentLauncherLaunchURL( + kTVApp, "https://dummyurl", "Dummy Content", callback); + }); + + runAndWait( + "mediaPlayback_play", + successFailureCallback, + () -> { + // 3.8.5. [TC-MEDIAPLAYBACK-6.5] Mandatory Media Playback Verification (DUT as Client) + tvCastingApp.mediaPlayback_play(kContentApp, callback); + }); + + runAndWait( + "mediaPlayback_next", + successFailureCallback, + () -> { + // 3.8.5. [TC-MEDIAPLAYBACK-6.5] Mandatory Media Playback Verification (DUT as Client) + tvCastingApp.mediaPlayback_next(kContentApp, callback); + }); + + runAndWait( + "mediaPlayback_skipForward", + successFailureCallback, + () -> { + // 3.8.5. [TC-MEDIAPLAYBACK-6.5] Mandatory Media Playback Verification (DUT as Client) + tvCastingApp.mediaPlayback_skipForward(kContentApp, 10000, callback); + }); + + runAndWait( + "mediaPlayback_skipBackward", + successFailureCallback, + () -> { + // 3.8.5. [TC-MEDIAPLAYBACK-6.5] Mandatory Media Playback Verification (DUT as Client) + tvCastingApp.mediaPlayback_skipBackward(kContentApp, 10000, callback); + }); + + runAndWait( + "mediaPlayback_pause", + successFailureCallback, + () -> { + // 3.8.5. [TC-MEDIAPLAYBACK-6.5] Mandatory Media Playback Verification (DUT as Client) + tvCastingApp.mediaPlayback_pause(kContentApp, callback); + }); + + runAndWait( + "mediaPlayback_stopPlayback", + successFailureCallback, + () -> { + // 3.8.5. [TC-MEDIAPLAYBACK-6.5] Mandatory Media Playback Verification (DUT as Client) + tvCastingApp.mediaPlayback_stopPlayback(kContentApp, callback); + }); + + // Additional Tests + // Mandatory + // OnOff cluster + runAndWait( + "onOff_on", + successFailureCallback, + () -> { + tvCastingApp.onOff_on(kTVApp, callback); + }); + + runAndWait( + "onOff_off", + successFailureCallback, + () -> { + tvCastingApp.onOff_off(kTVApp, callback); + }); + + runAndWait( + "onOff_toggle", + successFailureCallback, + () -> { + tvCastingApp.onOff_toggle(kTVApp, callback); + }); + + // Application Basic + runAndWait( + "applicationBasic_readApplicationVersion", + successFailureCallback, + () -> { + tvCastingApp.applicationBasic_readApplicationVersion( + kContentApp, successFailureCallback, successFailureCallback); + }); + + runAndWait( + "applicationBasic_readVendorName", + successFailureCallback, + () -> { + tvCastingApp.applicationBasic_readVendorName( + kContentApp, successFailureCallback, successFailureCallback); + }); + + runAndWait( + "applicationBasic_readApplicationName", + successFailureCallback, + () -> { + tvCastingApp.applicationBasic_readApplicationName( + kContentApp, successFailureCallback, successFailureCallback); + }); + + runAndWait( + "applicationBasic_readVendorID", + successFailureCallback, + () -> { + tvCastingApp.applicationBasic_readVendorID( + kContentApp, successFailureCallbackInteger, successFailureCallbackInteger); + }); + + runAndWait( + "applicationBasic_readProductID", + successFailureCallback, + () -> { + tvCastingApp.applicationBasic_readProductID( + kContentApp, successFailureCallbackInteger, successFailureCallbackInteger); + }); + + // Unsupported & Optional + // 3.2.2. [TC-LOWPOWER-2.2] Low Power Mode Verification (DUT as Client) + // 3.5.5. [TC-MEDIAINPUT-3.14] Select Input Verification (DUT as Client) + // 3.5.6. [TC-MEDIAINPUT-3.15] Show Input Status Verification (DUT as Client) + // 3.5.7. [TC-MEDIAINPUT-3.16] Hide Input Status Verification (DUT as Client) + // 3.5.8. [TC-MEDIAINPUT-3.17] Rename Input Verification (DUT as Client) + + // 3.7.4. [TC-CHANNEL-5.4] Change Channel Verification (DUT as Client) + // 3.7.5. [TC-CHANNEL-5.5] Change Channel By Number Verification (DUT as Client) + // 3.7.6. [TC-CHANNEL-5.6] Skip Channel Verification (DUT as Client) + + // 19.9.3. [TC-AUDIOOUTPUT-7.3] Select Output Verification (DUT as Client) + // 19.9.4. [TC-AUDIOOUTPUT-7.4] Rename Output Verification (DUT as Client) + + // 3.14.2. [TC-ALOGIN-12.2] Account Login Verification (DUT as Client) + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + Log.d(TAG, "ContentLauncherFragment.onViewCreated called"); + certTestStatusesAdapter = + new ArrayAdapter( + this.getContext(), + R.layout.cert_test_status_item, + R.id.launchCertTestStatus, + certTestStatuses); + ListView launchCertTestStatusUpdatesView = + getView().findViewById(R.id.launchCertTestStatusUpdates); + launchCertTestStatusUpdatesView.setAdapter(certTestStatusesAdapter); + getView() + .findViewById(R.id.launchCertTestButton) + .setOnClickListener(launchTestButtonClickListener); + } + + private void runAndWait( + String testMethod, CertTestMatterSuccessFailureCallback callback, Runnable runnable) { + CountDownLatch cdl = new CountDownLatch(1); + callback.setTestMethod(testMethod); + callback.setCountDownLatch(cdl); + runnable.run(); + try { + if (!cdl.await(10, TimeUnit.SECONDS)) { + Log.d(TAG, "Timed out for test to finish : " + testMethod); + } + } catch (InterruptedException e) { + Log.d(TAG, "Interrupted waiting for test to finish : " + testMethod); + } + } + + private void addCertTestStatus(Activity activity, MatterError error, String testMethod) { + Log.d(TAG, "Cert Test Status for " + testMethod + " : " + error); + certTestStatuses.add(testMethod + ":" + (error.isNoError() ? "Success!" : "Failure!")); + activity.runOnUiThread( + () -> { + certTestStatusesAdapter.notifyDataSetChanged(); + }); + } + + class CertTestMatterCallbackHandler extends MatterCallbackHandler { + private CertTestMatterSuccessFailureCallback delegate; + + CertTestMatterCallbackHandler(CertTestMatterSuccessFailureCallback delegate) { + this.delegate = delegate; + } + + @Override + public void handle(MatterError error) { + delegate.handle(error); + } + } + + class CertTestMatterSuccessFailureCallback extends FailureCallback + implements SuccessCallback { + private Activity activity; + private String testMethod; + private CountDownLatch cdl; + + CertTestMatterSuccessFailureCallback(Activity activity) { + this.activity = activity; + } + + void setTestMethod(String testMethod) { + this.testMethod = testMethod; + } + + public void setCountDownLatch(CountDownLatch cdl) { + this.cdl = cdl; + } + + @Override + public void handle(MatterError error) { + try { + cdl.countDown(); + addCertTestStatus(activity, error, testMethod); + } catch (Exception e) { + Log.e( + TAG, + "Exception when handling matter callback when running test method " + testMethod, + e); + } + } + + @Override + public void handle(String response) { + try { + cdl.countDown(); + addCertTestStatus(activity, MatterError.NO_ERROR, testMethod); + } catch (Exception e) { + Log.e( + TAG, + "Exception when handling matter callback when running test method " + testMethod, + e); + } + } + } + + class CertTestMatterSuccessFailureCallbackInteger extends FailureCallback + implements SuccessCallback { + + private CertTestMatterSuccessFailureCallback delegate; + + CertTestMatterSuccessFailureCallbackInteger(CertTestMatterSuccessFailureCallback delegate) { + this.delegate = delegate; + } + + @Override + public void handle(MatterError error) { + delegate.handle(error); + } + + @Override + public void handle(Integer response) { + delegate.handle(response.toString()); + } + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ContentLauncherFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ContentLauncherFragment.java index c1bb7dba3d6c42..2c3db2bc01f6d2 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ContentLauncherFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ContentLauncherFragment.java @@ -61,9 +61,13 @@ public void onClick(View v) { new MatterCallbackHandler() { @Override public void handle(MatterError error) { - Log.d(TAG, "handle() called on LaunchURLResponse with " + error); - TextView launchUrlStatus = getView().findViewById(R.id.launchUrlStatus); - launchUrlStatus.setText(error.isNoError() ? "Success!" : "Failure!"); + try { + Log.d(TAG, "handle() called on LaunchURLResponse with " + error); + TextView launchUrlStatus = getView().findViewById(R.id.launchUrlStatus); + launchUrlStatus.setText(error.isNoError() ? "Success!" : "Failure!"); + } catch (Exception e) { + Log.e(TAG, "Exception in handler", e); + } } }); } diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java index a9884bfdb88eac..03d18735edbf35 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java @@ -51,6 +51,11 @@ public void handleContentLauncherSelected() { showFragment(ContentLauncherFragment.newInstance(tvCastingApp)); } + @Override + public void handleCertTestLauncherSelected() { + showFragment(CertTestFragment.newInstance(tvCastingApp)); + } + @Override public void handleMediaPlaybackSelected() { showFragment(MediaPlaybackFragment.newInstance(tvCastingApp)); diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/SelectClusterFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/SelectClusterFragment.java index f80f286ea3df22..7f5277aeb81138 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/SelectClusterFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/SelectClusterFragment.java @@ -17,6 +17,7 @@ public class SelectClusterFragment extends Fragment { private View.OnClickListener selectContentLauncherButtonClickListener; private View.OnClickListener selectMediaPlaybackButtonClickListener; + private View.OnClickListener selectCertTestButtonClickListener; private View.OnClickListener disconnectButtonClickListener; public SelectClusterFragment(TvCastingApp tvCastingApp) { @@ -61,6 +62,14 @@ public void onClick(View v) { } }; + this.selectCertTestButtonClickListener = + new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(TAG, "handle() called on selectCertTestButtonClickListener"); + callback.handleCertTestLauncherSelected(); + } + }; this.disconnectButtonClickListener = new View.OnClickListener() { @Override @@ -84,6 +93,9 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { getView() .findViewById(R.id.selectMediaPlaybackButton) .setOnClickListener(selectMediaPlaybackButtonClickListener); + getView() + .findViewById(R.id.selectCertTestButton) + .setOnClickListener(selectCertTestButtonClickListener); getView().findViewById(R.id.disconnectButton).setOnClickListener(disconnectButtonClickListener); } @@ -97,5 +109,8 @@ public interface Callback { /** Notifies listener to trigger transition on click of the Disconnect button */ void handleDisconnect(); + + /** Notifies listener to trigger transition on click of the Cert Test button */ + void handleCertTestLauncherSelected(); } } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TvCastingApp.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TvCastingApp.java index d483844a79c26b..c34bb129b2b64d 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TvCastingApp.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TvCastingApp.java @@ -399,7 +399,13 @@ public native boolean applicationBasic_readProductID( public native boolean applicationBasic_readApplicationVersion( ContentApp contentApp, SuccessCallback readSuccessHandler, - FailureCallback readFailureHandlerr); + FailureCallback readFailureHandler); + + public native boolean onOff_on(ContentApp contentApp, Object responseHandler); + + public native boolean onOff_off(ContentApp contentApp, Object responseHandler); + + public native boolean onOff_toggle(ContentApp contentApp, Object responseHandler); static { System.loadLibrary("TvCastingApp"); diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/Constants.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/Constants.h index 334e1180e13f72..293e6683f4509b 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/Constants.h +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/Constants.h @@ -23,6 +23,9 @@ enum MediaCommandName ContentLauncher_LaunchContent, LevelControl_Step, LevelControl_MoveToLevel, + OnOff_On, + OnOff_Off, + OnOff_Toggle, MediaPlayback_Play, MediaPlayback_Pause, MediaPlayback_StopPlayback, diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp index 7ac67e67f4f7d6..079c695a3bcd1d 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp @@ -452,7 +452,9 @@ JNI_METHOD(jboolean, contentLauncher_1subscribeToSupportedStreamingProtocols) err = TvCastingAppJNIMgr().getSupportedStreamingProtocolsSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); - err = TvCastingAppJNIMgr().getReadFailureHandler(ContentLauncher_SupportedStreamingProtocols).SetUp(env, jReadFailureHandler); + err = TvCastingAppJNIMgr() + .getSubscriptionReadFailureHandler(ContentLauncher_SupportedStreamingProtocols) + .SetUp(env, jReadFailureHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -469,7 +471,7 @@ JNI_METHOD(jboolean, contentLauncher_1subscribeToSupportedStreamingProtocols) TvCastingAppJNIMgr().getSupportedStreamingProtocolsSuccessHandler().Handle(responseData); }, [](void * context, CHIP_ERROR err) { - TvCastingAppJNIMgr().getReadFailureHandler(ContentLauncher_SupportedStreamingProtocols).Handle(err); + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ContentLauncher_SupportedStreamingProtocols).Handle(err); }, static_cast(minInterval), static_cast(maxInterval), [](void * context) { @@ -707,6 +709,97 @@ JNI_METHOD(jboolean, levelControl_1subscribeToMaxLevel) return true; } +JNI_METHOD(jboolean, onOff_1on) +(JNIEnv * env, jobject, jobject contentApp, jobject jResponseHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD onOff_on called"); + + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(OnOff_On).SetUp(env, jResponseHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->OnOff_On( + &endpoint, [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(OnOff_On).Handle(err); }); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.OnOff_On failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, onOff_1off) +(JNIEnv * env, jobject, jobject contentApp, jobject jResponseHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD onOff_off called"); + + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(OnOff_Off).SetUp(env, jResponseHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->OnOff_Off( + &endpoint, [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(OnOff_Off).Handle(err); }); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.OnOff_Off failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, onOff_1toggle) +(JNIEnv * env, jobject, jobject contentApp, jobject jResponseHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD onOff_toggle called"); + + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(OnOff_Toggle).SetUp(env, jResponseHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->OnOff_Toggle( + &endpoint, [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(OnOff_Toggle).Handle(err); }); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.OnOff_Toggle failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + JNI_METHOD(jboolean, mediaPlayback_1play) (JNIEnv * env, jobject, jobject contentApp, jobject jResponseHandler) { @@ -1809,7 +1902,7 @@ JNI_METHOD(jboolean, applicationBasic_1readVendorName) err = CastingServer::GetInstance()->ApplicationBasic_ReadVendorName( &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType responseData) { - TvCastingAppJNIMgr().getVendorNameSuccessHandler().Handle(responseData); + TvCastingAppJNIMgr().getReadVendorNameSuccessHandler().Handle(responseData); }, [](void * context, CHIP_ERROR err) { TvCastingAppJNIMgr().getReadFailureHandler(ApplicationBasic_VendorName).Handle(err); @@ -1841,7 +1934,7 @@ JNI_METHOD(jboolean, applicationBasic_1readVendorID) ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, err.Format())); - err = TvCastingAppJNIMgr().getVendorIDSuccessHandler().SetUp(env, jReadSuccessHandler); + err = TvCastingAppJNIMgr().getReadVendorIDSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getReadFailureHandler(ApplicationBasic_VendorID).SetUp(env, jReadFailureHandler); @@ -1851,7 +1944,7 @@ JNI_METHOD(jboolean, applicationBasic_1readVendorID) err = CastingServer::GetInstance()->ApplicationBasic_ReadVendorID( &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType responseData) { - TvCastingAppJNIMgr().getVendorIDSuccessHandler().Handle(responseData); + TvCastingAppJNIMgr().getReadVendorIDSuccessHandler().Handle(responseData); }, [](void * context, CHIP_ERROR err) { TvCastingAppJNIMgr().getReadFailureHandler(ApplicationBasic_VendorID).Handle(err); }); @@ -1880,7 +1973,7 @@ JNI_METHOD(jboolean, applicationBasic_1readApplicationName) ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, err.Format())); - err = TvCastingAppJNIMgr().getApplicationNameSuccessHandler().SetUp(env, jReadSuccessHandler); + err = TvCastingAppJNIMgr().getReadApplicationNameSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getReadFailureHandler(ApplicationBasic_ApplicationName).SetUp(env, jReadFailureHandler); @@ -1891,7 +1984,7 @@ JNI_METHOD(jboolean, applicationBasic_1readApplicationName) &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType responseData) { - TvCastingAppJNIMgr().getApplicationNameSuccessHandler().Handle(responseData); + TvCastingAppJNIMgr().getReadApplicationNameSuccessHandler().Handle(responseData); }, [](void * context, CHIP_ERROR err) { TvCastingAppJNIMgr().getReadFailureHandler(ApplicationBasic_ApplicationName).Handle(err); @@ -1923,7 +2016,7 @@ JNI_METHOD(jboolean, applicationBasic_1readProductID) ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, err.Format())); - err = TvCastingAppJNIMgr().getProductIDSuccessHandler().SetUp(env, jReadSuccessHandler); + err = TvCastingAppJNIMgr().getReadProductIDSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getReadFailureHandler(ApplicationBasic_ProductID).SetUp(env, jReadFailureHandler); @@ -1933,7 +2026,7 @@ JNI_METHOD(jboolean, applicationBasic_1readProductID) err = CastingServer::GetInstance()->ApplicationBasic_ReadProductID( &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType responseData) { - TvCastingAppJNIMgr().getProductIDSuccessHandler().Handle(responseData); + TvCastingAppJNIMgr().getReadProductIDSuccessHandler().Handle(responseData); }, [](void * context, CHIP_ERROR err) { TvCastingAppJNIMgr().getReadFailureHandler(ApplicationBasic_ProductID).Handle(err); }); @@ -1962,7 +2055,7 @@ JNI_METHOD(jboolean, applicationBasic_1readApplicationVersion) ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, err.Format())); - err = TvCastingAppJNIMgr().getApplicationVersionSuccessHandler().SetUp(env, jReadSuccessHandler); + err = TvCastingAppJNIMgr().getReadApplicationVersionSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getReadFailureHandler(ApplicationBasic_ApplicationVersion).SetUp(env, jReadFailureHandler); @@ -1973,7 +2066,7 @@ JNI_METHOD(jboolean, applicationBasic_1readApplicationVersion) &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType responseData) { - TvCastingAppJNIMgr().getApplicationVersionSuccessHandler().Handle(responseData); + TvCastingAppJNIMgr().getReadApplicationVersionSuccessHandler().Handle(responseData); }, [](void * context, CHIP_ERROR err) { TvCastingAppJNIMgr().getReadFailureHandler(ApplicationBasic_ApplicationVersion).Handle(err); diff --git a/examples/tv-casting-app/android/App/app/src/main/res/layout/cert_test_status_item.xml b/examples/tv-casting-app/android/App/app/src/main/res/layout/cert_test_status_item.xml new file mode 100644 index 00000000000000..b1f1a1ed9e7604 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/res/layout/cert_test_status_item.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_cert_test_launcher.xml b/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_cert_test_launcher.xml new file mode 100644 index 00000000000000..f92d3e3957bbdc --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_cert_test_launcher.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + +