Skip to content

Commit 1484668

Browse files
sharadb-amazonpull[bot]
authored andcommitted
Added Content Launcher to android tv-casting-app (#18356)
1 parent cd440e5 commit 1484668

18 files changed

+395
-42
lines changed

examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissionerDiscoveryFragment.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public void run() {
9494

9595
/** Interface for notifying the host. */
9696
public interface Callback {
97-
/** Notifies listener of Skip to manual Commissioning Button click. */
97+
/** Notifies listener of Commissioning Button click. */
9898
void handleCommissioningButtonClicked(DiscoveredNodeData selectedCommissioner);
9999
}
100100
}

examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissioningFragment.java

+53-20
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import androidx.fragment.app.Fragment;
1111
import com.chip.casting.TvCastingApp;
1212
import com.chip.casting.dnssd.DiscoveredNodeData;
13+
import com.chip.casting.platform.MatterCallbackHandler;
1314
import com.chip.casting.util.GlobalCastingConstants;
1415

1516
/** A {@link Fragment} to get the TV Casting App commissioned. */
@@ -19,6 +20,10 @@ public class CommissioningFragment extends Fragment {
1920
private final TvCastingApp tvCastingApp;
2021
private final DiscoveredNodeData selectedCommissioner;
2122

23+
private boolean initServerSuccess;
24+
private boolean openCommissioningWindowSuccess;
25+
private boolean sendUdcSuccess;
26+
2227
public CommissioningFragment(TvCastingApp tvCastingApp, DiscoveredNodeData selectedCommissioner) {
2328
this.tvCastingApp = tvCastingApp;
2429
this.selectedCommissioner = selectedCommissioner;
@@ -43,40 +48,68 @@ public void onCreate(Bundle savedInstanceState) {
4348
@Override
4449
public View onCreateView(
4550
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
46-
// Inflate the layout for this fragment
51+
Callback callback = (CommissioningFragment.Callback) this.getActivity();
52+
this.initServerSuccess =
53+
tvCastingApp.initServer(
54+
new MatterCallbackHandler() {
55+
@Override
56+
public boolean handle(boolean success) {
57+
Log.d(
58+
TAG, "handle() called on CommissioningComplete event with success " + success);
59+
if (success) {
60+
callback.handleCommissioningComplete();
61+
}
62+
return true;
63+
}
64+
});
65+
66+
if (this.initServerSuccess) {
67+
this.openCommissioningWindowSuccess =
68+
tvCastingApp.openBasicCommissioningWindow(
69+
GlobalCastingConstants.CommissioningWindowDurationSecs);
70+
if (this.openCommissioningWindowSuccess) {
71+
if (selectedCommissioner != null && selectedCommissioner.getNumIPs() > 0) {
72+
String ipAddress = selectedCommissioner.getIpAddresses().get(0).getHostAddress();
73+
Log.d(
74+
TAG,
75+
"CommissioningFragment calling tvCastingApp.sendUserDirectedCommissioningRequest with IP: "
76+
+ ipAddress
77+
+ " port: "
78+
+ selectedCommissioner.getPort());
79+
80+
this.sendUdcSuccess =
81+
tvCastingApp.sendUserDirectedCommissioningRequest(
82+
ipAddress, selectedCommissioner.getPort());
83+
}
84+
}
85+
}
4786
return inflater.inflate(R.layout.fragment_commissioning, container, false);
4887
}
4988

5089
@Override
5190
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
5291
super.onViewCreated(view, savedInstanceState);
53-
54-
tvCastingApp.initServer();
55-
5692
String commissioningWindowStatus = "Failed to open commissioning window";
57-
if (tvCastingApp.openBasicCommissioningWindow(
58-
GlobalCastingConstants.CommissioningWindowDurationSecs)) {
59-
commissioningWindowStatus = "Commissioning window has been opened. Commission manually.";
60-
if (selectedCommissioner != null && selectedCommissioner.getNumIPs() > 0) {
61-
String ipAddress = selectedCommissioner.getIpAddresses().get(0).getHostAddress();
62-
Log.d(
63-
TAG,
64-
"CommissioningFragment calling tvCastingApp.sendUserDirectedCommissioningRequest with IP: "
65-
+ ipAddress
66-
+ " port: "
67-
+ selectedCommissioner.getPort());
68-
69-
if (tvCastingApp.sendUserDirectedCommissioningRequest(
70-
ipAddress, selectedCommissioner.getPort())) {
93+
if (this.initServerSuccess) {
94+
if (this.openCommissioningWindowSuccess) {
95+
commissioningWindowStatus = "Commissioning window has been opened. Commission manually.";
96+
if (this.sendUdcSuccess) {
7197
commissioningWindowStatus =
7298
"Commissioning window has been opened. Commissioning requested from "
7399
+ selectedCommissioner.getDeviceName();
74100
}
101+
TextView onboardingPayloadView = getView().findViewById(R.id.onboardingPayload);
102+
onboardingPayloadView.setText("Onboarding PIN: " + GlobalCastingConstants.SetupPasscode);
75103
}
76-
TextView onboardingPayloadView = getView().findViewById(R.id.onboardingPayload);
77-
onboardingPayloadView.setText("Onboarding PIN: " + GlobalCastingConstants.SetupPasscode);
78104
}
105+
79106
TextView commissioningWindowStatusView = getView().findViewById(R.id.commissioningWindowStatus);
80107
commissioningWindowStatusView.setText(commissioningWindowStatus);
81108
}
109+
110+
/** Interface for notifying the host. */
111+
public interface Callback {
112+
/** Notifies listener to trigger transition on completion of commissioning */
113+
void handleCommissioningComplete();
114+
}
82115
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.chip.casting.app;
2+
3+
import android.os.Bundle;
4+
import android.util.Log;
5+
import android.view.LayoutInflater;
6+
import android.view.View;
7+
import android.view.ViewGroup;
8+
import android.widget.EditText;
9+
import androidx.annotation.Nullable;
10+
import androidx.fragment.app.Fragment;
11+
import com.chip.casting.TvCastingApp;
12+
13+
/** A {@link Fragment} to send Content Launcher commands from the TV Casting App. */
14+
public class ContentLauncherFragment extends Fragment {
15+
private static final String TAG = ContentLauncherFragment.class.getSimpleName();
16+
17+
private final TvCastingApp tvCastingApp;
18+
19+
private View.OnClickListener launchUrlButtonClickListener;
20+
21+
public ContentLauncherFragment(TvCastingApp tvCastingApp) {
22+
this.tvCastingApp = tvCastingApp;
23+
}
24+
25+
/**
26+
* Use this factory method to create a new instance of this fragment using the provided
27+
* parameters.
28+
*
29+
* @param tvCastingApp TV Casting App (JNI)
30+
* @return A new instance of fragment ContentLauncherFragment.
31+
*/
32+
public static ContentLauncherFragment newInstance(TvCastingApp tvCastingApp) {
33+
return new ContentLauncherFragment(tvCastingApp);
34+
}
35+
36+
@Override
37+
public void onCreate(Bundle savedInstanceState) {
38+
super.onCreate(savedInstanceState);
39+
}
40+
41+
@Override
42+
public View onCreateView(
43+
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
44+
this.launchUrlButtonClickListener =
45+
new View.OnClickListener() {
46+
@Override
47+
public void onClick(View v) {
48+
EditText contentUrl = getView().findViewById(R.id.contentUrlEditText);
49+
EditText contentDisplayString =
50+
getView().findViewById(R.id.contentDisplayStringEditText);
51+
tvCastingApp.contentLauncherLaunchURL(
52+
contentUrl.getText().toString(), contentDisplayString.getText().toString());
53+
}
54+
};
55+
56+
return inflater.inflate(R.layout.fragment_content_launcher, container, false);
57+
}
58+
59+
@Override
60+
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
61+
super.onViewCreated(view, savedInstanceState);
62+
Log.d(TAG, "ContentLauncherFragment.onViewCreated called");
63+
getView().findViewById(R.id.launchUrlButton).setOnClickListener(launchUrlButtonClickListener);
64+
}
65+
}

examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import com.chip.casting.util.GlobalCastingConstants;
2020

2121
public class MainActivity extends AppCompatActivity
22-
implements CommissionerDiscoveryFragment.Callback {
22+
implements CommissionerDiscoveryFragment.Callback, CommissioningFragment.Callback {
2323

2424
private ChipAppServer chipAppServer;
2525
private TvCastingApp tvCastingApp;
@@ -43,6 +43,11 @@ public void handleCommissioningButtonClicked(DiscoveredNodeData commissioner) {
4343
showFragment(CommissioningFragment.newInstance(tvCastingApp, commissioner));
4444
}
4545

46+
@Override
47+
public void handleCommissioningComplete() {
48+
showFragment(ContentLauncherFragment.newInstance(tvCastingApp));
49+
}
50+
4651
private void initJni() {
4752
tvCastingApp =
4853
new TvCastingApp((app, clusterId, duration) -> app.openBasicCommissioningWindow(duration));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.chip.casting.platform;
2+
3+
public interface MatterCallbackHandler {
4+
boolean handle(boolean success);
5+
}

examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TvCastingApp.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ private void postClusterInit(int clusterId, int endpoint) {
4545

4646
public native boolean discoverCommissioners();
4747

48-
public native void initServer();
48+
public native boolean initServer(Object commissioningCompleteHandler);
49+
50+
public native void contentLauncherLaunchURL(String contentUrl, String contentDisplayStr);
4951

5052
static {
5153
System.loadLibrary("TvCastingApp");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
*
3+
* Copyright (c) 2022 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#include "CallbackHelper.h"
20+
21+
#include <lib/support/JniReferences.h>
22+
23+
using namespace chip;
24+
25+
struct MatterCallbackHandler gCommissioningCompleteHandler;
26+
27+
CHIP_ERROR SetUpMatterCallbackHandler(JNIEnv * env, jobject inHandler, MatterCallbackHandler & callback)
28+
{
29+
ChipLogProgress(AppServer, "SetUpMatterCallbackHandler called");
30+
CHIP_ERROR err = CHIP_NO_ERROR;
31+
32+
callback.object = env->NewGlobalRef(inHandler);
33+
VerifyOrExit(callback.object != nullptr, ChipLogError(AppServer, "Failed to NewGlobalRef for handler object"));
34+
35+
callback.clazz = env->GetObjectClass(callback.object);
36+
VerifyOrExit(callback.clazz != nullptr, ChipLogError(AppServer, "Failed to get handler Java class"));
37+
38+
callback.method = env->GetMethodID(callback.clazz, "handle", "(Z)Z");
39+
if (callback.method == nullptr)
40+
{
41+
ChipLogError(AppServer, "Failed to access 'handle' method");
42+
env->ExceptionClear();
43+
}
44+
45+
exit:
46+
if (err != CHIP_NO_ERROR)
47+
{
48+
ChipLogError(AppServer, "SetUpMatterCallbackHandler error: %s", err.AsString());
49+
return err;
50+
}
51+
52+
return err;
53+
}
54+
55+
CHIP_ERROR CommissioningCompleteHandler()
56+
{
57+
ChipLogProgress(AppServer, "CommissioningCompleteHandler called");
58+
59+
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
60+
CHIP_ERROR err = CHIP_NO_ERROR;
61+
VerifyOrExit(gCommissioningCompleteHandler.object != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
62+
VerifyOrExit(gCommissioningCompleteHandler.method != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
63+
VerifyOrExit(env->CallBooleanMethod(gCommissioningCompleteHandler.object, gCommissioningCompleteHandler.method,
64+
static_cast<jboolean>(true)) != JNI_FALSE,
65+
err = CHIP_ERROR_INCORRECT_STATE);
66+
exit:
67+
if (err != CHIP_NO_ERROR)
68+
{
69+
ChipLogError(AppServer, "CommissioningCompleteHandler status error: %s", err.AsString());
70+
}
71+
72+
return err;
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
*
3+
* Copyright (c) 2022 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <jni.h>
22+
#include <lib/core/CHIPError.h>
23+
24+
struct MatterCallbackHandler
25+
{
26+
jobject object = nullptr;
27+
jclass clazz = nullptr;
28+
jmethodID method = nullptr;
29+
};
30+
31+
extern struct MatterCallbackHandler gCommissioningCompleteHandler;
32+
33+
CHIP_ERROR SetUpMatterCallbackHandler(JNIEnv * env, jobject inHandler, MatterCallbackHandler & callback);
34+
35+
CHIP_ERROR CommissioningCompleteHandler();

examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp

+25-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
#include "TvCastingApp-JNI.h"
20+
#include "CallbackHelper.h"
2021
#include "CastingServer.h"
2122
#include "JNIDACProvider.h"
2223

@@ -146,8 +147,30 @@ JNI_METHOD(jboolean, discoverCommissioners)(JNIEnv *, jobject)
146147
return true;
147148
}
148149

149-
JNI_METHOD(void, initServer)(JNIEnv *, jobject)
150+
JNI_METHOD(jboolean, initServer)(JNIEnv * env, jobject, jobject jCommissioningCompleteHandler)
150151
{
151152
ChipLogProgress(AppServer, "JNI_METHOD initServer called");
152-
CastingServer::GetInstance()->InitServer();
153+
CHIP_ERROR err = SetUpMatterCallbackHandler(env, jCommissioningCompleteHandler, gCommissioningCompleteHandler);
154+
if (err == CHIP_NO_ERROR)
155+
{
156+
CastingServer::GetInstance()->InitServer(CommissioningCompleteHandler);
157+
return true;
158+
}
159+
else
160+
{
161+
ChipLogError(AppServer, "initServer error: %s", err.AsString());
162+
return false;
163+
}
164+
}
165+
166+
JNI_METHOD(void, contentLauncherLaunchURL)(JNIEnv * env, jobject, jstring contentUrl, jstring contentDisplayStr)
167+
{
168+
ChipLogProgress(AppServer, "JNI_METHOD contentLauncherLaunchURL called");
169+
const char * nativeContentUrl = env->GetStringUTFChars(contentUrl, 0);
170+
const char * nativeContentDisplayStr = env->GetStringUTFChars(contentDisplayStr, 0);
171+
172+
CastingServer::GetInstance()->ContentLauncherLaunchURL(nativeContentUrl, nativeContentDisplayStr);
173+
174+
env->ReleaseStringUTFChars(contentUrl, nativeContentUrl);
175+
env->ReleaseStringUTFChars(contentDisplayStr, nativeContentDisplayStr);
153176
}

0 commit comments

Comments
 (0)