From 0e974b3c0abb05f11ce7592cfa2154306b9293f3 Mon Sep 17 00:00:00 2001 From: Sharad Binjola Date: Fri, 5 Apr 2024 11:43:18 -0700 Subject: [PATCH] tv-casting-app: Implemented getDeviceProxy, used android chip IM --- .../casting/util/GlobalCastingConstants.java | 2 +- ...ntentLauncherLaunchURLExampleFragment.java | 42 +++++++++- .../matter/casting/core/MatterEndpoint.java | 5 ++ .../main/jni/cpp/core/MatterEndpoint-JNI.cpp | 25 +++++- .../main/jni/cpp/core/MatterEndpoint-JNI.h | 12 +++ .../main/jni/cpp/support/Converters-JNI.cpp | 24 ++++++ .../src/main/jni/cpp/support/Converters-JNI.h | 2 + .../main/jni/cpp/support/MatterCallback-JNI.h | 3 +- examples/tv-casting-app/android/BUILD.gn | 77 ++++++++++++++++++- 9 files changed, 187 insertions(+), 5 deletions(-) diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java index d063cc7e6f78c5..754d3bbe5ff4fd 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java @@ -6,5 +6,5 @@ public class GlobalCastingConstants { public static final int SetupPasscode = 20202021; public static final int Discriminator = 0xF00; public static final boolean ChipCastingSimplified = - false; // set this flag to true to demo simplified casting APIs + true; // set this flag to true to demo simplified casting APIs } diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ContentLauncherLaunchURLExampleFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ContentLauncherLaunchURLExampleFragment.java index c1bde0f9bb0323..5f0d7c6d16677f 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ContentLauncherLaunchURLExampleFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ContentLauncherLaunchURLExampleFragment.java @@ -23,10 +23,15 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import chip.devicecontroller.ChipClusters; import com.R; import com.matter.casting.core.CastingPlayer; import com.matter.casting.core.Endpoint; +import com.matter.casting.core.MatterEndpoint; +import com.matter.casting.support.MatterCallback; +import com.matter.casting.support.MatterError; import java.util.List; +import java.util.Optional; /** A {@link Fragment} to send Content Launcher LaunchURL command from the TV Casting App. */ public class ContentLauncherLaunchURLExampleFragment extends Fragment { @@ -73,7 +78,42 @@ public View onCreateView( return; } - // TODO: add command invocation API call + // TODO: complete command invocation API implementation + ((MatterEndpoint) endpoint) + .getDeviceProxy( + new MatterCallback() { + @Override + public void handle(Long device) { + Log.d(TAG, "getDeviceProxy success. Device: " + device); + + if (device != null) { + ChipClusters.ContentLauncherCluster cluster = + new ChipClusters.ContentLauncherCluster(device, endpoint.getId()); + Log.d(TAG, "Content launcher cluster created " + cluster); + cluster.launchURL( + new ChipClusters.ContentLauncherCluster.LauncherResponseCallback() { + @Override + public void onSuccess(Integer status, Optional data) { + Log.d(TAG, "Content launcher success " + status + data); + } + + @Override + public void onError(Exception error) { + Log.e(TAG, "Content launcher failure " + error); + } + }, + "my test url", + Optional.of("my display str"), + Optional.empty()); + } + } + }, + new MatterCallback() { + @Override + public void handle(MatterError err) { + Log.e(TAG, "getDeviceProxy err" + err); + } + }); }; return inflater.inflate(R.layout.fragment_content_launcher, container, false); } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/MatterEndpoint.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/MatterEndpoint.java index b9dd564d6ff95f..286777dee86b31 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/MatterEndpoint.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/MatterEndpoint.java @@ -17,6 +17,8 @@ package com.matter.casting.core; import com.matter.casting.support.DeviceTypeStruct; +import com.matter.casting.support.MatterCallback; +import com.matter.casting.support.MatterError; import java.util.List; import java.util.Objects; @@ -39,6 +41,9 @@ public class MatterEndpoint implements Endpoint { @Override public native CastingPlayer getCastingPlayer(); + public native void getDeviceProxy( + MatterCallback successCallback, MatterCallback failureCallback); + @Override public String toString() { return "MatterEndpoint{" + "id=" + getId() + '}'; diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterEndpoint-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterEndpoint-JNI.cpp index 2e28b873599a9a..e0c41ebc92d260 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterEndpoint-JNI.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterEndpoint-JNI.cpp @@ -19,7 +19,6 @@ #include "MatterEndpoint-JNI.h" #include "../JNIDACProvider.h" -#include "../support/Converters-JNI.h" #include "../support/MatterCallback-JNI.h" #include "../support/RotatingDeviceIdUniqueIdProvider-JNI.h" #include "clusters/Clusters.h" // from tv-casting-common @@ -86,6 +85,30 @@ JNI_METHOD(jobject, getCastingPlayer) return support::convertCastingPlayerFromCppToJava(std::shared_ptr(endpoint->GetCastingPlayer())); } +JNI_METHOD(void, getDeviceProxy) +(JNIEnv * env, jobject thiz, jobject jSuccessCallback, jobject jFailureCallback) +{ + chip::DeviceLayer::StackLock lock; + ChipLogProgress(AppServer, "MatterEndpoint-JNI::getDeviceProxy() called"); + Endpoint * endpoint = support::convertEndpointFromJavaToCpp(thiz); + VerifyOrReturn(endpoint != nullptr, ChipLogError(AppServer, "MatterEndpoint-JNI::getDeviceProxy() endpoint == nullptr")); + + ReturnOnFailure(MatterEndpointJNIMgr().mGetDeviceProxySuccessHandler.SetUp(env, jSuccessCallback)); + ReturnOnFailure(MatterEndpointJNIMgr().mGetDeviceProxyFailureHandler.SetUp(env, jFailureCallback)); + + endpoint->GetCastingPlayer()->FindOrEstablishSession( + nullptr, + [](void * context, chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle) { + ChipLogProgress(AppServer, "MatterEndpointJNI FindOrEstablishSession success"); + OperationalDeviceProxy * device = new OperationalDeviceProxy(&exchangeMgr, sessionHandle); // TODO: delete *device + MatterEndpointJNIMgr().mGetDeviceProxySuccessHandler.Handle(device); + }, + [](void * context, const chip::ScopedNodeId & peerId, CHIP_ERROR error) { + ChipLogError(AppServer, "MatterEndpointJNI FindOrEstablishSession failure %" CHIP_ERROR_FORMAT, error.Format()); + MatterEndpointJNIMgr().mGetDeviceProxyFailureHandler.Handle(error); + }); +} + }; // namespace core }; // namespace casting }; // namespace matter diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterEndpoint-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterEndpoint-JNI.h index f9534435ab1903..2c65ca448b6f29 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterEndpoint-JNI.h +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterEndpoint-JNI.h @@ -18,8 +18,11 @@ #pragma once +#include "../support/Converters-JNI.h" +#include "../support/MatterCallback-JNI.h" #include "core/Endpoint.h" // from tv-casting-common +#include #include #include #include @@ -30,6 +33,15 @@ namespace core { class MatterEndpointJNI { +public: + MatterEndpointJNI() : + mGetDeviceProxySuccessHandler([](chip::DeviceProxy * device) -> jobject { + return support::convertLongFromCppToJava(reinterpret_cast(device)); + }) + {} + support::MatterCallbackJNI mGetDeviceProxySuccessHandler; + support::MatterFailureCallbackJNI mGetDeviceProxyFailureHandler; + private: friend MatterEndpointJNI & MatterEndpointJNIMgr(); static MatterEndpointJNI sInstance; diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.cpp index 9798f2b48b9359..aa5ef2b25f0096 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.cpp @@ -25,6 +25,30 @@ namespace support { using namespace chip; +jobject convertLongFromCppToJava(jlong value) +{ + ChipLogProgress(AppServer, "convertLongFromCppToJava called"); + JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnValue(env != nullptr, nullptr, ChipLogError(AppServer, "Could not get JNIEnv for current thread")); + + jclass responseTypeClass = env->FindClass("java/lang/Long"); + if (responseTypeClass == nullptr) + { + ChipLogError(AppServer, "ConvertToJObject: Class for Response Type not found!"); + env->ExceptionClear(); + return nullptr; + } + + jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(J)V"); + if (constructor == nullptr) + { + ChipLogError(AppServer, "Failed to access Long constructor"); + env->ExceptionClear(); + return nullptr; + } + return env->NewObject(responseTypeClass, constructor, value); +} + jobject convertMatterErrorFromCppToJava(CHIP_ERROR inErr) { ChipLogProgress(AppServer, "convertMatterErrorFromCppToJava() called"); diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.h index ecc3a95d15bd74..aa96af0668f5d4 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.h +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/Converters-JNI.h @@ -29,6 +29,8 @@ namespace matter { namespace casting { namespace support { +jobject convertLongFromCppToJava(jlong value); + jobject convertMatterErrorFromCppToJava(CHIP_ERROR inErr); /** diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/MatterCallback-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/MatterCallback-JNI.h index 3c56c426359d5c..82894e075ea912 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/MatterCallback-JNI.h +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/MatterCallback-JNI.h @@ -43,6 +43,7 @@ class MatterCallbackJNI ChipLogProgress(AppServer, "MatterCallbackJNI::SetUp called"); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NO_ENV, ChipLogError(AppServer, "JNIEnv was null!")); + mCallbackObject.Reset(); ReturnErrorOnFailure(mCallbackObject.Init(inCallback)); jclass mClazz = env->GetObjectClass(mCallbackObject.ObjectRef()); @@ -53,7 +54,7 @@ class MatterCallbackJNI VerifyOrReturnError(mSuperClazz != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND, ChipLogError(AppServer, "Failed to get callback's parent's Java class")); - mMethod = env->GetMethodID(mClazz, "handleInternal", mMethodSignature); + mMethod = env->GetMethodID(mSuperClazz, "handleInternal", mMethodSignature); VerifyOrReturnError( mMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND, ChipLogError(AppServer, "Failed to access 'handleInternal' method with signature %s", mMethodSignature)); diff --git a/examples/tv-casting-app/android/BUILD.gn b/examples/tv-casting-app/android/BUILD.gn index 52a3342773175b..6747bea95bc91d 100644 --- a/examples/tv-casting-app/android/BUILD.gn +++ b/examples/tv-casting-app/android/BUILD.gn @@ -55,6 +55,7 @@ shared_library("jni") { "${chip_root}/examples/tv-casting-app/tv-casting-common", "${chip_root}/src/app/data-model:heap", "${chip_root}/src/app/server/java:jni", + "${chip_root}/src/controller/java:android_chip_im", "${chip_root}/src/lib", "${chip_root}/third_party/inipp", ] @@ -120,7 +121,81 @@ android_library("java") { "App/app/src/main/jni/com/matter/casting/support/MatterError.java", ] - javac_flags = [ "-Xlint:deprecation" ] + # Android CHIP IM .java files + sources += [ + "${chip_root}/src/controller/java/src/chip/devicecontroller/ChipClusterException.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/ChipInteractionClient.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/ExtendableInvokeCallback.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/ExtendableInvokeCallbackJni.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/InvokeCallback.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/InvokeCallbackJni.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/ReportCallback.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/ReportCallbackJni.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/ResubscriptionAttemptCallback.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/StatusException.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/SubscriptionEstablishedCallback.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/WriteAttributesCallback.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/WriteAttributesCallbackJni.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/AttributeState.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/AttributeWriteRequest.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/ChipAttributePath.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/ChipEventPath.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/ChipPathId.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/ClusterState.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/DataVersionFilter.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/EndpointState.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/EventState.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/InvokeElement.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/InvokeResponseData.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/NoInvokeResponseData.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/NodeState.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/model/Status.java", + ] + + if (matter_enable_tlv_decoder_api) { + sources += [ "${chip_root}/src/controller/java/src/chip/devicecontroller/ChipTLVValueDecoder.java" ] + } + + if (matter_enable_java_generated_api) { + sources += [ + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java", + "${chip_root}/src/controller/java/src/chip/clusterinfo/ClusterCommandCallback.java", + "${chip_root}/src/controller/java/src/chip/clusterinfo/ClusterInfo.java", + "${chip_root}/src/controller/java/src/chip/clusterinfo/CommandParameterInfo.java", + "${chip_root}/src/controller/java/src/chip/clusterinfo/CommandResponseInfo.java", + "${chip_root}/src/controller/java/src/chip/clusterinfo/DelegatedClusterCallback.java", + "${chip_root}/src/controller/java/src/chip/clusterinfo/InteractionInfo.java", + "${chip_root}/src/controller/java/src/chip/devicecontroller/ChipTLVType.java", + ] + } + + deps += [ + "${chip_root}/src/controller/java/:chipcluster", + "${chip_root}/src/controller/java/:chipclusterID", + "${chip_root}/third_party/java_deps:annotation", + ] + + if (matter_enable_java_compilation) { + deps += [ + "${chip_root}/third_party/java_deps:json", + "${chip_root}/third_party/java_deps/stub_src", + ] + } else { + deps += [ "${chip_root}/src/controller/java/:android" ] + + data_deps += [ "${chip_root}/build/chip/java:shared_cpplib" ] + } + + javac_flags = [ + "-Xlint:deprecation", + "-parameters", # Store infomation about method parameters + ] # TODO: add classpath support (we likely need to add something like # ..../platforms/android-26/android.jar to access BLE items)