From de60240309e109e01159977b6ea5e22ad439adf1 Mon Sep 17 00:00:00 2001 From: Sharad Binjola Date: Fri, 16 Sep 2022 09:50:39 -0700 Subject: [PATCH] Extending Media attribute subscriptions to Android tv-casting-app and lib --- .../casting/app/CommissioningFragment.java | 7 +- .../casting/app/ContentLauncherFragment.java | 7 +- .../com/chip/casting/app/MainActivity.java | 14 +- .../casting/app/MediaPlaybackFragment.java | 133 +++ .../casting/app/SelectClusterFragment.java | 78 ++ .../chip/casting/ContentLauncherTypes.java | 96 ++ .../jni/com/chip/casting/FailureCallback.java | 26 + .../chip/casting/MatterCallbackHandler.java | 52 +- .../jni/com/chip/casting/MatterError.java | 66 ++ .../com/chip/casting/MediaPlaybackTypes.java | 56 ++ .../SubscriptionEstablishedCallback.java | 22 + .../jni/com/chip/casting/SuccessCallback.java | 22 + .../chip/casting/TargetNavigatorTypes.java | 44 + .../jni/com/chip/casting/TvCastingApp.java | 132 +++ .../App/app/src/main/jni/cpp/Constants.h | 26 + .../jni/cpp/MatterCallbackHandler-JNI.cpp | 331 ++++++- .../main/jni/cpp/MatterCallbackHandler-JNI.h | 221 ++++- .../app/src/main/jni/cpp/TvCastingApp-JNI.cpp | 871 ++++++++++++++++++ .../app/src/main/jni/cpp/TvCastingApp-JNI.h | 59 ++ .../res/layout/fragment_media_playback.xml | 106 +++ .../res/layout/fragment_select_cluster.xml | 36 + .../App/app/src/main/res/values/strings.xml | 11 + examples/tv-casting-app/android/BUILD.gn | 7 + .../tv-casting-app/tv-casting-common/BUILD.gn | 1 + .../include/ApplicationBasic.h | 73 ++ .../tv-casting-common/include/CastingServer.h | 93 ++ .../include/ContentLauncher.h | 17 + .../tv-casting-common/src/CastingServer.cpp | 137 +++ 28 files changed, 2672 insertions(+), 72 deletions(-) create mode 100644 examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MediaPlaybackFragment.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/SelectClusterFragment.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/ContentLauncherTypes.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/FailureCallback.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MatterError.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MediaPlaybackTypes.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/SubscriptionEstablishedCallback.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/SuccessCallback.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TargetNavigatorTypes.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_media_playback.xml create mode 100644 examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_select_cluster.xml create mode 100644 examples/tv-casting-app/tv-casting-common/include/ApplicationBasic.h diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissioningFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissioningFragment.java index a46714224e8e2a..71b2d62b38b18d 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissioningFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissioningFragment.java @@ -9,6 +9,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.chip.casting.MatterCallbackHandler; +import com.chip.casting.MatterError; import com.chip.casting.TvCastingApp; import com.chip.casting.dnssd.DiscoveredNodeData; import com.chip.casting.util.GlobalCastingConstants; @@ -53,9 +54,9 @@ public View onCreateView( GlobalCastingConstants.CommissioningWindowDurationSecs, new MatterCallbackHandler() { @Override - public void handle(Status status) { - Log.d(TAG, "handle() called on CommissioningComplete event with " + status); - if (status.isSuccess()) { + public void handle(MatterError error) { + Log.d(TAG, "handle() called on CommissioningComplete event with " + error); + if (error.isNoError()) { callback.handleCommissioningComplete(); } } 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 0e1ff58fbdeb59..d939ad944265c6 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 @@ -10,6 +10,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.chip.casting.MatterCallbackHandler; +import com.chip.casting.MatterError; import com.chip.casting.TvCastingApp; /** A {@link Fragment} to send Content Launcher commands from the TV Casting App. */ @@ -55,10 +56,10 @@ public void onClick(View v) { contentDisplayString.getText().toString(), new MatterCallbackHandler() { @Override - public void handle(Status status) { - Log.d(TAG, "handle() called on LaunchURLResponse with success " + status); + public void handle(MatterError error) { + Log.d(TAG, "handle() called on LaunchURLResponse with " + error); TextView launchUrlStatus = getView().findViewById(R.id.launchUrlStatus); - launchUrlStatus.setText(status.isSuccess() ? "Success!" : "Failure!"); + launchUrlStatus.setText(error.isNoError() ? "Success!" : "Failure!"); } }); } 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 afd768a1a20679..c9d493d214b7cd 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 @@ -21,7 +21,9 @@ import com.chip.casting.util.GlobalCastingConstants; public class MainActivity extends AppCompatActivity - implements CommissionerDiscoveryFragment.Callback, CommissioningFragment.Callback { + implements CommissionerDiscoveryFragment.Callback, + CommissioningFragment.Callback, + SelectClusterFragment.Callback { private static final String TAG = MainActivity.class.getSimpleName(); @@ -49,9 +51,19 @@ public void handleCommissioningButtonClicked(DiscoveredNodeData commissioner) { @Override public void handleCommissioningComplete() { + showFragment(SelectClusterFragment.newInstance()); + } + + @Override + public void handleContentLauncherSelected() { showFragment(ContentLauncherFragment.newInstance(tvCastingApp)); } + @Override + public void handleMediaPlaybackSelected() { + showFragment(MediaPlaybackFragment.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 new file mode 100644 index 00000000000000..6745b94904e192 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MediaPlaybackFragment.java @@ -0,0 +1,133 @@ +package com.chip.casting.app; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import com.chip.casting.FailureCallback; +import com.chip.casting.MatterError; +import com.chip.casting.MediaPlaybackTypes; +import com.chip.casting.SubscriptionEstablishedCallback; +import com.chip.casting.SuccessCallback; +import com.chip.casting.TvCastingApp; + +/** A {@link Fragment} for the Media Playback cluster */ +public class MediaPlaybackFragment extends Fragment { + private static final String TAG = MediaPlaybackFragment.class.getSimpleName(); + + private final TvCastingApp tvCastingApp; + + private View.OnClickListener subscribeToCurrentStateButtonClickListener; + + public MediaPlaybackFragment(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 MediaPlaybackFragment. + */ + public static MediaPlaybackFragment newInstance(TvCastingApp tvCastingApp) { + return new MediaPlaybackFragment(tvCastingApp); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + this.subscribeToCurrentStateButtonClickListener = + new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(TAG, "SubscribeToCurrentStateButtonClickListener called"); + TextView minInterval = getView().findViewById(R.id.minIntervalEditText); + TextView maxInterval = getView().findViewById(R.id.maxIntervalEditText); + TextView subscriptionStatus = + getView().findViewById(R.id.currentStateSubscriptionEstablishedStatus); + TextView currentStateValue = getView().findViewById(R.id.currentStateValue); + + SuccessCallback successCallback = + playbackStateEnum -> { + Log.d( + TAG, + "handle() called on SuccessCallback with " + + playbackStateEnum); + getActivity() + .runOnUiThread( + new Runnable() { + @Override + public void run() { + if (playbackStateEnum != null) { + currentStateValue.setText(playbackStateEnum.toString()); + } + } + }); + }; + + FailureCallback failureCallback = + new FailureCallback() { + @Override + public void handle(MatterError matterError) { + Log.d(TAG, "handle() called on FailureCallback with " + matterError); + getActivity() + .runOnUiThread( + new Runnable() { + @Override + public void run() { + currentStateValue.setText("Error!"); + } + }); + } + }; + + SubscriptionEstablishedCallback subscriptionEstablishedCallback = + (SubscriptionEstablishedCallback) + () -> { + Log.d(TAG, "handle() called on SubscriptionEstablishedCallback"); + getActivity() + .runOnUiThread( + new Runnable() { + @Override + public void run() { + subscriptionStatus.setText("Subscription established!"); + } + }); + }; + + boolean retVal = + tvCastingApp.mediaPlayback_subscribeToCurrentState( + successCallback, + failureCallback, + Integer.parseInt(minInterval.getText().toString()), + Integer.parseInt(maxInterval.getText().toString()), + subscriptionEstablishedCallback); + Log.d(TAG, "tvCastingApp.mediaPlayback_subscribeToCurrentState returned " + retVal); + if (retVal == false) { + subscriptionStatus.setText("Subscribe call failed!"); + } + } + }; + + return inflater.inflate(R.layout.fragment_media_playback, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + Log.d(TAG, "MediaPlaybackFragment.onViewCreated called"); + getView() + .findViewById(R.id.subscribeToCurrentStateButton) + .setOnClickListener(subscribeToCurrentStateButtonClickListener); + } +} 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 new file mode 100644 index 00000000000000..67de30838b296d --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/SelectClusterFragment.java @@ -0,0 +1,78 @@ +package com.chip.casting.app; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +/** 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 View.OnClickListener selectContentLauncherButtonClickListener; + private View.OnClickListener selectMediaPlaybackButtonClickListener; + + /** + * Use this factory method to create a new instance of this fragment using the provided + * parameters. + * + * @return A new instance of fragment SelectActionFragment. + */ + public static SelectClusterFragment newInstance() { + return new SelectClusterFragment(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + SelectClusterFragment.Callback callback = (SelectClusterFragment.Callback) this.getActivity(); + this.selectContentLauncherButtonClickListener = + new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(TAG, "handle() called on selectContentLauncherButtonClickListener"); + callback.handleContentLauncherSelected(); + } + }; + + this.selectMediaPlaybackButtonClickListener = + new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(TAG, "handle() called on selectMediaPlaybackButtonClickListener"); + callback.handleMediaPlaybackSelected(); + } + }; + + return inflater.inflate(R.layout.fragment_select_cluster, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + Log.d(TAG, "SelectActionFragment.onViewCreated called"); + getView() + .findViewById(R.id.selectContentLauncherButton) + .setOnClickListener(selectContentLauncherButtonClickListener); + getView() + .findViewById(R.id.selectMediaPlaybackButton) + .setOnClickListener(selectMediaPlaybackButtonClickListener); + } + + /** Interface for notifying the host. */ + public interface Callback { + /** Notifies listener to trigger transition on selection of Content Launcher cluster */ + void handleContentLauncherSelected(); + + /** Notifies listener to trigger transition on selection of Media Playback cluster */ + void handleMediaPlaybackSelected(); + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/ContentLauncherTypes.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/ContentLauncherTypes.java new file mode 100644 index 00000000000000..bc4ee6a6a24bdf --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/ContentLauncherTypes.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2022 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. + * + */ +package com.chip.casting; + +import java.util.ArrayList; +import java.util.Optional; + +public class ContentLauncherTypes { + public static class AdditionalInfo { + public String name; + public String value; + + public AdditionalInfo(String name, String value) { + this.name = name; + this.value = value; + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("AdditionalInfo {\n"); + output.append("\tname: "); + output.append(name); + output.append("\n"); + output.append("\tvalue: "); + output.append(value); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } + } + + public static class Parameter { + public Integer type; + public String value; + public Optional> externalIDList; + + public Parameter( + Integer type, String value, Optional> externalIDList) { + this.type = type; + this.value = value; + this.externalIDList = externalIDList; + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("Parameter {\n"); + output.append("\ttype: "); + output.append(type); + output.append("\n"); + output.append("\tvalue: "); + output.append(value); + output.append("\n"); + output.append("\texternalIDList: "); + output.append(externalIDList); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } + } + + public static class ContentSearch { + public ArrayList parameterList; + + public ContentSearch(ArrayList parameterList) { + this.parameterList = parameterList; + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("ContentSearch {\n"); + output.append("\tparameterList: "); + output.append(parameterList); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/FailureCallback.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/FailureCallback.java new file mode 100644 index 00000000000000..1d6b4097e77cbc --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/FailureCallback.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 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. + * + */ +package com.chip.casting; + +public abstract class FailureCallback { + public abstract void handle(MatterError err); + + public final void handle(int errorCode, String errorMessage) { + handle(new MatterError(errorCode, errorMessage)); + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MatterCallbackHandler.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MatterCallbackHandler.java index 44eb3472d8f496..a06f12248883db 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MatterCallbackHandler.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MatterCallbackHandler.java @@ -17,58 +17,10 @@ */ package com.chip.casting; -import java.util.Objects; - public abstract class MatterCallbackHandler { - public abstract void handle(Status status); + public abstract void handle(MatterError err); public final void handle(int errorCode, String errorMessage) { - handle(new Status(errorCode, errorMessage)); - } - - public static class Status { - private int errorCode; - private String errorMessage; - - public static final Status SUCCESS = new Status(0, null); - - public Status(int errorCode, String errorMessage) { - this.errorCode = errorCode; - this.errorMessage = errorMessage; - } - - public boolean isSuccess() { - return this.equals(SUCCESS); - } - - public int getErrorCode() { - return errorCode; - } - - public String getErrorMessage() { - return errorMessage; - } - - @Override - public String toString() { - return "Status{" - + (isSuccess() - ? "Success" - : "errorCode=" + errorCode + ", errorMessage='" + errorMessage + '\'') - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Status status = (Status) o; - return errorCode == status.errorCode; - } - - @Override - public int hashCode() { - return Objects.hash(errorCode); - } + handle(new MatterError(errorCode, errorMessage)); } } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MatterError.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MatterError.java new file mode 100644 index 00000000000000..aaaf95911f18da --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MatterError.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 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. + * + */ +package com.chip.casting; + +import java.util.Objects; + +public class MatterError { + private int errorCode; + private String errorMessage; + + public static final MatterError NO_ERROR = new MatterError(0, null); + + public MatterError(int errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } + + public boolean isNoError() { + return this.equals(NO_ERROR); + } + + public int getErrorCode() { + return errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + @Override + public String toString() { + return "MatterError{" + + (isNoError() + ? "No error" + : "errorCode=" + errorCode + ", errorMessage='" + errorMessage + '\'') + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MatterError matterError = (MatterError) o; + return errorCode == matterError.errorCode; + } + + @Override + public int hashCode() { + return Objects.hash(errorCode); + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MediaPlaybackTypes.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MediaPlaybackTypes.java new file mode 100644 index 00000000000000..7bf37b5d1cd8e4 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/MediaPlaybackTypes.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022 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. + * + */ +package com.chip.casting; + +public class MediaPlaybackTypes { + public enum PlaybackStateEnum { + Playing, + Paused, + NotPlaying, + Buffering, + Unknown + } + + public static class PlaybackPosition { + public Long updatedAt; + public Long position; + + public PlaybackPosition(Long updatedAt) { + this.updatedAt = updatedAt; + } + + public PlaybackPosition(Long updatedAt, Long position) { + this.updatedAt = updatedAt; + this.position = position; + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("PlaybackPosition {\n"); + output.append("\tupdatedAt: "); + output.append(updatedAt); + output.append("\n"); + output.append("\tposition: "); + output.append(position); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/SubscriptionEstablishedCallback.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/SubscriptionEstablishedCallback.java new file mode 100644 index 00000000000000..e182c80e7ccdef --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/SubscriptionEstablishedCallback.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 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. + * + */ +package com.chip.casting; + +public interface SubscriptionEstablishedCallback { + void handle(); +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/SuccessCallback.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/SuccessCallback.java new file mode 100644 index 00000000000000..125ce4daabfc90 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/SuccessCallback.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 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. + * + */ +package com.chip.casting; + +public interface SuccessCallback { + void handle(R response); +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TargetNavigatorTypes.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TargetNavigatorTypes.java new file mode 100644 index 00000000000000..88f71bb796ceaf --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TargetNavigatorTypes.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 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. + * + */ +package com.chip.casting; + +public class TargetNavigatorTypes { + public static class TargetInfo { + public Integer identifier; + public String name; + + public TargetInfo(Integer identifier, String name) { + this.identifier = identifier; + this.name = name; + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("TargetInfo {\n"); + output.append("\tidentifier: "); + output.append(identifier); + output.append("\n"); + output.append("\tname: "); + output.append(name); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } + } +} 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 e8804387149b47..eb3a184b1ab3f8 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 @@ -33,10 +33,25 @@ public native boolean openBasicCommissioningWindow( /* * CONTENT LAUNCHER CLUSTER + * + * TODO: Add API to subscribe to AcceptHeader */ public native boolean contentLauncherLaunchURL( String contentUrl, String contentDisplayStr, Object launchURLHandler); + public native boolean contentLauncher_launchContent( + ContentLauncherTypes.ContentSearch search, + boolean autoPlay, + String data, + Object responseHandler); + + public native boolean contentLauncher_subscribeToSupportedStreamingProtocols( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + /* * LEVEL CONTROL CLUSTER */ @@ -55,6 +70,27 @@ public native boolean levelControl_moveToLevel( byte optionOverridem, Object responseHandler); + public native boolean levelControl_subscribeToCurrentLevel( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean levelControl_subscribeToMinLevel( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean levelControl_subscribeToMaxLevel( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + /* * MEDIA PLAYBACK CLUSTER */ @@ -74,6 +110,48 @@ public native boolean mediaPlayback_skipForward( public native boolean mediaPlayback_skipBackward( long deltaPositionMilliseconds, Object responseHandler); + public native boolean mediaPlayback_subscribeToCurrentState( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean mediaPlayback_subscribeToDuration( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean mediaPlayback_subscribeToSampledPosition( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean mediaPlayback_subscribeToPlaybackSpeed( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean mediaPlayback_subscribeToSeekRangeEnd( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean mediaPlayback_subscribeToSeekRangeStart( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + /* * APPLICATION LAUNCHER CLUSTER */ @@ -92,11 +170,65 @@ public native boolean applicationLauncher_hideApp( public native boolean targetNavigator_navigateTarget( byte target, String data, Object responseHandler); + public native boolean targetNavigator_subscribeToCurrentTarget( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean targetNavigator_subscribeToTargetList( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + /* * KEYPAD INPUT CLUSTER */ public native boolean keypadInput_sendKey(byte keyCode, Object responseHandler); + /** + * APPLICATION BASIC + * + *

TODO: Add APIs to subscribe to Application, Status and AllowedVendorList + */ + public native boolean applicationBasic_subscribeToVendorName( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean applicationBasic_subscribeToVendorID( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean applicationBasic_subscribeToApplicationName( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean applicationBasic_subscribeToProductID( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + + public native boolean applicationBasic_subscribeToApplicationVersion( + SuccessCallback readSuccessHandler, + FailureCallback readFailureHandler, + int minInterval, + int maxInterval, + SubscriptionEstablishedCallback subscriptionEstablishedHandler); + 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 ddf0ef028e9eb7..334e1180e13f72 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 @@ -38,3 +38,29 @@ enum MediaCommandName MEDIA_COMMAND_COUNT }; + +enum MediaAttributeName +{ + ContentLauncher_SupportedStreamingProtocols, + ContentLauncher_AcceptHeader, + LevelControl_CurrentLevel, + LevelControl_MinLevel, + LevelControl_MaxLevel, + MediaPlayback_CurrentState, + MediaPlayback_StartTime, + MediaPlayback_Duration, + MediaPlayback_SampledPosition, + MediaPlayback_PlaybackSpeed, + MediaPlayback_SeekRangeEnd, + MediaPlayback_SeekRangeStart, + ApplicationLauncher_CurrentApp, + TargetNavigator_TargetList, + TargetNavigator_CurrentTarget, + ApplicationBasic_VendorName, + ApplicationBasic_VendorID, + ApplicationBasic_ApplicationName, + ApplicationBasic_ProductID, + ApplicationBasic_ApplicationVersion, + + MEDIA_ATTRIBUTE_COUNT +}; 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 3f28b5ac5f84d7..ef682b67da3d78 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 @@ -18,14 +18,11 @@ #include "MatterCallbackHandler-JNI.h" -#include -#include - using namespace chip; -CHIP_ERROR MatterCallbackHandlerJNI::SetUp(JNIEnv * env, jobject inHandler) +CHIP_ERROR CallbackBaseJNI::SetUp(JNIEnv * env, jobject inHandler) { - ChipLogProgress(AppServer, "MatterCallbackHandlerJNI::SetUp called"); + ChipLogProgress(AppServer, "CallbackBaseJNI::SetUp called"); CHIP_ERROR err = CHIP_NO_ERROR; mObject = env->NewGlobalRef(inHandler); @@ -34,7 +31,7 @@ CHIP_ERROR MatterCallbackHandlerJNI::SetUp(JNIEnv * env, jobject inHandler) mClazz = env->GetObjectClass(mObject); VerifyOrExit(mClazz != nullptr, ChipLogError(AppServer, "Failed to get handler Java class")); - mMethod = env->GetMethodID(mClazz, "handle", "(ILjava/lang/String;)V"); + mMethod = env->GetMethodID(mClazz, "handle", mMethodSignature); if (mMethod == nullptr) { ChipLogError(AppServer, "Failed to access 'handle' method"); @@ -44,16 +41,16 @@ CHIP_ERROR MatterCallbackHandlerJNI::SetUp(JNIEnv * env, jobject inHandler) exit: if (err != CHIP_NO_ERROR) { - ChipLogError(AppServer, "MatterCallbackHandlerJNI::SetUp error: %s", err.AsString()); + ChipLogError(AppServer, "CallbackBaseJNI::SetUp error: %s", err.AsString()); return err; } return err; } -void MatterCallbackHandlerJNI::Handle(CHIP_ERROR callbackErr) +void FailureHandlerJNI::Handle(CHIP_ERROR callbackErr) { - ChipLogProgress(AppServer, "MatterCallbackHandlerJNI::Handle called"); + ChipLogProgress(AppServer, "FailureHandlerJNI::Handle called"); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); UtfString jniCallbackErrString(env, callbackErr.AsString()); @@ -65,6 +62,320 @@ void MatterCallbackHandlerJNI::Handle(CHIP_ERROR callbackErr) exit: if (err != CHIP_NO_ERROR) { - ChipLogError(AppServer, "MatterCallbackHandlerJNI::Handle status error: %s", err.AsString()); + ChipLogError(AppServer, "FailureHandlerJNI::Handle status error: %s", err.AsString()); + } +} + +void SubscriptionEstablishedHandlerJNI::Handle() +{ + ChipLogProgress(AppServer, "SubscriptionEstablishedHandlerJNI::Handle called"); + + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + CHIP_ERROR err = CHIP_NO_ERROR; + VerifyOrExit(mObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + env->CallVoidMethod(mObject, mMethod); +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "SubscriptionEstablishedHandlerJNI::Handle status error: %s", err.AsString()); + } +} + +jobject ConvertToLongJObject(uint64_t responseData) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass responseTypeClass = env->FindClass("java/lang/Long"); + if (responseTypeClass == nullptr) + { + ChipLogError(AppServer, "ConvertToJObject: Class for Response Type not found!"); + return nullptr; + } + + jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(J)V"); + return env->NewObject(responseTypeClass, constructor, responseData); +} + +jobject ConvertToFloatJObject(float responseData) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass responseTypeClass = env->FindClass("java/lang/Float"); + if (responseTypeClass == nullptr) + { + ChipLogError(AppServer, "ConvertToJObject: Class for Response Type not found!"); + return nullptr; + } + + jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(F)V"); + return env->NewObject(responseTypeClass, constructor, responseData); +} + +jobject ConvertToShortJObject(uint16_t responseData) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass responseTypeClass = env->FindClass("java/lang/Short"); + if (responseTypeClass == nullptr) + { + ChipLogError(AppServer, "ConvertToJObject: Class for Response Type not found!"); + return nullptr; + } + + jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(S)V"); + return env->NewObject(responseTypeClass, constructor, responseData); +} + +jobject ConvertToByteJObject(uint8_t responseData) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass responseTypeClass = env->FindClass("java/lang/Byte"); + if (responseTypeClass == nullptr) + { + ChipLogError(AppServer, "ConvertToJObject: Class for Response Type not found!"); + return nullptr; + } + + jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(B)V"); + return env->NewObject(responseTypeClass, constructor, responseData); +} + +jstring ConvertToJString(chip::CharSpan responseData) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + return env->NewStringUTF(std::string(responseData.data(), responseData.size()).c_str()); +} + +jobject ConvertToIntegerJObject(uint32_t responseData) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass responseTypeClass = env->FindClass("java/lang/Integer"); + if (responseTypeClass == nullptr) + { + ChipLogError(AppServer, "ConvertToJObject: Class for Response Type not found!"); + return nullptr; + } + + jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(I)V"); + return env->NewObject(responseTypeClass, constructor, responseData); +} + +// MEDIA PLAYBACK + +jobject CurrentStateSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "CurrentStateSuccessHandlerJNI::ConvertToJObject called"); + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass enumClass = nullptr; + CHIP_ERROR err = + JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/MediaPlaybackTypes$PlaybackStateEnum", enumClass); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "ConvertToJObject: Class for Response Type not found!"); + return nullptr; } + + jfieldID enumType = nullptr; + switch (responseData) + { + case chip::app::Clusters::MediaPlayback::PlaybackStateEnum::kPlaying: + enumType = env->GetStaticFieldID(enumClass, "Playing", "Lcom/chip/casting/MediaPlaybackTypes$PlaybackStateEnum;"); + break; + case chip::app::Clusters::MediaPlayback::PlaybackStateEnum::kPaused: + enumType = env->GetStaticFieldID(enumClass, "Paused", "Lcom/chip/casting/MediaPlaybackTypes$PlaybackStateEnum;"); + break; + case chip::app::Clusters::MediaPlayback::PlaybackStateEnum::kNotPlaying: + enumType = env->GetStaticFieldID(enumClass, "NotPlaying", "Lcom/chip/casting/MediaPlaybackTypes$PlaybackStateEnum;"); + break; + case chip::app::Clusters::MediaPlayback::PlaybackStateEnum::kBuffering: + enumType = env->GetStaticFieldID(enumClass, "Buffering", "Lcom/chip/casting/MediaPlaybackTypes$PlaybackStateEnum;"); + break; + default: + enumType = env->GetStaticFieldID(enumClass, "Unknown", "Lcom/chip/casting/MediaPlaybackTypes$PlaybackStateEnum;"); + break; + } + + if (enumType != nullptr) + { + return env->GetStaticObjectField(enumClass, enumType); + } + return nullptr; +} + +jobject DurationSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::MediaPlayback::Attributes::Duration::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "DurationSuccessHandlerJNI::ConvertToJObject called"); + return responseData.IsNull() ? nullptr : ConvertToLongJObject(responseData.Value()); +} + +jobject SampledPositionSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::MediaPlayback::Attributes::SampledPosition::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "SampledPositionSuccessHandlerJNI::ConvertToJObject called"); + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jobject jSampledPosition = nullptr; + if (!responseData.IsNull()) + { + const chip::app::Clusters::MediaPlayback::Structs::PlaybackPosition::DecodableType & playbackPosition = + responseData.Value(); + + jclass responseTypeClass = nullptr; + CHIP_ERROR err = JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/MediaPlaybackTypes$PlaybackPosition", + responseTypeClass); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "ConvertToJObject: Class for Response Type not found!"); + return nullptr; + } + + if (playbackPosition.position.IsNull()) + { + jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(Ljava/lang/Long;)V"); + jSampledPosition = env->NewObject(responseTypeClass, constructor, playbackPosition.updatedAt); + } + else + { + jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(Ljava/lang/Long;java/lang/Long;)V"); + jSampledPosition = + env->NewObject(responseTypeClass, constructor, playbackPosition.updatedAt, playbackPosition.position.Value()); + } + } + + return jSampledPosition; +} + +jobject PlaybackSpeedSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::MediaPlayback::Attributes::PlaybackSpeed::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "PlaybackSpeedSuccessHandlerJNI::ConvertToJObject called"); + return ConvertToFloatJObject(responseData); +} + +jobject SeekRangeEndSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::MediaPlayback::Attributes::SeekRangeEnd::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "SeekRangeEndSuccessHandlerJNI::ConvertToJObject called"); + return responseData.IsNull() ? nullptr : ConvertToLongJObject(responseData.Value()); +} + +jobject SeekRangeStartSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::MediaPlayback::Attributes::SeekRangeStart::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "SeekRangeStartSuccessHandlerJNI::ConvertToJObject called"); + return responseData.IsNull() ? nullptr : ConvertToLongJObject(responseData.Value()); +} + +// TARGET NAVIGATOR +jobject CurrentTargetSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::TargetNavigator::Attributes::CurrentTarget::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "CurrentTargetSuccessHandlerJNI::ConvertToJObject called"); + return ConvertToByteJObject(responseData); +} + +jobject TargetListSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::TargetNavigator::Attributes::TargetList::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "TargetListSuccessHandlerJNI::ConvertToJObject called"); + + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + jobject jArrayList; + chip::JniReferences::GetInstance().CreateArrayList(jArrayList); + auto iter = responseData.begin(); + while (iter.Next()) + { + const chip::app::Clusters::TargetNavigator::Structs::TargetInfo::DecodableType & targetInfo = iter.GetValue(); + + jclass responseTypeClass = nullptr; + CHIP_ERROR err = + JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/TargetNavigatorTypes$TargetInfo", responseTypeClass); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "ConvertToJObject: Class for Response Type not found!"); + return nullptr; + } + + jmethodID constructor = env->GetMethodID(responseTypeClass, "", "(Ljava/lang/Integer;java/lang/String;)V"); + jobject jTargetInfo = env->NewObject(responseTypeClass, constructor, targetInfo.identifier, targetInfo.name); + + chip::JniReferences::GetInstance().AddToList(jArrayList, jTargetInfo); + } + return jArrayList; +} + +// LEVEL CONTROL +jobject CurrentLevelSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::LevelControl::Attributes::CurrentLevel::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "CurrentLevelSuccessHandlerJNI::ConvertToJObject called"); + return responseData.IsNull() ? nullptr : ConvertToByteJObject(responseData.Value()); +} + +jobject MinLevelSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::LevelControl::Attributes::MinLevel::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "MinLevelSuccessHandlerJNI::ConvertToJObject called"); + return ConvertToByteJObject(responseData); +} + +jobject MaxLevelSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::LevelControl::Attributes::MaxLevel::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "MaxLevelSuccessHandlerJNI::ConvertToJObject called"); + return ConvertToByteJObject(responseData); +} + +// CONTENT LAUNCHER +jobject SupportedStreamingProtocolsSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "SupportedStreamingProtocolsSuccessHandlerJNI::ConvertToJObject called"); + return ConvertToIntegerJObject(responseData); +} + +// APPLICATION BASIC +jobject VendorNameSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "VendorNameSuccessHandlerJNI::ConvertToJObject called"); + return ConvertToJString(responseData); +} + +jobject VendorIDSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "VendorIDSuccessHandlerJNI::ConvertToJObject called"); + return ConvertToShortJObject(responseData); +} + +jobject ApplicationNameSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "ApplicationNameSuccessHandlerJNI::ConvertToJObject called"); + return ConvertToJString(responseData); +} + +jobject ProductIDSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "ProductIDSuccessHandlerJNI::ConvertToJObject called"); + return ConvertToShortJObject(responseData); +} + +jobject ApplicationVersionSuccessHandlerJNI::ConvertToJObject( + chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "ApplicationVersionSuccessHandlerJNI::ConvertToJObject called"); + return ConvertToJString(responseData); } diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.h index 51f1f0edf45593..91babd44a4fb7b 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.h +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.h @@ -18,18 +18,229 @@ #pragma once +#include #include #include +#include +#include -class MatterCallbackHandlerJNI +class CallbackBaseJNI { public: + CallbackBaseJNI(const char * methodSignature) { mMethodSignature = methodSignature; } CHIP_ERROR SetUp(JNIEnv * env, jobject inHandler); +protected: + jobject mObject = nullptr; + jclass mClazz = nullptr; + jmethodID mMethod = nullptr; + const char * mMethodSignature = nullptr; +}; + +class FailureHandlerJNI : public CallbackBaseJNI +{ +public: + FailureHandlerJNI() : CallbackBaseJNI("(ILjava/lang/String;)V") {} void Handle(CHIP_ERROR err); +}; + +class MatterCallbackHandlerJNI : public FailureHandlerJNI +{ +}; + +class SubscriptionEstablishedHandlerJNI : public CallbackBaseJNI +{ +public: + SubscriptionEstablishedHandlerJNI() : CallbackBaseJNI("()V") {} + void Handle(); +}; + +// helper functions for conversions +jobject ConvertToLongJObject(uint64_t responseData); +jobject ConvertToFloatJObject(float responseData); +jobject ConvertToShortJObject(uint8_t responseData); +jobject ConvertToByteJObject(uint8_t responseData); +jobject ConvertToIntegerJObject(uint32_t responseData); +jstring ConvertToJString(chip::CharSpan responseData); + +template +class SuccessHandlerJNI : public CallbackBaseJNI +{ +public: + SuccessHandlerJNI(const char * methodSignature) : CallbackBaseJNI(methodSignature) {} + + virtual ~SuccessHandlerJNI() = 0; + + virtual jobject ConvertToJObject(T responseData) = 0; + + void Handle(T responseData) + { + ChipLogProgress(AppServer, "SuccessHandlerJNI::Handle called"); + + JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); + jobject jResponseData = ConvertToJObject(responseData); + + CHIP_ERROR err = CHIP_NO_ERROR; + VerifyOrExit(mObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->CallVoidMethod(mObject, mMethod, jResponseData); + exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "SuccessHandlerJNI::Handle status error: %s", err.AsString()); + } + } +}; + +template +SuccessHandlerJNI::~SuccessHandlerJNI(){}; -private: - jobject mObject = nullptr; - jclass mClazz = nullptr; - jmethodID mMethod = nullptr; +// MEDIA PLAYBACK +class CurrentStateSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + CurrentStateSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Object;)V") {} + jobject ConvertToJObject(chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType responseData); +}; + +class DurationSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + DurationSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Long;)V") {} + jobject ConvertToJObject(chip::app::Clusters::MediaPlayback::Attributes::Duration::TypeInfo::DecodableArgType responseData); +}; + +class SampledPositionSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + SampledPositionSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Object;)V") {} + jobject + ConvertToJObject(chip::app::Clusters::MediaPlayback::Attributes::SampledPosition::TypeInfo::DecodableArgType responseData); +}; + +class PlaybackSpeedSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + PlaybackSpeedSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Float;)V") {} + jobject + ConvertToJObject(chip::app::Clusters::MediaPlayback::Attributes::PlaybackSpeed::TypeInfo::DecodableArgType responseData); +}; + +class SeekRangeEndSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + SeekRangeEndSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Long;)V") {} + jobject ConvertToJObject(chip::app::Clusters::MediaPlayback::Attributes::SeekRangeEnd::TypeInfo::DecodableArgType responseData); +}; + +class SeekRangeStartSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + SeekRangeStartSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Long;)V") {} + jobject + ConvertToJObject(chip::app::Clusters::MediaPlayback::Attributes::SeekRangeStart::TypeInfo::DecodableArgType responseData); +}; + +// TARGET NAVIGATOR +class CurrentTargetSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + CurrentTargetSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Byte;)V") {} + jobject + ConvertToJObject(chip::app::Clusters::TargetNavigator::Attributes::CurrentTarget::TypeInfo::DecodableArgType responseData); +}; + +class TargetListSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + TargetListSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/util/ArrayList;)V") {} + jobject ConvertToJObject(chip::app::Clusters::TargetNavigator::Attributes::TargetList::TypeInfo::DecodableArgType responseData); +}; + +// LEVEL CONTROL +class CurrentLevelSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + CurrentLevelSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Byte;)V") {} + jobject ConvertToJObject(chip::app::Clusters::LevelControl::Attributes::CurrentLevel::TypeInfo::DecodableArgType responseData); +}; + +class MinLevelSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + MinLevelSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Byte;)V") {} + jobject ConvertToJObject(chip::app::Clusters::LevelControl::Attributes::MinLevel::TypeInfo::DecodableArgType responseData); +}; + +class MaxLevelSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + MaxLevelSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Byte;)V") {} + jobject ConvertToJObject(chip::app::Clusters::LevelControl::Attributes::MaxLevel::TypeInfo::DecodableArgType responseData); +}; + +// CONTENT LAUNCHER +class SupportedStreamingProtocolsSuccessHandlerJNI + : public SuccessHandlerJNI< + chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::TypeInfo::DecodableArgType> +{ +public: + SupportedStreamingProtocolsSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Integer;)V") {} + jobject ConvertToJObject( + chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::TypeInfo::DecodableArgType responseData); +}; + +// APPLICATION BASIC +class VendorNameSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + VendorNameSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/String;)V") {} + jobject + ConvertToJObject(chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType responseData); +}; + +class VendorIDSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + VendorIDSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Short;)V") {} + jobject ConvertToJObject(chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType responseData); +}; + +class ApplicationNameSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + ApplicationNameSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/String;)V") {} + jobject + ConvertToJObject(chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType responseData); +}; + +class ProductIDSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + ProductIDSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Short;)V") {} + jobject ConvertToJObject(chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType responseData); +}; + +class ApplicationVersionSuccessHandlerJNI + : public SuccessHandlerJNI +{ +public: + ApplicationVersionSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/String;)V") {} + jobject ConvertToJObject( + chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType responseData); }; 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 ebc564bccff185..4edb41683f1962 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 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -153,6 +154,152 @@ JNI_METHOD(jboolean, contentLauncherLaunchURL) return true; } +CHIP_ERROR CreateParameter(JNIEnv * env, jobject jParameter, + chip::app::Clusters::ContentLauncher::Structs::Parameter::Type & parameter) +{ + jclass jParameterClass = env->GetObjectClass(jParameter); + + jfieldID jTypeField = env->GetFieldID(jParameterClass, "type", "Ljava/lang/Integer;"); + jobject jTypeObj = env->GetObjectField(jParameter, jTypeField); + jclass jIntegerClass = env->FindClass("java/lang/Integer"); + jmethodID jIntValueMid = env->GetMethodID(jIntegerClass, "intValue", "()I"); + parameter.type = static_cast(env->CallIntMethod(jTypeObj, jIntValueMid)); + + jfieldID jValueField = env->GetFieldID(jParameterClass, "value", "Ljava/lang/String;"); + jstring jValueObj = (jstring) env->GetObjectField(jParameter, jValueField); + const char * nativeValue = env->GetStringUTFChars(jValueObj, 0); + parameter.value = CharSpan::fromCharString(nativeValue); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CreateContentSearch(JNIEnv * env, jobject jSearch, + chip::app::Clusters::ContentLauncher::Structs::ContentSearch::Type & search) +{ + jclass jContentSearchClass; + ReturnErrorOnFailure( + JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/ContentLauncherTypes$ContentSearch", jContentSearchClass)); + + jfieldID jParameterListField = env->GetFieldID(jContentSearchClass, "parameterList", "Ljava/util/ArrayList;"); + jobject jParameterList = env->GetObjectField(jSearch, jParameterListField); + ReturnErrorOnFailure(jParameterList != nullptr ? CHIP_NO_ERROR : CHIP_ERROR_INVALID_ARGUMENT); + + jclass jArrayListClass = env->FindClass("java/util/ArrayList"); + jmethodID sizeMid = env->GetMethodID(jArrayListClass, "size", "()I"); + size_t parameterListSize = static_cast(env->CallIntMethod(jParameterList, sizeMid)); + + jobject jIterator = env->CallObjectMethod( + jParameterList, env->GetMethodID(env->GetObjectClass(jParameterList), "iterator", "()Ljava/util/Iterator;")); + jmethodID jNextMid = env->GetMethodID(env->GetObjectClass(jIterator), "next", "()Ljava/lang/Object;"); + jmethodID jHasNextMid = env->GetMethodID(env->GetObjectClass(jIterator), "hasNext", "()Z"); + + chip::app::Clusters::ContentLauncher::Structs::Parameter::Type * parameterList = + new chip::app::Clusters::ContentLauncher::Structs::Parameter::Type[parameterListSize]; + int parameterIndex = 0; + while (env->CallBooleanMethod(jIterator, jHasNextMid)) + { + jobject jParameter = env->CallObjectMethod(jIterator, jNextMid); + chip::app::Clusters::ContentLauncher::Structs::Parameter::Type parameter; + ReturnErrorOnFailure(CreateParameter(env, jParameter, parameter)); + parameterList[parameterIndex++] = parameter; + } + search.parameterList = chip::app::DataModel::List( + parameterList, parameterListSize); + + return CHIP_NO_ERROR; +} + +JNI_METHOD(jboolean, contentLauncher_1launchContent) +(JNIEnv * env, jobject, jobject jSearch, jboolean jAutoplay, jstring jData, jobject jResponseHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD contentLauncher_1launchContent called"); + + // prepare arguments + bool autoplay = static_cast(jAutoplay); + + const char * nativeData = env->GetStringUTFChars(jData, 0); + chip::Optional data = MakeOptional(CharSpan::fromCharString(nativeData)); + + chip::app::Clusters::ContentLauncher::Structs::ContentSearch::Type search; + CHIP_ERROR err = CreateContentSearch(env, jSearch, search); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, + "contentLauncher_1launchContent::Could not create ContentSearch object %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(ContentLauncher_LaunchContent).SetUp(env, jResponseHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "MatterCallbackHandlerJNI::SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->ContentLauncher_LaunchContent(search, autoplay, data, [](CHIP_ERROR err) { + TvCastingAppJNIMgr().getMediaCommandResponseHandler(ContentLauncher_LaunchContent).Handle(err); + }); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer::ContentLauncher_LaunchContent failed %" CHIP_ERROR_FORMAT, err.Format())); + + env->ReleaseStringUTFChars(jData, nativeData); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, contentLauncher_1subscribeToSupportedStreamingProtocols) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD ContentLauncher_subscribeToSupportedStreamingProtocols called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getSupportedStreamingProtocolsSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionReadFailureHandler(ContentLauncher_SupportedStreamingProtocols) + .SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(ContentLauncher_SupportedStreamingProtocols) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->ContentLauncher_SubscribeToSupportedStreamingProtocols( + nullptr, + [](void * context, + chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getSupportedStreamingProtocolsSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ContentLauncher_SupportedStreamingProtocols).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { + TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(ContentLauncher_SupportedStreamingProtocols).Handle(); + }); + + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, + "CastingServer.ContentLauncher_SubscribeToSupportedStreamingProtocols failed %" CHIP_ERROR_FORMAT, + err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + JNI_METHOD(jboolean, levelControl_1step) (JNIEnv * env, jobject, jbyte stepMode, jbyte stepSize, jshort transitionTime, jbyte optionMask, jbyte optionOverride, jobject jResponseHandler) @@ -208,6 +355,137 @@ JNI_METHOD(jboolean, levelControl_1moveToLevel) return true; } +JNI_METHOD(jboolean, levelControl_1subscribeToCurrentLevel) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD levelControl_subscribeToCurrentLevel called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getCurrentLevelSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(LevelControl_CurrentLevel).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(LevelControl_CurrentLevel) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->LevelControl_SubscribeToCurrentLevel( + nullptr, + [](void * context, chip::app::Clusters::LevelControl::Attributes::CurrentLevel::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getCurrentLevelSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(LevelControl_CurrentLevel).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(LevelControl_CurrentLevel).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.LevelControl_SubscribeToCurrentLevel failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, levelControl_1subscribeToMinLevel) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD levelControl_subscribeToMinLevel called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getMinLevelSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(LevelControl_MinLevel).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(LevelControl_MinLevel).SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->LevelControl_SubscribeToMinLevel( + nullptr, + [](void * context, chip::app::Clusters::LevelControl::Attributes::MinLevel::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getMinLevelSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(LevelControl_MinLevel).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(LevelControl_MinLevel).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.LevelControl_SubscribeToMinLevel failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, levelControl_1subscribeToMaxLevel) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD levelControl_subscribeToMaxLevel called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getMaxLevelSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(LevelControl_MaxLevel).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(LevelControl_MaxLevel).SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->LevelControl_SubscribeToMaxLevel( + nullptr, + [](void * context, chip::app::Clusters::LevelControl::Attributes::MaxLevel::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getMaxLevelSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(LevelControl_MaxLevel).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(LevelControl_MaxLevel).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.LevelControl_SubscribeToMaxLevel 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 jResponseHandler) { @@ -386,6 +664,277 @@ JNI_METHOD(jboolean, mediaPlayback_1skipBackward) return true; } +JNI_METHOD(jboolean, mediaPlayback_1subscribeToCurrentState) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_subscribeToCurrentState called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getCurrentStateSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_CurrentState).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(MediaPlayback_CurrentState) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->MediaPlayback_SubscribeToCurrentState( + nullptr, + [](void * context, chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getCurrentStateSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_CurrentState).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(MediaPlayback_CurrentState).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.MediaPlayback_SubscribeToCurrentState failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, mediaPlayback_1subscribeToDuration) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_1subscribeToDuration called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getDurationSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_Duration).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = + TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(MediaPlayback_Duration).SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->MediaPlayback_SubscribeToDuration( + nullptr, + [](void * context, chip::app::Clusters::MediaPlayback::Attributes::Duration::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getDurationSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_Duration).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(MediaPlayback_Duration).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.mediaPlayback_subscribeToDuration failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, mediaPlayback_1subscribeToSampledPosition) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_1subscribeToSampledPosition called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getSampledPositionSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_SampledPosition).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(MediaPlayback_SampledPosition) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->MediaPlayback_SubscribeToSampledPosition( + nullptr, + [](void * context, + chip::app::Clusters::MediaPlayback::Attributes::SampledPosition::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getSampledPositionSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_SampledPosition).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(MediaPlayback_SampledPosition).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.mediaPlayback_subscribeToSampledPosition failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, mediaPlayback_1subscribeToPlaybackSpeed) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_1subscribeToPlaybackSpeed called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getPlaybackSpeedSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_PlaybackSpeed).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(MediaPlayback_PlaybackSpeed) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->MediaPlayback_SubscribeToPlaybackSpeed( + nullptr, + [](void * context, chip::app::Clusters::MediaPlayback::Attributes::PlaybackSpeed::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getPlaybackSpeedSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_PlaybackSpeed).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(MediaPlayback_PlaybackSpeed).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.mediaPlayback_subscribeToPlaybackSpeed failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, mediaPlayback_1subscribeToSeekRangeEnd) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_1subscribeToSeekRangeEnd called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getSeekRangeEndSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_SeekRangeEnd).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(MediaPlayback_SeekRangeEnd) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->MediaPlayback_SubscribeToSeekRangeEnd( + nullptr, + [](void * context, chip::app::Clusters::MediaPlayback::Attributes::SeekRangeEnd::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getSeekRangeEndSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_SeekRangeEnd).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(MediaPlayback_SeekRangeEnd).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.mediaPlayback_subscribeToSeekRangeEnd failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, mediaPlayback_1subscribeToSeekRangeStart) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_1subscribeToSeekRangeStart called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getSeekRangeStartSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_SeekRangeStart).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(MediaPlayback_SeekRangeStart) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->MediaPlayback_SubscribeToSeekRangeStart( + nullptr, + [](void * context, + chip::app::Clusters::MediaPlayback::Attributes::SeekRangeStart::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getSeekRangeStartSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_SeekRangeStart).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(MediaPlayback_SeekRangeStart).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.mediaPlayback_subscribeToSeekRangeStart failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + JNI_METHOD(jboolean, applicationLauncher_1launchApp) (JNIEnv * env, jobject, jshort catalogVendorId, jstring applicationId, jbyteArray data, jobject jResponseHandler) { @@ -514,6 +1063,97 @@ JNI_METHOD(jboolean, targetNavigator_1navigateTarget) return true; } +JNI_METHOD(jboolean, targetNavigator_1subscribeToCurrentTarget) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD targetNavigator_1subscribeToCurrentTarget called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getCurrentTargetSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(TargetNavigator_CurrentTarget).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(TargetNavigator_CurrentTarget) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->TargetNavigator_SubscribeToCurrentTarget( + nullptr, + [](void * context, + chip::app::Clusters::TargetNavigator::Attributes::CurrentTarget::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getCurrentTargetSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(TargetNavigator_CurrentTarget).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(TargetNavigator_CurrentTarget).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.targetNavigator_subscribeToCurrentTarget failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, targetNavigator_1subscribeToTargetList) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD targetNavigator_1subscribeToTargetList called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getTargetListSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(TargetNavigator_TargetList).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(TargetNavigator_TargetList) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->TargetNavigator_SubscribeToTargetList( + nullptr, + [](void * context, chip::app::Clusters::TargetNavigator::Attributes::TargetList::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getTargetListSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(TargetNavigator_TargetList).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(TargetNavigator_TargetList).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.targetNavigator_subscribeToTargetList failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + JNI_METHOD(jboolean, keypadInput_1sendKey) (JNIEnv * env, jobject, jbyte keyCode, jobject jResponseHandler) { @@ -539,3 +1179,234 @@ JNI_METHOD(jboolean, keypadInput_1sendKey) return true; } + +// APPLICATION BASIC +JNI_METHOD(jboolean, applicationBasic_1subscribeToVendorName) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD applicationBasic_1subscribeToVendorName called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getVendorNameSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_VendorName).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(ApplicationBasic_VendorName) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToVendorName( + nullptr, + [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getVendorNameSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_VendorName).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(ApplicationBasic_VendorName).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.applicationBasic_subscribeToVendorName failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, applicationBasic_1subscribeToVendorID) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD applicationBasic_1subscribeToVendorID called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getVendorIDSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_VendorID).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(ApplicationBasic_VendorID) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToVendorID( + nullptr, + [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getVendorIDSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_VendorID).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(ApplicationBasic_VendorID).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.applicationBasic_subscribeToVendorID failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, applicationBasic_1subscribeToApplicationName) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD applicationBasic_1subscribeToApplicationName called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getApplicationNameSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_ApplicationName).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(ApplicationBasic_ApplicationName) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToApplicationName( + nullptr, + [](void * context, + chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getApplicationNameSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_ApplicationName).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(ApplicationBasic_ApplicationName).Handle(); }); + + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.applicationBasic_subscribeToApplicationName failed %" CHIP_ERROR_FORMAT, + err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, applicationBasic_1subscribeToProductID) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD applicationBasic_1subscribeToProductID called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getProductIDSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_ProductID).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(ApplicationBasic_ProductID) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToProductID( + nullptr, + [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getProductIDSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_ProductID).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(ApplicationBasic_ProductID).Handle(); }); + + VerifyOrExit( + CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.applicationBasic_subscribeToProductID failed %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jboolean, applicationBasic_1subscribeToApplicationVersion) +(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, + jobject jSubscriptionEstablishedHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD applicationBasic_1subscribeToApplicationVersion called"); + + CHIP_ERROR err = TvCastingAppJNIMgr().getApplicationVersionSuccessHandler().SetUp(env, jReadSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_ApplicationVersion).SetUp(env, jReadFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionReadFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr() + .getSubscriptionEstablishedHandler(ApplicationBasic_ApplicationVersion) + .SetUp(env, jSubscriptionEstablishedHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToApplicationVersion( + nullptr, + [](void * context, + chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType responseData) { + TvCastingAppJNIMgr().getApplicationVersionSuccessHandler().Handle(responseData); + }, + [](void * context, CHIP_ERROR err) { + TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_ApplicationVersion).Handle(err); + }, + static_cast(minInterval), static_cast(maxInterval), + [](void * context) { + TvCastingAppJNIMgr().getSubscriptionEstablishedHandler(ApplicationBasic_ApplicationVersion).Handle(); + }); + + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer.applicationBasic_subscribeToApplicationVersion failed %" CHIP_ERROR_FORMAT, + err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.h index fdab6936710069..1336eb076d8ecd 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.h +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.h @@ -32,6 +32,41 @@ class TvCastingAppJNI return mMediaCommandResponseHandler[name]; } + FailureHandlerJNI & getSubscriptionReadFailureHandler(enum MediaAttributeName name) + { + return mSubscriptionReadFailureHandler[name]; + } + + SubscriptionEstablishedHandlerJNI & getSubscriptionEstablishedHandler(enum MediaAttributeName name) + { + return mSubscriptionEstablishedHandler[name]; + } + + CurrentStateSuccessHandlerJNI & getCurrentStateSuccessHandler() { return mCurrentStateSuccessHandlerJNI; } + DurationSuccessHandlerJNI & getDurationSuccessHandler() { return mDurationSuccessHandlerJNI; } + SampledPositionSuccessHandlerJNI & getSampledPositionSuccessHandler() { return mSampledPositionSuccessHandlerJNI; } + PlaybackSpeedSuccessHandlerJNI & getPlaybackSpeedSuccessHandler() { return mPlaybackSpeedSuccessHandlerJNI; } + SeekRangeEndSuccessHandlerJNI & getSeekRangeEndSuccessHandler() { return mSeekRangeEndSuccessHandlerJNI; } + SeekRangeStartSuccessHandlerJNI & getSeekRangeStartSuccessHandler() { return mSeekRangeStartSuccessHandlerJNI; } + + CurrentTargetSuccessHandlerJNI & getCurrentTargetSuccessHandler() { return mCurrentTargetSuccessHandlerJNI; } + TargetListSuccessHandlerJNI & getTargetListSuccessHandler() { return mTargetListSuccessHandlerJNI; } + + CurrentLevelSuccessHandlerJNI & getCurrentLevelSuccessHandler() { return mCurrentLevelSuccessHandlerJNI; } + MinLevelSuccessHandlerJNI & getMinLevelSuccessHandler() { return mMinLevelSuccessHandlerJNI; } + MaxLevelSuccessHandlerJNI & getMaxLevelSuccessHandler() { return mMaxLevelSuccessHandlerJNI; } + + SupportedStreamingProtocolsSuccessHandlerJNI & getSupportedStreamingProtocolsSuccessHandler() + { + return mSupportedStreamingProtocolsSuccessHandlerJNI; + } + + VendorNameSuccessHandlerJNI & getVendorNameSuccessHandler() { return mVendorNameSuccessHandlerJNI; } + VendorIDSuccessHandlerJNI & getVendorIDSuccessHandler() { return mVendorIDSuccessHandlerJNI; } + ApplicationNameSuccessHandlerJNI & getApplicationNameSuccessHandler() { return mApplicationNameSuccessHandlerJNI; } + ProductIDSuccessHandlerJNI & getProductIDSuccessHandler() { return mProductIDSuccessHandlerJNI; } + ApplicationVersionSuccessHandlerJNI & getApplicationVersionSuccessHandler() { return mApplicationVersionSuccessHandlerJNI; } + private: friend TvCastingAppJNI & TvCastingAppJNIMgr(); @@ -39,6 +74,30 @@ class TvCastingAppJNI MatterCallbackHandlerJNI mCommissioningCompleteHandler; MatterCallbackHandlerJNI mMediaCommandResponseHandler[MEDIA_COMMAND_COUNT]; + FailureHandlerJNI mSubscriptionReadFailureHandler[MEDIA_ATTRIBUTE_COUNT]; + SubscriptionEstablishedHandlerJNI mSubscriptionEstablishedHandler[MEDIA_ATTRIBUTE_COUNT]; + + CurrentStateSuccessHandlerJNI mCurrentStateSuccessHandlerJNI; + DurationSuccessHandlerJNI mDurationSuccessHandlerJNI; + SampledPositionSuccessHandlerJNI mSampledPositionSuccessHandlerJNI; + PlaybackSpeedSuccessHandlerJNI mPlaybackSpeedSuccessHandlerJNI; + SeekRangeEndSuccessHandlerJNI mSeekRangeEndSuccessHandlerJNI; + SeekRangeStartSuccessHandlerJNI mSeekRangeStartSuccessHandlerJNI; + + CurrentTargetSuccessHandlerJNI mCurrentTargetSuccessHandlerJNI; + TargetListSuccessHandlerJNI mTargetListSuccessHandlerJNI; + + CurrentLevelSuccessHandlerJNI mCurrentLevelSuccessHandlerJNI; + MinLevelSuccessHandlerJNI mMinLevelSuccessHandlerJNI; + MaxLevelSuccessHandlerJNI mMaxLevelSuccessHandlerJNI; + + SupportedStreamingProtocolsSuccessHandlerJNI mSupportedStreamingProtocolsSuccessHandlerJNI; + + VendorNameSuccessHandlerJNI mVendorNameSuccessHandlerJNI; + VendorIDSuccessHandlerJNI mVendorIDSuccessHandlerJNI; + ApplicationNameSuccessHandlerJNI mApplicationNameSuccessHandlerJNI; + ProductIDSuccessHandlerJNI mProductIDSuccessHandlerJNI; + ApplicationVersionSuccessHandlerJNI mApplicationVersionSuccessHandlerJNI; }; inline class TvCastingAppJNI & TvCastingAppJNIMgr() 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 new file mode 100644 index 00000000000000..fac656c8c447a5 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_media_playback.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +