This commit is contained in:
Dan Albert
2025-09-19 19:14:49 +00:00
committed by GitHub
59 changed files with 711 additions and 357 deletions

View File

@@ -19,8 +19,13 @@ android {
}
}
namespace 'com.google.sample.echo'
buildFeatures {
prefab true
}
}
dependencies {
implementation libs.appcompat
implementation project(":base")
}

View File

@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.22.1)
project(echo LANGUAGES C CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(echo
SHARED
@@ -10,17 +11,20 @@ add_app_library(echo
audio_recorder.cpp
audio_effect.cpp
audio_common.cpp
debug_utils.cpp)
debug_utils.cpp
jni.cpp
)
#include libraries needed for echo lib
target_link_libraries(echo
PRIVATE
base::base
OpenSLES
android
log
atomic)
atomic
)
if (ANDROID_ABI STREQUAL riscv64)
if(ANDROID_ABI STREQUAL riscv64)
# This sample uses OpenSLES, which was deprecated in API 26. Our
# minSdkVersion is 21, but we also build for riscv64, which isn't a
# supported ABI yet and so that configuration is built for the latest API
@@ -32,4 +36,4 @@ if (ANDROID_ABI STREQUAL riscv64)
# measurement in this sample that should be moved to the Oboe sample before
# we delete it though.
target_compile_options(echo PRIVATE -Wno-deprecated-declarations)
endif ()
endif()

View File

@@ -51,9 +51,8 @@ static EchoAudioEngine engine;
bool EngineService(void* ctx, uint32_t msg, void* data);
JNIEXPORT void JNICALL Java_com_google_sample_echo_MainActivity_createSLEngine(
JNIEnv*, jclass, jint sampleRate, jint framesPerBuf, jlong delayInMs,
jfloat decay) {
void CreateSlEngine(JNIEnv*, jclass, jint sampleRate, jint framesPerBuf,
jlong delayInMs, jfloat decay) {
SLresult result;
memset(&engine, 0, sizeof(engine));
@@ -102,10 +101,7 @@ JNIEXPORT void JNICALL Java_com_google_sample_echo_MainActivity_createSLEngine(
assert(engine.delayEffect_);
}
JNIEXPORT jboolean JNICALL
Java_com_google_sample_echo_MainActivity_configureEcho(JNIEnv*, jclass,
jint delayInMs,
jfloat decay) {
jboolean ConfigureEcho(JNIEnv*, jclass, jint delayInMs, jfloat decay) {
engine.echoDelay_ = delayInMs;
engine.echoDecay_ = decay;
@@ -114,9 +110,7 @@ Java_com_google_sample_echo_MainActivity_configureEcho(JNIEnv*, jclass,
return JNI_FALSE;
}
JNIEXPORT jboolean JNICALL
Java_com_google_sample_echo_MainActivity_createSLBufferQueueAudioPlayer(
JNIEnv*, jclass) {
jboolean CreateSlBufferQueueAudioPlayer(JNIEnv*, jclass) {
SampleFormat sampleFormat;
memset(&sampleFormat, 0, sizeof(sampleFormat));
sampleFormat.pcmFormat_ = (uint16_t)engine.bitsPerSample_;
@@ -136,17 +130,14 @@ Java_com_google_sample_echo_MainActivity_createSLBufferQueueAudioPlayer(
return JNI_TRUE;
}
JNIEXPORT void JNICALL
Java_com_google_sample_echo_MainActivity_deleteSLBufferQueueAudioPlayer(
JNIEnv*, jclass) {
void DeleteSlBufferQueueAudioPlayer(JNIEnv*, jclass) {
if (engine.player_) {
delete engine.player_;
engine.player_ = nullptr;
}
}
JNIEXPORT jboolean JNICALL
Java_com_google_sample_echo_MainActivity_createAudioRecorder(JNIEnv*, jclass) {
jboolean CreateAudioRecorder(JNIEnv*, jclass) {
SampleFormat sampleFormat;
memset(&sampleFormat, 0, sizeof(sampleFormat));
sampleFormat.pcmFormat_ = static_cast<uint16_t>(engine.bitsPerSample_);
@@ -164,15 +155,13 @@ Java_com_google_sample_echo_MainActivity_createAudioRecorder(JNIEnv*, jclass) {
return JNI_TRUE;
}
JNIEXPORT void JNICALL
Java_com_google_sample_echo_MainActivity_deleteAudioRecorder(JNIEnv*, jclass) {
void DeleteAudioRecorder(JNIEnv*, jclass) {
if (engine.recorder_) delete engine.recorder_;
engine.recorder_ = nullptr;
}
JNIEXPORT void JNICALL
Java_com_google_sample_echo_MainActivity_startPlay(JNIEnv*, jclass) {
void StartPlay(JNIEnv*, jclass) {
engine.frameCount_ = 0;
/*
* start player: make it into waitForData state
@@ -184,8 +173,7 @@ Java_com_google_sample_echo_MainActivity_startPlay(JNIEnv*, jclass) {
engine.recorder_->Start();
}
JNIEXPORT void JNICALL
Java_com_google_sample_echo_MainActivity_stopPlay(JNIEnv*, jclass) {
void StopPlay(JNIEnv*, jclass) {
engine.recorder_->Stop();
engine.player_->Stop();
@@ -195,8 +183,7 @@ Java_com_google_sample_echo_MainActivity_stopPlay(JNIEnv*, jclass) {
engine.player_ = NULL;
}
JNIEXPORT void JNICALL
Java_com_google_sample_echo_MainActivity_deleteSLEngine(JNIEnv*, jclass) {
void DeleteSlEngine(JNIEnv*, jclass) {
delete engine.recBufQueue_;
delete engine.freeBufQueue_;
releaseSampleBufs(engine.bufs_, engine.bufCount_);

View File

@@ -0,0 +1,37 @@
// Copyright (C) 2025 The Android Open Source Project
// SPDX-License-Identifier: Apache-2.0
#include <base/macros.h>
#include <jni.h>
#include "jni_interface.h"
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/google/sample/echo/MainActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"createSLEngine", "(IIJF)V", reinterpret_cast<void*>(CreateSlEngine)},
{"deleteSLEngine", "()V", reinterpret_cast<void*>(DeleteSlEngine)},
{"createSLBufferQueueAudioPlayer", "()Z",
reinterpret_cast<void*>(CreateSlBufferQueueAudioPlayer)},
{"deleteSLBufferQueueAudioPlayer", "()V",
reinterpret_cast<void*>(DeleteSlBufferQueueAudioPlayer)},
{"createAudioRecorder", "()Z",
reinterpret_cast<void*>(CreateAudioRecorder)},
{"deleteAudioRecorder", "()V",
reinterpret_cast<void*>(DeleteAudioRecorder)},
{"startPlay", "()V", reinterpret_cast<void*>(StartPlay)},
{"stopPlay", "()V", reinterpret_cast<void*>(StopPlay)},
{"configureEcho", "(IF)Z", reinterpret_cast<void*>(ConfigureEcho)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -13,42 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef JNI_INTERFACE_H
#define JNI_INTERFACE_H
#pragma once
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
void CreateSlEngine(JNIEnv* env, jclass, jint, jint, jlong delayInMs,
jfloat decay);
void DeleteSlEngine(JNIEnv* env, jclass type);
jboolean CreateSlBufferQueueAudioPlayer(JNIEnv* env, jclass);
void DeleteSlBufferQueueAudioPlayer(JNIEnv* env, jclass type);
JNIEXPORT void JNICALL Java_com_google_sample_echo_MainActivity_createSLEngine(
JNIEnv* env, jclass, jint, jint, jlong delayInMs, jfloat decay);
JNIEXPORT void JNICALL Java_com_google_sample_echo_MainActivity_deleteSLEngine(
JNIEnv* env, jclass type);
JNIEXPORT jboolean JNICALL
Java_com_google_sample_echo_MainActivity_createSLBufferQueueAudioPlayer(
JNIEnv* env, jclass);
JNIEXPORT void JNICALL
Java_com_google_sample_echo_MainActivity_deleteSLBufferQueueAudioPlayer(
JNIEnv* env, jclass type);
JNIEXPORT jboolean JNICALL
Java_com_google_sample_echo_MainActivity_createAudioRecorder(JNIEnv* env,
jclass type);
JNIEXPORT void JNICALL
Java_com_google_sample_echo_MainActivity_deleteAudioRecorder(JNIEnv* env,
jclass type);
JNIEXPORT void JNICALL
Java_com_google_sample_echo_MainActivity_startPlay(JNIEnv* env, jclass type);
JNIEXPORT void JNICALL
Java_com_google_sample_echo_MainActivity_stopPlay(JNIEnv* env, jclass type);
JNIEXPORT jboolean JNICALL
Java_com_google_sample_echo_MainActivity_configureEcho(JNIEnv* env, jclass type,
jint delayInMs,
jfloat decay);
#ifdef __cplusplus
}
#endif
#endif // JNI_INTERFACE_H
jboolean CreateAudioRecorder(JNIEnv* env, jclass type);
void DeleteAudioRecorder(JNIEnv* env, jclass type);
void StartPlay(JNIEnv* env, jclass type);
void StopPlay(JNIEnv* env, jclass type);
jboolean ConfigureEcho(JNIEnv* env, jclass type, jint delayInMs, jfloat decay);

View File

@@ -12,4 +12,12 @@ android {
path 'src/main/cpp/CMakeLists.txt'
}
}
buildFeatures {
prefab true
}
}
dependencies {
implementation project(":base")
}

View File

@@ -2,11 +2,12 @@ cmake_minimum_required(VERSION 3.22.1)
project(BitmapPlasma LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(plasma SHARED plasma.cpp)
add_app_library(plasma SHARED jni.cpp plasma.cpp)
# Include libraries needed for plasma lib
target_link_libraries(plasma
base::base
android
jnigraphics
log

View File

@@ -0,0 +1,26 @@
// Copyright (C) 2025 The Android Open Source Project
// SPDX-License-Identifier: Apache-2.0
#include <base/macros.h>
#include <jni.h>
#include "plasma.h"
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/example/plasma/PlasmaView");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"renderPlasma", "(Landroid/graphics/Bitmap;J)V",
reinterpret_cast<void*>(RenderPlasma)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -327,8 +327,7 @@ static void stats_endFrame(Stats* s) {
s->lastTime = now;
}
JNIEXPORT void JNICALL Java_com_example_plasma_PlasmaView_renderPlasma(
JNIEnv* env, jclass, jobject bitmap, jlong time_ms) {
void RenderPlasma(JNIEnv* env, jclass, jobject bitmap, jlong time_ms) {
AndroidBitmapInfo info;
void* pixels;
int ret;

View File

@@ -0,0 +1,8 @@
// Copyright (C) 2025 The Android Open Source Project
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <jni.h>
void RenderPlasma(JNIEnv* env, jclass, jobject bitmap, jlong time_ms);

View File

@@ -25,6 +25,7 @@ android {
}
dependencies {
implementation project(":base")
implementation libs.appcompat
implementation project(":camera:camera-utils")
}

View File

@@ -19,6 +19,7 @@ project(CameraBasic LANGUAGES C CXX)
include(AppLibrary)
include(AndroidNdkModules)
find_package(base REQUIRED CONFIG)
find_package(camera-utils REQUIRED CONFIG)
android_ndk_import_module_native_app_glue()
@@ -34,6 +35,7 @@ add_app_library(ndk_camera SHARED
target_link_libraries(ndk_camera
PRIVATE
base::base
camera-utils::camera-utils
android
log

View File

@@ -15,6 +15,7 @@
* limitations under the License.
*/
#include <base/macros.h>
#include <ndksamples/camera/native_debug.h>
#include "camera_engine.h"
@@ -126,30 +127,46 @@ void CameraEngine::OnCameraPermission(jboolean granted) {
* exposure and sensitivity SeekBars
* takePhoto button
*/
extern "C" JNIEXPORT void JNICALL
Java_com_sample_camera_basic_CameraActivity_notifyCameraPermission(
JNIEnv*, jclass, jboolean permission) {
void notifyCameraPermission(JNIEnv*, jclass, jboolean permission) {
std::thread permissionHandler(&CameraEngine::OnCameraPermission,
GetAppEngine(), permission);
permissionHandler.detach();
}
extern "C" JNIEXPORT void JNICALL
Java_com_sample_camera_basic_CameraActivity_TakePhoto(JNIEnv*, jclass) {
void TakePhoto(JNIEnv*, jclass) {
std::thread takePhotoHandler(&CameraEngine::OnTakePhoto, GetAppEngine());
takePhotoHandler.detach();
}
extern "C" JNIEXPORT void JNICALL
Java_com_sample_camera_basic_CameraActivity_OnExposureChanged(
JNIEnv*, jobject, jlong exposurePercent) {
void OnExposureChanged(JNIEnv*, jobject, jlong exposurePercent) {
GetAppEngine()->OnCameraParameterChanged(ACAMERA_SENSOR_EXPOSURE_TIME,
exposurePercent);
}
extern "C" JNIEXPORT void JNICALL
Java_com_sample_camera_basic_CameraActivity_OnSensitivityChanged(
JNIEnv*, jobject, jlong sensitivity) {
void OnSensitivityChanged(JNIEnv*, jobject, jlong sensitivity) {
GetAppEngine()->OnCameraParameterChanged(ACAMERA_SENSOR_SENSITIVITY,
sensitivity);
}
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/sample/camera/basic/CameraActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"notifyCameraPermission", "(Z)V",
reinterpret_cast<void*>(notifyCameraPermission)},
{"TakePhoto", "()V", reinterpret_cast<void*>(TakePhoto)},
{"OnExposureChanged", "(J)V", reinterpret_cast<void*>(OnExposureChanged)},
{"OnSensitivityChanged", "(J)V",
reinterpret_cast<void*>(OnSensitivityChanged)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -27,5 +27,6 @@ android {
dependencies {
implementation libs.androidx.core
implementation project(":base")
implementation project(":camera:camera-utils")
}

View File

@@ -18,13 +18,9 @@ cmake_minimum_required(VERSION 3.22.1)
project(CameraTextureView LANGUAGES CXX)
include(AppLibrary)
find_package(base REQUIRED CONFIG)
find_package(camera-utils REQUIRED CONFIG)
# Export ANativeActivity_onCreate(),
# Refer to: https://github.com/android-ndk/ndk/issues/381.
set(CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
add_app_library(camera_textureview SHARED
android_main.cpp
camera_manager.cpp
@@ -32,9 +28,9 @@ add_app_library(camera_textureview SHARED
camera_listeners.cpp
)
# add lib dependencies
target_link_libraries(camera_textureview
PRIVATE
base::base
camera-utils::camera-utils
dl
android

View File

@@ -22,6 +22,7 @@
* Tested:
* Google Pixel and Nexus 6 phones
*/
#include <base/macros.h>
#include <jni.h>
#include <ndksamples/camera/native_debug.h>
@@ -49,9 +50,7 @@ CameraAppEngine* pEngineObj = nullptr;
* portrait mode.
* @return application object instance ( not used in this sample )
*/
extern "C" JNIEXPORT jlong JNICALL
Java_com_sample_textureview_ViewActivity_createCamera(JNIEnv* env, jobject,
jint width, jint height) {
jlong CreateCamera(JNIEnv* env, jobject, jint width, jint height) {
pEngineObj = new CameraAppEngine(env, width, height);
return reinterpret_cast<jlong>(pEngineObj);
}
@@ -61,9 +60,7 @@ Java_com_sample_textureview_ViewActivity_createCamera(JNIEnv* env, jobject,
* releases native application object, which
* triggers native camera object be released
*/
extern "C" JNIEXPORT void JNICALL
Java_com_sample_textureview_ViewActivity_deleteCamera(JNIEnv*, jobject,
jlong ndkCameraObj) {
void DeleteCamera(JNIEnv*, jobject, jlong ndkCameraObj) {
if (!pEngineObj || !ndkCameraObj) {
return;
}
@@ -87,9 +84,8 @@ Java_com_sample_textureview_ViewActivity_deleteCamera(JNIEnv*, jobject,
* 3) textureView size is stretched when previewing image
* on display device
*/
extern "C" JNIEXPORT jobject JNICALL
Java_com_sample_textureview_ViewActivity_getMinimumCompatiblePreviewSize(
JNIEnv* env, jobject, jlong ndkCameraObj) {
jobject GetMinimumCompatiblePreviewSize(JNIEnv* env, jobject,
jlong ndkCameraObj) {
if (!ndkCameraObj) {
return nullptr;
}
@@ -102,28 +98,14 @@ Java_com_sample_textureview_ViewActivity_getMinimumCompatiblePreviewSize(
return previewSize;
}
/**
* getCameraSensorOrientation()
* @ return camera sensor orientation angle relative to Android device's
* display orientation. This sample only deal to back facing camera.
*/
extern "C" JNIEXPORT jint JNICALL
Java_com_sample_textureview_ViewActivity_getCameraSensorOrientation(
JNIEnv*, jobject, jlong ndkCameraObj) {
ASSERT(ndkCameraObj, "NativeObject should not be null Pointer");
CameraAppEngine* pApp = reinterpret_cast<CameraAppEngine*>(ndkCameraObj);
return pApp->GetCameraSensorOrientation(ACAMERA_LENS_FACING_BACK);
}
/**
* OnPreviewSurfaceCreated()
* Notification to native camera that java TextureView is ready
* to preview video. Simply create cameraSession and
* start camera preview
*/
extern "C" JNIEXPORT void JNICALL
Java_com_sample_textureview_ViewActivity_onPreviewSurfaceCreated(
JNIEnv*, jobject, jlong ndkCameraObj, jobject surface) {
void OnPreviewSurfaceCreated(JNIEnv*, jobject, jlong ndkCameraObj,
jobject surface) {
ASSERT(ndkCameraObj && (jlong)pEngineObj == ndkCameraObj,
"NativeObject should not be null Pointer");
CameraAppEngine* pApp = reinterpret_cast<CameraAppEngine*>(ndkCameraObj);
@@ -137,9 +119,8 @@ Java_com_sample_textureview_ViewActivity_onPreviewSurfaceCreated(
* Native camera would:
* * stop preview
*/
extern "C" JNIEXPORT void JNICALL
Java_com_sample_textureview_ViewActivity_onPreviewSurfaceDestroyed(
JNIEnv* env, jobject, jlong ndkCameraObj, jobject surface) {
void OnPreviewSurfaceDestroyed(JNIEnv* env, jobject, jlong ndkCameraObj,
jobject surface) {
CameraAppEngine* pApp = reinterpret_cast<CameraAppEngine*>(ndkCameraObj);
ASSERT(ndkCameraObj && pEngineObj == pApp,
"NativeObject should not be null Pointer");
@@ -162,3 +143,29 @@ Java_com_sample_textureview_ViewActivity_onPreviewSurfaceDestroyed(
pApp->StartPreview(false);
}
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/sample/textureview/ViewActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"createCamera", "(II)J", reinterpret_cast<void*>(CreateCamera)},
{"deleteCamera", "(JLandroid/view/Surface;)V",
reinterpret_cast<void*>(DeleteCamera)},
{"getMinimumCompatiblePreviewSize", "(J)Landroid/util/Size;",
reinterpret_cast<void*>(GetMinimumCompatiblePreviewSize)},
{"onPreviewSurfaceCreated", "(JLandroid/view/Surface;)V",
reinterpret_cast<void*>(OnPreviewSurfaceCreated)},
{"onPreviewSurfaceDestroyed", "(JLandroid/view/Surface;)V",
reinterpret_cast<void*>(OnPreviewSurfaceDestroyed)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -19,6 +19,7 @@ android {
}
buildFeatures {
prefab true
viewBinding true
}
}
@@ -27,4 +28,5 @@ dependencies {
implementation libs.appcompat
implementation libs.material
implementation libs.androidx.constraintlayout
implementation project(":base")
}

View File

@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.22.1)
project(exceptions LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(
exceptions
@@ -12,5 +13,7 @@ add_app_library(
target_link_libraries(
exceptions
PRIVATE
base::base
log
)

View File

@@ -1,3 +1,4 @@
#include <base/macros.h>
#include <jni.h>
#include <stdexcept>
@@ -6,9 +7,7 @@
void might_throw() { throw std::runtime_error("A C++ runtime_error"); }
extern "C" JNIEXPORT void JNICALL
Java_com_example_exceptions_MainActivity_throwsException(JNIEnv* env,
jobject /* this */) {
void ThrowsException(JNIEnv* env, jobject /* this */) {
try {
might_throw();
} catch (std::exception& e) {
@@ -18,4 +17,22 @@ Java_com_example_exceptions_MainActivity_throwsException(JNIEnv* env,
// catch-all.
jniThrowRuntimeException(env, "Catch-all");
}
}
}
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/example/exceptions/MainActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"throwsException", "()V", reinterpret_cast<void*>(ThrowsException)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -19,4 +19,12 @@ android {
path 'src/main/cpp/CMakeLists.txt'
}
}
buildFeatures {
prefab true
}
}
dependencies {
implementation project(":base")
}

View File

@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.22.1)
project(Gles3Jni LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(gles3jni SHARED
${GL3STUB_SRC}
@@ -10,8 +11,8 @@ add_app_library(gles3jni SHARED
RendererES3.cpp
)
# Include libraries needed for gles3jni lib
target_link_libraries(gles3jni
base::base
GLESv3
android
EGL

View File

@@ -16,6 +16,7 @@
#include "gles3jni.h"
#include <base/macros.h>
#include <jni.h>
#include <stdlib.h>
#include <string.h>
@@ -227,21 +228,11 @@ void Renderer::render() {
static Renderer* g_renderer = NULL;
extern "C" {
JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_init(JNIEnv* env,
jobject obj);
JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_resize(
JNIEnv* env, jobject obj, jint width, jint height);
JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_step(JNIEnv* env,
jobject obj);
};
#if !defined(DYNAMIC_ES3)
static GLboolean gl3stubInit() { return GL_TRUE; }
#endif
JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_init(JNIEnv*,
jobject) {
void Init(JNIEnv*, jclass) {
if (g_renderer) {
delete g_renderer;
g_renderer = NULL;
@@ -262,16 +253,34 @@ JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_init(JNIEnv*,
}
}
JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_resize(
JNIEnv*, jobject, jint width, jint height) {
void Resize(JNIEnv*, jclass, jint width, jint height) {
if (g_renderer) {
g_renderer->resize(width, height);
}
}
JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_step(JNIEnv*,
jobject) {
void Step(JNIEnv*, jclass) {
if (g_renderer) {
g_renderer->render();
}
}
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/android/gles3jni/GLES3JNILib");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"init", "()V", reinterpret_cast<void*>(Init)},
{"resize", "(II)V", reinterpret_cast<void*>(Resize)},
{"step", "()V", reinterpret_cast<void*>(Step)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -20,4 +20,12 @@ android {
path 'src/main/cpp/CMakeLists.txt'
}
}
buildFeatures {
prefab true
}
}
dependencies {
implementation project(":base")
}

View File

@@ -2,10 +2,13 @@ cmake_minimum_required(VERSION 3.22.1)
project(HelloGl2 LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(gl2jni SHARED gl_code.cpp)
target_link_libraries(gl2jni
PRIVATE
base::base
android
log
EGL

View File

@@ -19,6 +19,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <android/log.h>
#include <base/macros.h>
#include <jni.h>
#include <math.h>
#include <stdio.h>
@@ -163,15 +164,27 @@ void renderFrame() {
checkGlError("glDrawArrays");
}
extern "C" {
JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv*, jobject,
jint width,
jint height) {
void Init(JNIEnv*, jclass, jint width, jint height) {
setupGraphics(width, height);
}
JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv*,
jobject) {
renderFrame();
}
void Step(JNIEnv*, jclass) { renderFrame(); }
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/android/gl2jni/GL2JNILib");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"init", "(II)V", reinterpret_cast<void*>(Init)},
{"step", "()V", reinterpret_cast<void*>(Step)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -21,9 +21,14 @@ android {
buildFeatures {
viewBinding true
}
buildFeatures {
prefab true
}
}
dependencies {
implementation project(":base")
implementation libs.appcompat
implementation libs.androidx.constraintlayout
}

View File

@@ -2,12 +2,15 @@ cmake_minimum_required(VERSION 3.22.1)
project("hello-jni" LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(hello-jni SHARED
hello-jni.cpp
)
target_link_libraries(hello-jni
PRIVATE
base::base
android
log
)

View File

@@ -14,13 +14,31 @@
* limitations under the License.
*
*/
#include <base/macros.h>
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv* env,
jobject /* this */) {
jstring StringFromJni(JNIEnv* env, jobject) {
std::string hello = "Hello from JNI.";
return env->NewStringUTF(hello.c_str());
}
}
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/example/hellojni/HelloJni");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"stringFromJNI", "()Ljava/lang/String;",
reinterpret_cast<void*>(StringFromJni)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -16,9 +16,14 @@ android {
path "src/main/cpp/CMakeLists.txt"
}
}
buildFeatures {
prefab true
}
}
dependencies {
implementation project(":base")
implementation libs.appcompat
implementation libs.androidx.constraintlayout
}

View File

@@ -2,10 +2,13 @@ cmake_minimum_required(VERSION 3.22.1)
project(HelloJniCallback LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(hello-jnicallback SHARED hello-jnicallback.cpp)
target_link_libraries(hello-jnicallback
PRIVATE
base::base
android
log
)

View File

@@ -16,6 +16,7 @@
*/
#include <android/log.h>
#include <assert.h>
#include <base/macros.h>
#include <inttypes.h>
#include <jni.h>
#include <pthread.h>
@@ -132,40 +133,6 @@ void queryRuntimeInfo(JNIEnv* env, jobject instance) {
(void)result; // silence the compiler warning
}
/*
* processing one time initialization:
* Cache the javaVM into our context
* Find class ID for JniHandler
* Create an instance of JniHandler
* Make global reference since we are using them from a native thread
* Note:
* All resources allocated here are never released by application
* we rely on system to free all global refs when it goes away;
* the pairing function JNI_OnUnload() never gets called at all.
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
JNIEnv* env;
memset(&g_ctx, 0, sizeof(g_ctx));
g_ctx.javaVM = vm;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR; // JNI version not supported.
}
jclass clz = env->FindClass("com/example/hellojnicallback/JniHandler");
g_ctx.jniHandlerClz = static_cast<jclass>(env->NewGlobalRef(clz));
jmethodID jniHandlerCtor =
env->GetMethodID(g_ctx.jniHandlerClz, "<init>", "()V");
jobject handler = env->NewObject(g_ctx.jniHandlerClz, jniHandlerCtor);
g_ctx.jniHandlerObj = env->NewGlobalRef(handler);
queryRuntimeInfo(env, g_ctx.jniHandlerObj);
g_ctx.done = 0;
g_ctx.mainActivityObj = NULL;
return JNI_VERSION_1_6;
}
/*
* A helper function to wrap java JniHandler::updateStatus(String msg)
* JNI allow us to call this function via an instance even it is
@@ -248,9 +215,7 @@ void* UpdateTicks(void* context) {
/*
* Interface to Java side to start ticks, caller is from onResume()
*/
extern "C" JNIEXPORT void JNICALL
Java_com_example_hellojnicallback_MainActivity_startTicks(JNIEnv* env,
jobject instance) {
void StartTicks(JNIEnv* env, jobject instance) {
pthread_t threadInfo_;
pthread_attr_t threadAttr_;
@@ -276,8 +241,7 @@ Java_com_example_hellojnicallback_MainActivity_startTicks(JNIEnv* env,
* we need to hold and make sure our native thread has finished before return
* for a clean shutdown. The caller is from onPause
*/
extern "C" JNIEXPORT void JNICALL
Java_com_example_hellojnicallback_MainActivity_StopTicks(JNIEnv* env, jobject) {
void StopTicks(JNIEnv* env, jobject) {
pthread_mutex_lock(&g_ctx.lock);
g_ctx.done = 1;
pthread_mutex_unlock(&g_ctx.lock);
@@ -298,3 +262,48 @@ Java_com_example_hellojnicallback_MainActivity_StopTicks(JNIEnv* env, jobject) {
pthread_mutex_destroy(&g_ctx.lock);
}
/*
* processing one time initialization:
* Cache the javaVM into our context
* Register native methods
* Find class ID for JniHandler
* Create an instance of JniHandler
* Make global reference since we are using them from a native thread
* Note:
* All resources allocated here are never released by application
* we rely on system to free all global refs when it goes away;
* the pairing function JNI_OnUnload() never gets called at all.
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
JNIEnv* env;
memset(&g_ctx, 0, sizeof(g_ctx));
g_ctx.javaVM = vm;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR; // JNI version not supported.
}
jclass c = env->FindClass("com/example/hellojnicallback/MainActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"startTicks", "()V", reinterpret_cast<void*>(StartTicks)},
{"StopTicks", "()V", reinterpret_cast<void*>(StopTicks)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
jclass clz = env->FindClass("com/example/hellojnicallback/JniHandler");
g_ctx.jniHandlerClz = static_cast<jclass>(env->NewGlobalRef(clz));
jmethodID jniHandlerCtor =
env->GetMethodID(g_ctx.jniHandlerClz, "<init>", "()V");
jobject handler = env->NewObject(g_ctx.jniHandlerClz, jniHandlerCtor);
g_ctx.jniHandlerObj = env->NewGlobalRef(handler);
queryRuntimeInfo(env, g_ctx.jniHandlerObj);
g_ctx.done = 0;
g_ctx.mainActivityObj = NULL;
return JNI_VERSION_1_6;
}

View File

@@ -1,6 +0,0 @@
# Sample removed
This sample has been removed in favor of the new `vectorization` sample, which
demonstrates more options for vectorization and includes a benchmark to
highlight that performance decisions cannot be made correctly unless you measure
them.

View File

@@ -33,6 +33,7 @@ android {
}
dependencies {
implementation project(":base")
implementation libs.appcompat
implementation libs.androidx.constraintlayout
implementation libs.oboe

View File

@@ -17,6 +17,7 @@ cmake_minimum_required(VERSION 3.22.1)
project(hello-oboe LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
# add oboe pre-release lib hosted at https://maven.google.com/web/index.html
# under com.google.oboe:oboe. For documentation about oboe pre-built lib, refer to
@@ -25,7 +26,7 @@ find_package(oboe REQUIRED CONFIG)
# build application with the oboe lib
add_app_library(${PROJECT_NAME} SHARED hello-oboe.cpp)
target_link_libraries(${PROJECT_NAME} oboe::oboe android log)
target_link_libraries(${PROJECT_NAME} base::base oboe::oboe android log)
# Enable optimization flags: if having problems with source level debugging,
# disable -Ofast ( and debug ), re-enable after done debugging.

View File

@@ -15,27 +15,23 @@
*
*/
#include <base/macros.h>
#include <jni.h>
#include "OboeSinePlayer.h"
static OboeSinePlayer* oboePlayer = nullptr;
extern "C" {
/* Create Oboe playback stream
* Returns: 0 - success
* -1 - failed
*/
JNIEXPORT jint JNICALL
Java_com_google_example_hellooboe_MainActivity_createStream(
JNIEnv* /* env */, jobject /* this */) {
jint CreateStream(JNIEnv* /* env */, jobject /* this */) {
oboePlayer = new OboeSinePlayer();
return oboePlayer ? 0 : -1;
}
JNIEXPORT void JNICALL
Java_com_google_example_hellooboe_MainActivity_destroyStream(
JNIEnv* /* env */, jobject /* this */) {
void DestroyStream(JNIEnv* /* env */, jobject /* this */) {
if (oboePlayer) {
delete oboePlayer;
oboePlayer = nullptr;
@@ -46,8 +42,7 @@ Java_com_google_example_hellooboe_MainActivity_destroyStream(
* returns: 0 - success
* -1 - failed (stream has not created yet )
*/
JNIEXPORT jint JNICALL Java_com_google_example_hellooboe_MainActivity_playSound(
JNIEnv* /* env */, jobject /* this */, jboolean enable) {
jint PlaySound(JNIEnv* /* env */, jobject /* this */, jboolean enable) {
jint result = 0;
if (oboePlayer) {
oboePlayer->enable(enable);
@@ -56,4 +51,23 @@ JNIEXPORT jint JNICALL Java_com_google_example_hellooboe_MainActivity_playSound(
}
return result;
}
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/google/example/hellooboe/MainActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"createStream", "()I", reinterpret_cast<void*>(CreateStream)},
{"destroyStream", "()V", reinterpret_cast<void*>(DestroyStream)},
{"playSound", "(Z)I", reinterpret_cast<void*>(PlaySound)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -19,9 +19,11 @@ android {
buildFeatures {
buildConfig = true
prefab = true
}
}
dependencies {
implementation project(":base")
implementation libs.appcompat
}

View File

@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.22.1)
project(NativeAudio LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(native-audio-jni SHARED
native-audio-jni.cpp
@@ -9,6 +10,8 @@ add_app_library(native-audio-jni SHARED
# Include libraries needed for native-audio-jni lib
target_link_libraries(native-audio-jni
PRIVATE
base::base
android
log
OpenSLES

View File

@@ -22,6 +22,7 @@
*/
#include <assert.h>
#include <base/macros.h>
#include <jni.h>
#include <pthread.h>
#include <stdlib.h>
@@ -234,8 +235,7 @@ void bqRecorderCallback([[maybe_unused]] SLAndroidSimpleBufferQueueItf bq,
}
// create the engine and output mix objects
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_createEngine(JNIEnv*, jclass) {
void CreateEngine(JNIEnv*, jclass) {
SLresult result;
// create engine
@@ -286,9 +286,8 @@ Java_com_example_nativeaudio_NativeAudio_createEngine(JNIEnv*, jclass) {
}
// create buffer queue audio player
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_createBufferQueueAudioPlayer(
JNIEnv*, jclass, jint sampleRate, jint bufSize) {
void CreateBufferQueueAudioPlayer(JNIEnv*, jclass, jint sampleRate,
jint bufSize) {
SLresult result;
if (sampleRate >= 0 && bufSize >= 0) {
bqPlayerSampleRate = sampleRate * 1000;
@@ -395,10 +394,7 @@ Java_com_example_nativeaudio_NativeAudio_createBufferQueueAudioPlayer(
}
// create URI audio player
extern "C" JNIEXPORT jboolean JNICALL
Java_com_example_nativeaudio_NativeAudio_createUriAudioPlayer(JNIEnv* env,
jclass,
jstring uri) {
jboolean CreateUriAudioPlayer(JNIEnv* env, jclass, jstring uri) {
SLresult result;
// convert Java string to UTF-8
@@ -471,9 +467,7 @@ Java_com_example_nativeaudio_NativeAudio_createUriAudioPlayer(JNIEnv* env,
// set the playing state for the URI audio player
// to PLAYING (true) or PAUSED (false)
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_setPlayingUriAudioPlayer(
JNIEnv*, jclass, jboolean isPlaying) {
void SetPlayingUriAudioPlayer(JNIEnv*, jclass, jboolean isPlaying) {
SLresult result;
// make sure the URI audio player was created
@@ -488,9 +482,7 @@ Java_com_example_nativeaudio_NativeAudio_setPlayingUriAudioPlayer(
}
// set the whole file looping state for the URI audio player
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_setLoopingUriAudioPlayer(
JNIEnv*, jclass, jboolean isLooping) {
void SetLoopingUriAudioPlayer(JNIEnv*, jclass, jboolean isLooping) {
SLresult result;
// make sure the URI audio player was created
@@ -515,9 +507,7 @@ static SLMuteSoloItf getMuteSolo() {
return bqPlayerMuteSolo;
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_setChannelMuteUriAudioPlayer(
JNIEnv*, jclass, jint chan, jboolean mute) {
void SetChannelMuteUriAudioPlayer(JNIEnv*, jclass, jint chan, jboolean mute) {
SLresult result;
SLMuteSoloItf muteSoloItf = getMuteSolo();
if (NULL != muteSoloItf) {
@@ -527,9 +517,7 @@ Java_com_example_nativeaudio_NativeAudio_setChannelMuteUriAudioPlayer(
}
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_setChannelSoloUriAudioPlayer(
JNIEnv*, jclass, jint chan, jboolean solo) {
void SetChannelSoloUriAudioPlayer(JNIEnv*, jclass, jint chan, jboolean solo) {
SLresult result;
SLMuteSoloItf muteSoloItf = getMuteSolo();
if (NULL != muteSoloItf) {
@@ -539,9 +527,7 @@ Java_com_example_nativeaudio_NativeAudio_setChannelSoloUriAudioPlayer(
}
}
extern "C" JNIEXPORT jint JNICALL
Java_com_example_nativeaudio_NativeAudio_getNumChannelsUriAudioPlayer(JNIEnv*,
jclass) {
jint GetNumChannelsUriAudioPlayer(JNIEnv*, jclass) {
SLuint8 numChannels;
SLresult result;
SLMuteSoloItf muteSoloItf = getMuteSolo();
@@ -570,9 +556,7 @@ static SLVolumeItf getVolume() {
return bqPlayerVolume;
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_setVolumeUriAudioPlayer(
JNIEnv*, jclass, jint millibel) {
void SetVolumeUriAudioPlayer(JNIEnv*, jclass, jint millibel) {
SLresult result;
SLVolumeItf volumeItf = getVolume();
if (NULL != volumeItf) {
@@ -582,9 +566,7 @@ Java_com_example_nativeaudio_NativeAudio_setVolumeUriAudioPlayer(
}
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_setMuteUriAudioPlayer(JNIEnv*, jclass,
jboolean mute) {
void SetMuteUriAudioPlayer(JNIEnv*, jclass, jboolean mute) {
SLresult result;
SLVolumeItf volumeItf = getVolume();
if (NULL != volumeItf) {
@@ -594,9 +576,7 @@ Java_com_example_nativeaudio_NativeAudio_setMuteUriAudioPlayer(JNIEnv*, jclass,
}
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_enableStereoPositionUriAudioPlayer(
JNIEnv*, jclass, jboolean enable) {
void EnableStereoPositionUriAudioPlayer(JNIEnv*, jclass, jboolean enable) {
SLresult result;
SLVolumeItf volumeItf = getVolume();
if (NULL != volumeItf) {
@@ -606,9 +586,7 @@ Java_com_example_nativeaudio_NativeAudio_enableStereoPositionUriAudioPlayer(
}
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_setStereoPositionUriAudioPlayer(
JNIEnv*, jclass, jint permille) {
void SetStereoPositionUriAudioPlayer(JNIEnv*, jclass, jint permille) {
SLresult result;
SLVolumeItf volumeItf = getVolume();
if (NULL != volumeItf) {
@@ -619,9 +597,7 @@ Java_com_example_nativeaudio_NativeAudio_setStereoPositionUriAudioPlayer(
}
// enable reverb on the buffer queue player
extern "C" JNIEXPORT jboolean JNICALL
Java_com_example_nativeaudio_NativeAudio_enableReverb(JNIEnv*, jclass,
jboolean enabled) {
jboolean EnableReverb(JNIEnv*, jclass, jboolean enabled) {
SLresult result;
// we might not have been able to add environmental reverb to the output mix
@@ -649,9 +625,7 @@ Java_com_example_nativeaudio_NativeAudio_enableReverb(JNIEnv*, jclass,
}
// select the desired clip and play count, and enqueue the first buffer if idle
extern "C" JNIEXPORT jboolean JNICALL
Java_com_example_nativeaudio_NativeAudio_selectClip(JNIEnv*, jclass, jint which,
jint count) {
jboolean SelectClip(JNIEnv*, jclass, jint which, jint count) {
if (pthread_mutex_trylock(&audioEngineLock)) {
// If we could not acquire audio engine lock, reject this request and client
// should re-try
@@ -722,9 +696,8 @@ Java_com_example_nativeaudio_NativeAudio_selectClip(JNIEnv*, jclass, jint which,
}
// create asset audio player
extern "C" JNIEXPORT jboolean JNICALL
Java_com_example_nativeaudio_NativeAudio_createAssetAudioPlayer(
JNIEnv* env, jclass, jobject assetManager, jstring filename) {
jboolean CreateAssetAudioPlayer(JNIEnv* env, jclass, jobject assetManager,
jstring filename) {
SLresult result;
// convert Java string to UTF-8
@@ -811,9 +784,7 @@ Java_com_example_nativeaudio_NativeAudio_createAssetAudioPlayer(
}
// set the playing state for the asset audio player
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_setPlayingAssetAudioPlayer(
JNIEnv*, jclass, jboolean isPlaying) {
void SetPlayingAssetAudioPlayer(JNIEnv*, jclass, jboolean isPlaying) {
SLresult result;
// make sure the asset audio player was created
@@ -830,8 +801,7 @@ Java_com_example_nativeaudio_NativeAudio_setPlayingAssetAudioPlayer(
// create audio recorder: recorder is not in fast path
// like to avoid excessive re-sampling while playing back from Hello &
// Android clip
extern "C" JNIEXPORT jboolean JNICALL
Java_com_example_nativeaudio_NativeAudio_createAudioRecorder(JNIEnv*, jclass) {
jboolean CreateAudioRecorder(JNIEnv*, jclass) {
SLresult result;
// configure audio source
@@ -891,8 +861,7 @@ Java_com_example_nativeaudio_NativeAudio_createAudioRecorder(JNIEnv*, jclass) {
}
// set the recording state for the audio recorder
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_startRecording(JNIEnv*, jclass) {
void StartRecording(JNIEnv*, jclass) {
SLresult result;
if (pthread_mutex_trylock(&audioEngineLock)) {
@@ -929,8 +898,7 @@ Java_com_example_nativeaudio_NativeAudio_startRecording(JNIEnv*, jclass) {
}
// shut down the native audio system
extern "C" JNIEXPORT void JNICALL
Java_com_example_nativeaudio_NativeAudio_shutdown(JNIEnv*, jclass) {
void Shutdown(JNIEnv*, jclass) {
// destroy buffer queue audio player object, and invalidate all associated
// interfaces
if (bqPlayerObject != NULL) {
@@ -988,3 +956,55 @@ Java_com_example_nativeaudio_NativeAudio_shutdown(JNIEnv*, jclass) {
pthread_mutex_destroy(&audioEngineLock);
}
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* _Nonnull vm,
void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/example/nativeaudio/NativeAudio");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"createEngine", "()V", reinterpret_cast<void*>(CreateEngine)},
{"createBufferQueueAudioPlayer", "(II)V",
reinterpret_cast<void*>(CreateBufferQueueAudioPlayer)},
{"createUriAudioPlayer", "(Ljava/lang/String;)Z",
reinterpret_cast<void*>(CreateUriAudioPlayer)},
{"setPlayingUriAudioPlayer", "(Z)V",
reinterpret_cast<void*>(SetPlayingUriAudioPlayer)},
{"setLoopingUriAudioPlayer", "(Z)V",
reinterpret_cast<void*>(SetLoopingUriAudioPlayer)},
{"setChannelMuteUriAudioPlayer", "(IZ)V",
reinterpret_cast<void*>(SetChannelMuteUriAudioPlayer)},
{"setChannelSoloUriAudioPlayer", "(IZ)V",
reinterpret_cast<void*>(SetChannelSoloUriAudioPlayer)},
{"getNumChannelsUriAudioPlayer", "()I",
reinterpret_cast<void*>(GetNumChannelsUriAudioPlayer)},
{"setVolumeUriAudioPlayer", "(I)V",
reinterpret_cast<void*>(SetVolumeUriAudioPlayer)},
{"setMuteUriAudioPlayer", "(Z)V",
reinterpret_cast<void*>(SetMuteUriAudioPlayer)},
{"enableStereoPositionUriAudioPlayer", "(Z)V",
reinterpret_cast<void*>(EnableStereoPositionUriAudioPlayer)},
{"setStereoPositionUriAudioPlayer", "(I)V",
reinterpret_cast<void*>(SetStereoPositionUriAudioPlayer)},
{"enableReverb", "(Z)Z", reinterpret_cast<void*>(EnableReverb)},
{"selectClip", "(II)Z", reinterpret_cast<void*>(SelectClip)},
{"createAssetAudioPlayer",
"(Landroid/content/res/AssetManager;Ljava/lang/String;)Z",
reinterpret_cast<void*>(CreateAssetAudioPlayer)},
{"setPlayingAssetAudioPlayer", "(Z)V",
reinterpret_cast<void*>(SetPlayingAssetAudioPlayer)},
{"createAudioRecorder", "()Z",
reinterpret_cast<void*>(CreateAudioRecorder)},
{"startRecording", "()V", reinterpret_cast<void*>(StartRecording)},
{"shutdown", "()V", reinterpret_cast<void*>(Shutdown)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -19,4 +19,12 @@ android {
path 'src/main/cpp/CMakeLists.txt'
}
}
buildFeatures {
prefab true
}
}
dependencies {
implementation project(":base")
}

View File

@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.22.1)
project(NativeCodec LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(native-codec-jni SHARED
looper.cpp
@@ -9,6 +10,8 @@ add_app_library(native-codec-jni SHARED
)
target_link_libraries(native-codec-jni
PRIVATE
base::base
android
log
mediandk

View File

@@ -49,6 +49,7 @@
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/native_window_jni.h>
#include <base/macros.h>
typedef struct {
int fd;
@@ -196,10 +197,8 @@ void mylooper::handle(int what, void* obj) {
}
}
extern "C" {
jboolean Java_com_example_nativecodec_NativeCodec_createStreamingMediaPlayer(
JNIEnv* env, jclass, jobject assetMgr, jstring filename) {
jboolean CreateStreamingMediaPlayer(JNIEnv* env, jclass, jobject assetMgr,
jstring filename) {
LOGV("@@@ create");
// convert Java string to UTF-8
@@ -268,8 +267,7 @@ jboolean Java_com_example_nativecodec_NativeCodec_createStreamingMediaPlayer(
}
// set the playing state for the streaming media player
void Java_com_example_nativecodec_NativeCodec_setPlayingStreamingMediaPlayer(
JNIEnv*, jclass, jboolean isPlaying) {
void SetPlayingStreamingMediaPlayer(JNIEnv*, jclass, jboolean isPlaying) {
LOGV("@@@ playpause: %d", isPlaying);
if (mlooper) {
if (isPlaying) {
@@ -281,7 +279,7 @@ void Java_com_example_nativecodec_NativeCodec_setPlayingStreamingMediaPlayer(
}
// shut down the native media system
void Java_com_example_nativecodec_NativeCodec_shutdown(JNIEnv*, jclass) {
void Shutdown(JNIEnv*, jclass) {
LOGV("@@@ shutdown");
if (mlooper) {
mlooper->post(kMsgDecodeDone, &data, true /* flush */);
@@ -296,8 +294,7 @@ void Java_com_example_nativecodec_NativeCodec_shutdown(JNIEnv*, jclass) {
}
// set the surface
void Java_com_example_nativecodec_NativeCodec_setSurface(JNIEnv* env, jclass,
jobject surface) {
void SetSurface(JNIEnv* env, jclass, jobject surface) {
// obtain a native window from a Java surface
if (data.window) {
ANativeWindow_release(data.window);
@@ -308,11 +305,37 @@ void Java_com_example_nativecodec_NativeCodec_setSurface(JNIEnv* env, jclass,
}
// rewind the streaming media player
void Java_com_example_nativecodec_NativeCodec_rewindStreamingMediaPlayer(
JNIEnv*, jclass) {
void RewindStreamingMediaPlayer(JNIEnv*, jclass) {
LOGV("@@@ rewind");
if (mlooper) {
mlooper->post(kMsgSeek, &data);
}
}
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* _Nonnull vm,
void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/example/nativecodec/NativeCodec");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"createStreamingMediaPlayer",
"(Landroid/content/res/AssetManager;Ljava/lang/String;)Z",
reinterpret_cast<void*>(CreateStreamingMediaPlayer)},
{"setPlayingStreamingMediaPlayer", "(Z)V",
reinterpret_cast<void*>(SetPlayingStreamingMediaPlayer)},
{"shutdown", "()V", reinterpret_cast<void*>(Shutdown)},
{"setSurface", "(Landroid/view/Surface;)V",
reinterpret_cast<void*>(SetSurface)},
{"rewindStreamingMediaPlayer", "()V",
reinterpret_cast<void*>(RewindStreamingMediaPlayer)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -4,7 +4,7 @@ plugins {
android {
namespace 'com.example.nativemidi'
defaultConfig {
applicationId "com.example.nativemidi"
minSdkVersion 29
@@ -22,9 +22,14 @@ android {
path "src/main/cpp/CMakeLists.txt"
}
}
buildFeatures {
prefab true
}
}
dependencies {
implementation project(":base")
implementation libs.appcompat
implementation libs.androidx.constraintlayout
}

View File

@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.22.1)
project(native_midi LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(${PROJECT_NAME}
SHARED
@@ -9,4 +10,11 @@ add_app_library(${PROJECT_NAME}
MainActivity.cpp
)
target_link_libraries(${PROJECT_NAME} PRIVATE amidi OpenSLES android log)
target_link_libraries(${PROJECT_NAME}
PRIVATE
base::base
amidi
OpenSLES
android
log
)

View File

@@ -14,10 +14,9 @@
* limitations under the License.
*
*/
#include <base/macros.h>
#include <jni.h>
extern "C" {
// Data callback stuff
JavaVM* theJvm;
jobject dataCallbackObj;
@@ -27,8 +26,7 @@ jmethodID midDataCallback;
* Initializes JNI interface stuff, specifically the info needed to call back
* into the Java layer when MIDI data is received.
*/
JNICALL void Java_com_example_nativemidi_MainActivity_initNative(
JNIEnv* env, jobject instance) {
void InitNative(JNIEnv* env, jobject instance) {
env->GetJavaVM(&theJvm);
// Setup the receive data callback (into Java)
@@ -39,4 +37,21 @@ JNICALL void Java_com_example_nativemidi_MainActivity_initNative(
env->GetMethodID(clsMainActivity, "onNativeMessageReceive", "([B)V");
}
} // extern "C"
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* _Nonnull vm,
void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/example/nativemidi/MainActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"initNative", "()V", reinterpret_cast<void*>(InitNative)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -26,11 +26,13 @@ android {
}
buildFeatures {
prefab true
viewBinding true
}
}
dependencies {
implementation project(":base")
implementation libs.appcompat
implementation libs.material
implementation libs.androidx.constraintlayout

View File

@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.22.1)
project(OrderfileDemo CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
# We have setup build variables that you can just comment or uncomment to use.
# Make sure to have only one build variable uncommented at a time.
@@ -13,7 +14,7 @@ set(GENERATE_PROFILES ON)
#set(USE_PROFILE "${CMAKE_SOURCE_DIR}/demo.orderfile")
add_app_library(orderfiledemo SHARED orderfile.cpp)
target_link_libraries(orderfiledemo log)
target_link_libraries(orderfiledemo PRIVATE base::base log)
if(GENERATE_PROFILES)
# Generating profiles requires any optimization flag aside from -O0.

View File

@@ -1,4 +1,5 @@
#include <android/log.h>
#include <base/macros.h>
#include <errno.h>
#include <jni.h>
#include <linux/limits.h>
@@ -46,9 +47,26 @@ void DumpProfileDataIfNeeded(const char* temp_dir) {
#endif
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_orderfiledemo_MainActivity_runWorkload(JNIEnv* env,
jobject /* this */,
jstring temp_dir) {
void RunWorkload(JNIEnv* env, jobject /* this */, jstring temp_dir) {
DumpProfileDataIfNeeded(env->GetStringUTFChars(temp_dir, 0));
}
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* _Nonnull vm,
void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/example/orderfiledemo/MainActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"runWorkload", "(Ljava/lang/String;)V",
reinterpret_cast<void*>(RunWorkload)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -55,6 +55,10 @@ android {
"x86_64",
)
}
// Allows buildTypes which inherit from debug to match dependencies
// with the debug buildType.
matchingFallbacks = ["debug"]
}
release {
@@ -136,6 +140,7 @@ android {
}
buildFeatures {
prefab true
viewBinding true
}
@@ -147,6 +152,7 @@ android {
}
dependencies {
implementation project(":base")
implementation libs.appcompat
implementation libs.material
implementation libs.androidx.constraintlayout

View File

@@ -2,9 +2,10 @@ cmake_minimum_required(VERSION 3.22.1)
project(sanitizers LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(sanitizers SHARED native-lib.cpp)
target_link_libraries(sanitizers PRIVATE log)
target_link_libraries(sanitizers PRIVATE base::base log)
if(SANITIZE)
# For asan and ubsan, we need to copy some files from the NDK into our APK.

View File

@@ -1,10 +1,9 @@
#include <base/macros.h>
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_sanitizers_MainActivity_stringFromJNI(JNIEnv* env,
jobject /* this */) {
jstring StringFromJni(JNIEnv* env, jobject /* this */) {
// Use-after-free error, caught by asan and hwasan.
int* foo = new int;
*foo = 3;
@@ -18,3 +17,23 @@ Java_com_example_sanitizers_MainActivity_stringFromJNI(JNIEnv* env,
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* _Nonnull vm,
void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/example/sanitizers/MainActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"stringFromJNI", "()Ljava/lang/String;",
reinterpret_cast<void*>(StringFromJni)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -19,4 +19,12 @@ android {
path 'src/main/cpp/CMakeLists.txt'
}
}
buildFeatures {
prefab true
}
}
dependencies {
implementation project(":base")
}

View File

@@ -2,10 +2,13 @@ cmake_minimum_required(VERSION 3.22.1)
project(SensorGraph LANGUAGES CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
add_app_library(accelerometergraph SHARED sensorgraph.cpp)
target_link_libraries(accelerometergraph
PRIVATE
base::base
android
GLESv2
log

View File

@@ -41,6 +41,7 @@ const float SENSOR_FILTER_ALPHA = 0.1f;
* Workaround AsensorManager_getInstance() deprecation false alarm
* for Android-N and before, when compiling with NDK-r15
*/
#include <base/macros.h>
#include <dlfcn.h>
const char* kPackageName = "com.android.accelerometergraph";
ASensorManager* AcquireASensorManagerInstance(void) {
@@ -252,53 +253,48 @@ class sensorgraph {
sensorgraph gSensorGraph;
extern "C" {
JNIEXPORT void JNICALL
Java_com_android_accelerometergraph_AccelerometerGraphJNI_init(
JNIEnv* env, jclass type, jobject assetManager) {
(void)type;
void Init(JNIEnv* env, jclass, jobject assetManager) {
AAssetManager* nativeAssetManager = AAssetManager_fromJava(env, assetManager);
gSensorGraph.init(nativeAssetManager);
}
JNIEXPORT void JNICALL
Java_com_android_accelerometergraph_AccelerometerGraphJNI_surfaceCreated(
JNIEnv* env, jclass type) {
(void)env;
(void)type;
gSensorGraph.surfaceCreated();
}
void SurfaceCreated(JNIEnv*, jclass) { gSensorGraph.surfaceCreated(); }
JNIEXPORT void JNICALL
Java_com_android_accelerometergraph_AccelerometerGraphJNI_surfaceChanged(
JNIEnv* env, jclass type, jint width, jint height) {
(void)env;
(void)type;
void SurfaceChanged(JNIEnv*, jclass, jint width, jint height) {
gSensorGraph.surfaceChanged(width, height);
}
JNIEXPORT void JNICALL
Java_com_android_accelerometergraph_AccelerometerGraphJNI_drawFrame(
JNIEnv* env, jclass type) {
(void)env;
(void)type;
void DrawFrame(JNIEnv*, jclass) {
gSensorGraph.update();
gSensorGraph.render();
}
JNIEXPORT void JNICALL
Java_com_android_accelerometergraph_AccelerometerGraphJNI_pause(JNIEnv* env,
jclass type) {
(void)env;
(void)type;
gSensorGraph.pause();
}
void Pause(JNIEnv*, jclass) { gSensorGraph.pause(); }
JNIEXPORT void JNICALL
Java_com_android_accelerometergraph_AccelerometerGraphJNI_resume(JNIEnv* env,
jclass type) {
(void)env;
(void)type;
gSensorGraph.resume();
}
void Resume(JNIEnv*, jclass) { gSensorGraph.resume(); }
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* _Nonnull vm,
void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c =
env->FindClass("com/android/accelerometergraph/AccelerometerGraphJNI");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"init", "(Landroid/content/res/AssetManager;)V",
reinterpret_cast<void*>(Init)},
{"surfaceCreated", "()V", reinterpret_cast<void*>(SurfaceCreated)},
{"surfaceChanged", "(II)V", reinterpret_cast<void*>(SurfaceChanged)},
{"drawFrame", "()V", reinterpret_cast<void*>(DrawFrame)},
{"pause", "()V", reinterpret_cast<void*>(Pause)},
{"resume", "()V", reinterpret_cast<void*>(Resume)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -19,9 +19,14 @@ android {
path 'src/main/cpp/CMakeLists.txt'
}
}
buildFeatures {
prefab true
}
}
dependencies {
implementation project(":base")
implementation libs.appcompat
implementation libs.androidx.constraintlayout
}

View File

@@ -18,6 +18,7 @@ cmake_minimum_required(VERSION 3.22.1)
project(ChoreographerNativeActivity LANGUAGES C CXX)
include(AppLibrary)
find_package(base CONFIG REQUIRED)
# build the ndk-helper library
get_filename_component(commonDir ${CMAKE_CURRENT_SOURCE_DIR}/../../../../common ABSOLUTE)
@@ -40,6 +41,6 @@ set_target_properties(${PROJECT_NAME}
# add lib dependencies
target_link_libraries(${PROJECT_NAME}
PRIVATE
base::base
NdkHelper
)

View File

@@ -20,6 +20,7 @@
#include <EGL/egl.h>
#include <android/log.h>
#include <android_native_app_glue.h>
#include <base/macros.h>
#include <dlfcn.h>
#include <condition_variable>
@@ -303,9 +304,7 @@ void Engine::SynchInCallback(jlong frameTimeInNanos) {
}
};
extern "C" JNIEXPORT void JNICALL
Java_com_sample_choreographer_ChoreographerNativeActivity_choregrapherCallback(
JNIEnv*, jobject, jlong frameTimeInNanos) {
void ChoregrapherCallback(JNIEnv*, jobject, jlong frameTimeInNanos) {
g_engine.SynchInCallback(frameTimeInNanos);
}
@@ -611,4 +610,25 @@ void android_main(android_app* state) {
}
g_engine.TermDisplay();
}
}
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* _Nonnull vm,
void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c =
env->FindClass("com/sample/choreographer/ChoreographerNativeActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"choregrapherCallback", "(J)V",
reinterpret_cast<void*>(ChoregrapherCallback)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}

View File

@@ -47,6 +47,7 @@ android {
}
dependencies {
implementation project(":base")
implementation libs.appcompat
implementation libs.material
implementation libs.androidx.constraintlayout

View File

@@ -8,49 +8,25 @@ project("unittest")
include(AppLibrary)
find_package(base REQUIRED CONFIG)
find_package(googletest REQUIRED CONFIG)
find_package(junit-gtest REQUIRED CONFIG)
add_app_library(adder OBJECT adder.cpp)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_app_library( # Sets the name of the library.
add_app_library(
unittest
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
$<TARGET_OBJECTS:adder>
native-lib.cpp)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
native-lib.cpp
)
target_link_libraries( # Specifies the target library.
unittest
# Links the target library to the log library
# included in the NDK.
${log-lib})
PRIVATE
base::base
log
)
add_app_library(app_tests SHARED adder_test.cpp)
target_link_libraries(app_tests

View File

@@ -1,8 +1,25 @@
#include <base/macros.h>
#include <jni.h>
#include "adder.h"
extern "C" JNIEXPORT jint JNICALL
Java_com_example_unittest_MainActivity_add(JNIEnv*, jobject, jint a, jint b) {
return add((int)a, (int)b);
}
jint Add(JNIEnv*, jobject, jint a, jint b) { return add((int)a, (int)b); }
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* _Nonnull vm,
void* _Nullable) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass c = env->FindClass("com/example/unittest/MainActivity");
if (c == nullptr) return JNI_ERR;
static const JNINativeMethod methods[] = {
{"add", "(II)I", reinterpret_cast<void*>(Add)},
};
int rc = env->RegisterNatives(c, methods, arraysize(methods));
if (rc != JNI_OK) return rc;
return JNI_VERSION_1_6;
}