Skip to content

Commit

Permalink
Adding the JNI layer for Android tv-casting-app (#15001)
Browse files Browse the repository at this point in the history
  • Loading branch information
sharadb-amazon authored Feb 11, 2022
1 parent 91ea3d5 commit 787d670
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.net.wifi.WifiManager;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.chip.casting.TvCastingApp;
import com.chip.casting.dnssd.CommissionerDiscoveryListener;
import com.chip.casting.util.GlobalCastingConstants;
import java.util.concurrent.Executors;
Expand All @@ -17,6 +18,8 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startCommissionerDiscovery();

testJni();
}

private void startCommissionerDiscovery() {
Expand Down Expand Up @@ -48,4 +51,11 @@ public void run() {
10,
TimeUnit.SECONDS);
}

/** TBD: Temp dummy function for testing */
private void testJni() {
TvCastingApp tvCastingApp =
new TvCastingApp((app, clusterId, endpoint) -> app.doSomethingInCpp(endpoint));
tvCastingApp.doSomethingInCpp(0);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Project CHIP Authors
* Copyright (c) 2022 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -17,8 +17,28 @@
*/
package com.chip.casting;

import android.util.Log;

public class TvCastingApp {
public TvCastingApp() {}
private TvCastingAppCallback mCallback;
private static final String TAG = TvCastingApp.class.getSimpleName();

public TvCastingApp(TvCastingAppCallback callback) {
mCallback = callback;
nativeInit();
}

private void postClusterInit(int clusterId, int endpoint) {
Log.d(TAG, "postClusterInit for " + clusterId + " at " + endpoint);
if (mCallback != null) {
mCallback.onClusterInit(this, clusterId, endpoint);
}
}

public native void nativeInit();

/** TBD: Temp dummy function for testing */
public native void doSomethingInCpp(int endpoint);

static {
System.loadLibrary("TvCastingApp");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
*
* Copyright (c) 2022 Project CHIP Authors
*
* 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 TvCastingAppCallback {
void onClusterInit(TvCastingApp app, int clusterId, int endpoint);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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.
*
*/

#include "TvCastingApp-JNI.h"
#include <app/server/java/AndroidAppServerWrapper.h>
#include <jni.h>
#include <lib/core/CHIPError.h>
#include <lib/support/CHIPJNIError.h>
#include <lib/support/JniReferences.h>

using namespace chip;

#define JNI_METHOD(RETURN, METHOD_NAME) extern "C" JNIEXPORT RETURN JNICALL Java_com_chip_casting_TvCastingApp_##METHOD_NAME

TvCastingAppJNI TvCastingAppJNI::sInstance;

void TvCastingAppJNI::InitializeWithObjects(jobject app)
{
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturn(env != nullptr, ChipLogError(AppServer, "Failed to GetEnvForCurrentThread for TvCastingAppJNI"));

mTvCastingAppObject = env->NewGlobalRef(app);
VerifyOrReturn(mTvCastingAppObject != nullptr, ChipLogError(AppServer, "Failed to NewGlobalRef TvCastingAppJNI"));

jclass managerClass = env->GetObjectClass(mTvCastingAppObject);
VerifyOrReturn(managerClass != nullptr, ChipLogError(AppServer, "Failed to get TvCastingAppJNI Java class"));

mPostClusterInitMethod = env->GetMethodID(managerClass, "postClusterInit", "(II)V");
if (mPostClusterInitMethod == nullptr)
{
ChipLogError(AppServer, "Failed to access ChannelManager 'postClusterInit' method");
env->ExceptionClear();
}
}

void TvCastingAppJNI::PostClusterInit(chip::ClusterId clusterId, chip::EndpointId endpoint)
{
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturn(env != nullptr,
ChipLogError(AppServer, "Failed to GetEnvForCurrentThread for TvCastingAppJNI::PostClusterInit"));
VerifyOrReturn(mTvCastingAppObject != nullptr, ChipLogError(AppServer, "TvCastingAppJNI::mTvCastingAppObject null"));
VerifyOrReturn(mPostClusterInitMethod != nullptr, ChipLogError(AppServer, "TvCastingAppJNI::mPostClusterInitMethod null"));

env->CallVoidMethod(mTvCastingAppObject, mPostClusterInitMethod, static_cast<jint>(clusterId), static_cast<jint>(endpoint));
if (env->ExceptionCheck())
{
ChipLogError(AppServer, "Failed to call TvCastingAppJNI 'postClusterInit' method");
env->ExceptionClear();
}
}

jint JNI_OnLoad(JavaVM * jvm, void * reserved)
{
return AndroidAppServerJNI_OnLoad(jvm, reserved);
}

void JNI_OnUnload(JavaVM * jvm, void * reserved)
{
return AndroidAppServerJNI_OnUnload(jvm, reserved);
}

JNI_METHOD(void, nativeInit)(JNIEnv *, jobject app)
{
TvCastingAppJNIMgr().InitializeWithObjects(app);
}

// TBD: Temp dummy function for testing
JNI_METHOD(void, doSomethingInCpp)(JNIEnv *, jobject, jint endpoint)
{
ChipLogProgress(AppServer, "JNI_METHOD doSomethingInCpp called with endpoint %d", endpoint);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
*
* 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.
*/

#pragma once

#include <jni.h>
#include <lib/core/DataModelTypes.h>

class TvCastingAppJNI
{
public:
void InitializeWithObjects(jobject app);
void PostClusterInit(chip::ClusterId clusterId, chip::EndpointId endpoint);

private:
friend TvCastingAppJNI & TvCastingAppJNIMgr();

static TvCastingAppJNI sInstance;
jobject mTvCastingAppObject = nullptr;
jmethodID mPostClusterInitMethod = nullptr;
};

inline class TvCastingAppJNI & TvCastingAppJNIMgr()
{
return TvCastingAppJNI::sInstance;
}
10 changes: 8 additions & 2 deletions examples/tv-casting-app/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ import("${chip_root}/build/chip/tools.gni")
shared_library("jni") {
output_name = "libTvCastingApp"

sources = [ "${chip_root}/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h" ]
sources = [
"${chip_root}/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h",
"App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp",
]

deps = [
"${chip_root}/examples/tv-casting-app/tv-casting-common",
Expand Down Expand Up @@ -51,7 +54,10 @@ android_library("java") {
"${chip_root}/build/chip/java:shared_cpplib",
]

sources = [ "java/src/com/chip/casting/TvCastingApp.java" ]
sources = [
"App/app/src/main/jni/com/chip/casting/TvCastingApp.java",
"App/app/src/main/jni/com/chip/casting/TvCastingAppCallback.java",
]

javac_flags = [ "-Xlint:deprecation" ]

Expand Down
97 changes: 97 additions & 0 deletions examples/tv-casting-app/android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Matter TV Casting Android App Example

This is a Matter TV Casting Android app that can be used to cast content to a
TV. This app discovers TVs on the local network that act as commissioners, lets
the user select one, sends the TV a User Directed Commissioning request, enters
commissioning mode, advertises itself as a Commissionable Node and gets
commissioned. Then it allows the user to send Matter ContentLauncher commands to
the TV.

<hr>

- [Requirements for building](#requirements)
- [ABIs and TARGET_CPU](#abi)
- [Gradle & JDK Version](#jdk)
- [Preparing for build](#preparing)
- [Building & Installing the app](#building-installing)
- [Running the app on Android](#running-the-app-on-android)

<hr>

<a name="requirements"></a>

## Requirements for building

You need Android SDK 21 & NDK downloaded to your machine. Set the
`$ANDROID_HOME` environment variable to where the SDK is downloaded and the
`$ANDROID_NDK_HOME` environment variable to point to where the NDK package is
downloaded.

<a name="abi"></a>

### ABIs and TARGET_CPU

`TARGET_CPU` can have the following values, depending on your smartphone CPU
architecture:

| ABI | TARGET_CPU |
| ----------- | ---------- |
| armeabi-v7a | arm |
| arm64-v8a | arm64 |
| x86 | x86 |
| x86_64 | x64 |

<a name="jdk"></a>

### Gradle & JDK Version

We are using Gradle 7.1.1 for all android project which does not support Java 17
(https://docs.gradle.org/current/userguide/compatibility.html) while the default
JDK version on MacOS for Apple Silicon is 'openjdk 17.0.1' or above.

Using JDK bundled with Android Studio will help with that.

```shell
export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jre/Contents/Home/
```

<hr>

<a name="preparing"></a>

## Preparing for build

Complete the following steps to prepare the Matter build:

1. Check out the Matter repository.

2. Run bootstrap (**only required first time**)

```shell
source scripts/bootstrap.sh
```

<a name="building-installing"></a>

## Building & Installing the app

This is the simplest option. In the command line, run the following command from
the top Matter directory:

```shell
./scripts/build/build_examples.py --target android-arm64-chip-tv-casting-app build
```

See the table above for other values of `TARGET_CPU`.

The debug Android package `app-debug.apk` will be generated at
`out/android-$TARGET_CPU-chip-tv-casting-app/outputs/apk/debug/`, and can be
installed with

```shell
adb install out/android-$TARGET_CPU-chip-tv-casting-app/outputs/apk/debug/app-debug.apk
```

You can use Android Studio to edit the Android app itself and run it after
build_examples.py, but you will not be able to edit Matter Android code from
`src/controller/java`, or other Matter C++ code within Android Studio.
3 changes: 2 additions & 1 deletion scripts/build/builders/android.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def copyToExampleAndroid(self):
title='Prepare Native libs ' + self.identifier)

if self.app.ExampleName() == 'tv-casting-app':
libs = ['libc++_shared.so']
libs = ['libc++_shared.so', 'libTvCastingApp.so']
else:
libs = ['libSetupPayloadParser.so',
'libc++_shared.so', 'libTvApp.so']
Expand All @@ -194,6 +194,7 @@ def copyToExampleAndroid(self):
if self.app.ExampleName() == 'tv-casting-app':
jars = {
'AndroidPlatform.jar': 'third_party/connectedhomeip/src/platform/android/AndroidPlatform.jar',
'CHIPAppServer.jar': 'third_party/connectedhomeip/src/app/server/java/CHIPAppServer.jar',
'TvCastingApp.jar': 'TvCastingApp.jar',
}
else:
Expand Down
8 changes: 8 additions & 0 deletions scripts/build/testdata/build_all_except_host.txt
Original file line number Diff line number Diff line change
Expand Up @@ -725,8 +725,12 @@ mkdir -p {root}/examples/tv-casting-app/android/App/app/libs/jniLibs/armeabi-v7a

cp {out}/android-arm-chip-tv-casting-app/lib/jni/armeabi-v7a/libc++_shared.so {root}/examples/tv-casting-app/android/App/app/libs/jniLibs/armeabi-v7a/libc++_shared.so

cp {out}/android-arm-chip-tv-casting-app/lib/jni/armeabi-v7a/libTvCastingApp.so {root}/examples/tv-casting-app/android/App/app/libs/jniLibs/armeabi-v7a/libTvCastingApp.so

cp {out}/android-arm-chip-tv-casting-app/lib/third_party/connectedhomeip/src/platform/android/AndroidPlatform.jar {root}/examples/tv-casting-app/android/App/app/libs/AndroidPlatform.jar

cp {out}/android-arm-chip-tv-casting-app/lib/third_party/connectedhomeip/src/app/server/java/CHIPAppServer.jar {root}/examples/tv-casting-app/android/App/app/libs/CHIPAppServer.jar

cp {out}/android-arm-chip-tv-casting-app/lib/TvCastingApp.jar {root}/examples/tv-casting-app/android/App/app/libs/TvCastingApp.jar

# Building Example android-arm-chip-tv-casting-app
Expand Down Expand Up @@ -805,8 +809,12 @@ mkdir -p {root}/examples/tv-casting-app/android/App/app/libs/jniLibs/arm64-v8a

cp {out}/android-arm64-chip-tv-casting-app/lib/jni/arm64-v8a/libc++_shared.so {root}/examples/tv-casting-app/android/App/app/libs/jniLibs/arm64-v8a/libc++_shared.so

cp {out}/android-arm64-chip-tv-casting-app/lib/jni/arm64-v8a/libTvCastingApp.so {root}/examples/tv-casting-app/android/App/app/libs/jniLibs/arm64-v8a/libTvCastingApp.so

cp {out}/android-arm64-chip-tv-casting-app/lib/third_party/connectedhomeip/src/platform/android/AndroidPlatform.jar {root}/examples/tv-casting-app/android/App/app/libs/AndroidPlatform.jar

cp {out}/android-arm64-chip-tv-casting-app/lib/third_party/connectedhomeip/src/app/server/java/CHIPAppServer.jar {root}/examples/tv-casting-app/android/App/app/libs/CHIPAppServer.jar

cp {out}/android-arm64-chip-tv-casting-app/lib/TvCastingApp.jar {root}/examples/tv-casting-app/android/App/app/libs/TvCastingApp.jar

# Building Example android-arm64-chip-tv-casting-app
Expand Down

0 comments on commit 787d670

Please sign in to comment.