From 957034dba30807bbb0305f4c40320de9baff936a Mon Sep 17 00:00:00 2001 From: Sharad Binjola <31142146+sharadb-amazon@users.noreply.github.com> Date: Wed, 26 Oct 2022 14:07:03 -0700 Subject: [PATCH] tv-casting-app: ShutdownAllSubscriptions and Disconnect APIs (#23350) --- .../com/chip/casting/app/MainActivity.java | 7 ++++- .../casting/app/MediaPlaybackFragment.java | 15 +++++++++++ .../casting/app/SelectClusterFragment.java | 27 +++++++++++++++++-- .../jni/com/chip/casting/TvCastingApp.java | 8 ++++-- .../jni/cpp/MatterCallbackHandler-JNI.cpp | 11 ++++---- .../app/src/main/jni/cpp/TvCastingApp-JNI.cpp | 15 +++++++++++ .../res/layout/fragment_media_playback.xml | 14 ++++++++++ .../res/layout/fragment_select_cluster.xml | 20 +++++++++++--- .../App/app/src/main/res/values/strings.xml | 2 ++ .../CastingServerBridge.h | 18 +++++++++++++ .../CastingServerBridge.mm | 22 +++++++++++++++ .../tv-casting-common/include/CastingServer.h | 10 +++++++ .../tv-casting-common/src/CastingServer.cpp | 22 +++++++++++++++ 13 files changed, 177 insertions(+), 14 deletions(-) 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 d2a4327685b832..85812285fe581e 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 @@ -53,7 +53,7 @@ public void handleCommissioningButtonClicked(DiscoveredNodeData commissioner) { @Override public void handleCommissioningComplete() { - showFragment(SelectClusterFragment.newInstance()); + showFragment(SelectClusterFragment.newInstance(tvCastingApp)); } @Override @@ -66,6 +66,11 @@ public void handleMediaPlaybackSelected() { showFragment(MediaPlaybackFragment.newInstance(tvCastingApp)); } + @Override + public void handleDisconnect() { + showFragment(CommissionerDiscoveryFragment.newInstance(tvCastingApp)); + } + /** * The order is important, must first new TvCastingApp to load dynamic library, then * AndroidChipPlatform to prepare platform, then start ChipAppServer, then call init on diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MediaPlaybackFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MediaPlaybackFragment.java index ad0df7878dc63c..7e9070665b74b4 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MediaPlaybackFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MediaPlaybackFragment.java @@ -24,6 +24,8 @@ public class MediaPlaybackFragment extends Fragment { private View.OnClickListener subscribeToCurrentStateButtonClickListener; + private View.OnClickListener shutdownALlSubscriptionsButtonClickListener; + private static final ContentApp kContentApp = new ContentApp((short) 4, null); public MediaPlaybackFragment(TvCastingApp tvCastingApp) { @@ -123,6 +125,15 @@ public void run() { } }; + this.shutdownALlSubscriptionsButtonClickListener = + new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(TAG, "Shutting down all subscriptions"); + tvCastingApp.shutdownAllSubscriptions(); + } + }; + return inflater.inflate(R.layout.fragment_media_playback, container, false); } @@ -133,5 +144,9 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { getView() .findViewById(R.id.subscribeToCurrentStateButton) .setOnClickListener(subscribeToCurrentStateButtonClickListener); + + getView() + .findViewById(R.id.shutdownAllSubscriptionsButton) + .setOnClickListener(shutdownALlSubscriptionsButtonClickListener); } } 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 67de30838b296d..f80f286ea3df22 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 @@ -7,22 +7,31 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.chip.casting.TvCastingApp; /** An interstitial {@link Fragment} to select one of the supported media actions to perform */ public class SelectClusterFragment extends Fragment { private static final String TAG = SelectClusterFragment.class.getSimpleName(); + private final TvCastingApp tvCastingApp; + private View.OnClickListener selectContentLauncherButtonClickListener; private View.OnClickListener selectMediaPlaybackButtonClickListener; + private View.OnClickListener disconnectButtonClickListener; + + public SelectClusterFragment(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 SelectActionFragment. */ - public static SelectClusterFragment newInstance() { - return new SelectClusterFragment(); + public static SelectClusterFragment newInstance(TvCastingApp tvCastingApp) { + return new SelectClusterFragment(tvCastingApp); } @Override @@ -52,6 +61,16 @@ public void onClick(View v) { } }; + this.disconnectButtonClickListener = + new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(TAG, "Disconnecting from current video player"); + tvCastingApp.disconnect(); + callback.handleDisconnect(); + } + }; + return inflater.inflate(R.layout.fragment_select_cluster, container, false); } @@ -65,6 +84,7 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { getView() .findViewById(R.id.selectMediaPlaybackButton) .setOnClickListener(selectMediaPlaybackButtonClickListener); + getView().findViewById(R.id.disconnectButton).setOnClickListener(disconnectButtonClickListener); } /** Interface for notifying the host. */ @@ -74,5 +94,8 @@ public interface Callback { /** Notifies listener to trigger transition on selection of Media Playback cluster */ void handleMediaPlaybackSelected(); + + /** Notifies listener to trigger transition on click of the Disconnect button */ + void handleDisconnect(); } } 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 20235ae21b38e2..65cd2cbcec1902 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 @@ -95,6 +95,10 @@ public native boolean verifyOrEstablishConnection( FailureCallback onConnectionFailure, SuccessCallback onNewOrUpdatedEndpointCallback); + public native void shutdownAllSubscriptions(); + + public native void disconnect(); + public native List getActiveTargetVideoPlayers(); /* @@ -328,7 +332,7 @@ public native boolean applicationBasic_readVendorName( public native boolean applicationBasic_readVendorID( ContentApp contentApp, - SuccessCallback readSuccessHandler, + SuccessCallback readSuccessHandler, FailureCallback readFailureHandler); public native boolean applicationBasic_readApplicationName( @@ -338,7 +342,7 @@ public native boolean applicationBasic_readApplicationName( public native boolean applicationBasic_readProductID( ContentApp contentApp, - SuccessCallback readSuccessHandler, + SuccessCallback readSuccessHandler, FailureCallback readFailureHandler); public native boolean applicationBasic_readApplicationVersion( diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.cpp index 862334ae1ee4cb..2d78fe461a6c2e 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.cpp @@ -34,7 +34,7 @@ CHIP_ERROR CallbackBaseJNI::SetUp(JNIEnv * env, jobject inHandler) mMethod = env->GetMethodID(mClazz, "handle", mMethodSignature); if (mMethod == nullptr) { - ChipLogError(AppServer, "Failed to access 'handle' method"); + ChipLogError(AppServer, "Failed to access 'handle' method with signature %s", mMethodSignature); env->ExceptionClear(); } @@ -50,7 +50,7 @@ CHIP_ERROR CallbackBaseJNI::SetUp(JNIEnv * env, jobject inHandler) void FailureHandlerJNI::Handle(CHIP_ERROR callbackErr) { - ChipLogProgress(AppServer, "FailureHandlerJNI::Handle called"); + ChipLogProgress(AppServer, "Handle(CHIP_ERROR) called"); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); UtfString jniCallbackErrString(env, callbackErr.AsString()); @@ -63,7 +63,7 @@ void FailureHandlerJNI::Handle(CHIP_ERROR callbackErr) exit: if (err != CHIP_NO_ERROR) { - ChipLogError(AppServer, "FailureHandlerJNI::Handle status error: %s", err.AsString()); + ChipLogError(AppServer, "Handle(CHIP_ERROR) status error: %s", err.AsString()); } } @@ -332,9 +332,10 @@ jobject TargetListSuccessHandlerJNI::ConvertToJObject( return nullptr; } - jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(Ljava/lang/Integer;java/lang/String;)V"); + jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(Ljava/lang/Integer;Ljava/lang/String;)V"); chip::UtfString targetInfoName(env, targetInfo.name); - jobject jTargetInfo = env->NewObject(responseTypeClass, constructor, targetInfo.identifier, targetInfoName.jniValue()); + jobject jTargetInfo = env->NewObject(responseTypeClass, constructor, ConvertToIntegerJObject(targetInfo.identifier), + targetInfoName.jniValue()); chip::JniReferences::GetInstance().AddToList(jArrayList, jTargetInfo); } 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 33d7c753bf9042..04c1196fcd57fe 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 @@ -204,6 +204,21 @@ JNI_METHOD(jboolean, verifyOrEstablishConnection) return true; } +JNI_METHOD(void, shutdownAllSubscriptions)(JNIEnv * env, jobject) +{ + chip::DeviceLayer::StackLock lock; + ChipLogProgress(AppServer, "JNI_METHOD shutdownAllSubscriptions called"); + + CastingServer::GetInstance()->ShutdownAllSubscriptions(); +} + +JNI_METHOD(void, disconnect)(JNIEnv * env, jobject) +{ + chip::DeviceLayer::StackLock lock; + ChipLogProgress(AppServer, "JNI_METHOD disconnect called"); + CastingServer::GetInstance()->Disconnect(); +} + JNI_METHOD(jobject, getActiveTargetVideoPlayers)(JNIEnv * env, jobject) { chip::DeviceLayer::StackLock lock; diff --git a/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_media_playback.xml b/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_media_playback.xml index fac656c8c447a5..4aea6b35967ed5 100644 --- a/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_media_playback.xml +++ b/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_media_playback.xml @@ -102,5 +102,19 @@ android:layout_height="wrap_content" android:textAppearance="@style/TextAppearance.AppCompat.Large" /> + + +