TestActivity.
package edu.usc.nsl.carma;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import edu.usc.nsl.carma.nativecaller.NativeCaller;
public class TestActivity extends ActionBarActivity {
private NativeCaller nc;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
//final TextView textview = (TextView) findViewById(R.id.textview1);
nc = new NativeCaller();
final Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
nc.call1();
}
});
final Button button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
nc.call2();
}
});
final Button button3 = (Button) findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
nc.call3();
}
});
}
}
NativeCaller
package edu.usc.nsl.carma.nativecaller;
import android.util.Log;
/**
* The NDK seems fairly restrictive in terms of what java classes may make a call
* to the native functions since these functions must contain in their name,
* the name fo the java classes that are allowed to call them
*
* This Native Caller is a central interface to all of the native functions written
* for this application, as in all native function declarations contain "NativeCaller"
* in their name.
*/
public class NativeCaller {
private static final String DEBUG_TAG = "JAVA";
// Don't make these static
private native void helloLog(String logThis);
private native String getString(int value1, int value2);
private native String stringFromJNI();
// The name (ndk1) of the native library is defined in the makefile
static {
System.loadLibrary("ndk1");
}
public NativeCaller() {
super();
}
//c example accepting a string and making a call to the Android log util
public void call1() {
helloLog("This will log to LogCat via the native call.");
}
//c example doing some math and returning a string
public void call2() {
String result = getString(5,2);
Log.v(DEBUG_TAG, "Result: "+result);
result = getString(105, 1232);
Log.v(DEBUG_TAG, "Result2: "+result);
}
//c++ example returning a string
public void call3() {
Log.v(DEBUG_TAG, stringFromJNI());
}
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
# Discussion on compiling multiple source files:
# https://groups.google.com/forum/#!topic/android-ndk/R8q-5bFc3SA
LOCAL_MODULE := ndk1
LOCAL_SRC_FILES := native.c hello-jni.cpp
include $(BUILD_SHARED_LIBRARY)
hello-jni.cpp
#include <string.h>
#include <jni.h>
/**
* Taken from here:
* http://taylorpeer.com/hello-world-cpp-android-ndk/
*/
extern "C" {
/**
* c++ example returning a string
*
* JNIEXPORT jstring JNICALL would be a more explicit way of defining the return data type,
* though this appears to not be neccessary
*/
jstring Java_edu_usc_nsl_carma_nativecaller_NativeCaller_stringFromJNI (JNIEnv *env, jobject obj) {
return env->NewStringUTF("Hello from C++ over JNI!");
}
}
native.c
#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <android/log.h>
#define DEBUG_TAG "NDK"
/**
* Taken from here:
* http://code.tutsplus.com/tutorials/advanced-android-getting-started-with-the-ndk--mobile-2152
*/
/**
* Naming convention for functions writen for the NDK:
* T Java__package-name_class-name_method-name(){}
*/
//c example accepting a string and making a call to the Android log util
void Java_edu_usc_nsl_carma_nativecaller_NativeCaller_helloLog(JNIEnv * env,
jobject this, jstring logThis) {
jboolean isCopy;
const char * szLogThis = (*env)->GetStringUTFChars(env, logThis, &isCopy);
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:LC: [%s]",
szLogThis);
(*env)->ReleaseStringUTFChars(env, logThis, szLogThis);
}
//c example doing some math and returning a string
jstring Java_edu_usc_nsl_carma_nativecaller_NativeCaller_getString(
JNIEnv * env, jobject this, jint value1, jint value2) {
char *szFormat = "The sum of the two numbers is: %i";
char *szResult;
// add the two values
jlong sum = value1 + value2;
// malloc room for the resulting string
szResult = malloc(sizeof(szFormat) + 20);
// standard sprintf
sprintf(szResult, szFormat, sum);
// get an object string
jstring result = (*env)->NewStringUTF(env, szResult);
// cleanup
free(szResult);
return result;
}