JNI questions: Java to C++ and C++ to Java strings problem

#2

to get a string from Java to C++; I do that;

in the ofApp.cpp:

std::string ofApp::getJavaString() {
    jmethodID midCallBack = ofGetJNIEnv()->GetMethodID(ofGetJavaOFAndroid(), "getStringToCppSide", "()Ljava/lang/String;"); //"getStringToCppSide" is the name of a Java function of ofAndroid.java
    jstring resultJNIStr = (jstring)ofGetJNIEnv()->CallObjectMethod(ofGetJavaOFAndroid(), midCallBack);
    const char *resultCStr = ofGetJNIEnv()->GetStringUTFChars(resultJNIStr, NULL);
    std::string resultStr(resultCStr);
    ofGetJNIEnv()->ReleaseStringUTFChars(resultJNIStr, resultCStr);
    return resultStr;
}

in the OFAndroid.java:

private String getStringToCppSide() {
    return requiredstring;
}

to send a string from C++ to Java, what i do is;

in the ofApp.cpp:

void ofApp::sendStringtoJava(std::string message) {
    jstring jStringParam = ofGetJNIEnv()->NewStringUTF(message.c_str());
    ofGetJNIEnv()->CallVoidMethod(ofGetOFActivityObject(), ofGetJNIEnv()->GetMethodID(ofGetJavaOFAndroid(), "setStringFromCppSide", "(Ljava/lang/String;)V"), jStringParam); //"setStringFromCppSide" is the name of a void of ofAndroid.java
    ofGetJNIEnv()->DeleteLocalRef(jStringParam);
}

in the OFAndroid.java:

private void setStringFromCppSide(String message) {
    //do whatever you do here with the string message coming from cpp side
}
#3

In the Java to C++ part then i call it like a normal function?
Such as:

string myString = getStringToCppSide();

Bacause in this way it give me a force close to the app, with one error only:

02-01 17:17:07.644: A/libc(31013): Fatal signal 11 (SIGSEGV) at 0x00000004 (code=1), thread 31049 (Thread-3981)

#4
std::string myString = getJavaString();
#5

It still doesn’t work… force close the app with a very long list of errors, the first (I think it is the most relevant) is:

02-02 12:22:21.008: A/art(30777): art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: JNI FindClass called with pending exception ‘java.lang.NoSuchMethodError’ thrown in void cc.openframeworks.OFAndroid.setup(int, int):-2

Thnk you so much for your help

#6

Did you add the getStringToCppSide() method inside OFAndroid.java?

I edited my first response. Does your implementation is like that?

#7

Yes, in ofApp.h

std::string getJavaString();

In ofApp.cpp

std::string ofApp::getJavaString() {
	jmethodID midCallBack = ofGetJNIEnv()->GetMethodID(ofGetJavaOFAndroid(),
			"getStringToCppSide", "()Ljava/lang/String;"); //"getStringToCppSide" is the name of a Java function of ofAndroid.java
	jstring resultJNIStr = (jstring) ofGetJNIEnv()->CallObjectMethod(
			ofGetJavaOFAndroid(), midCallBack);
	const char *resultCStr = ofGetJNIEnv()->GetStringUTFChars(resultJNIStr,
			NULL);
	std::string resultStr(resultCStr);
	ofGetJNIEnv()->ReleaseStringUTFChars(resultJNIStr, resultCStr);
	return resultStr;
}

void ofApp::setup() {
std::string myString = getJavaString();
}

in OFActivity.java

String myString;
int densityDpi;

@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		String packageName = getPackageName();

		ofApp = new OFAndroid(packageName, this);
		DisplayMetrics dm = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(dm);

		densityDpi = dm.densityDpi;

		myString = "this is a string";

		this.dpiJNI(densityDpi);
	}

public native void dpiJNI(int dpi);   // this to call an integer for display DPI

	private String getStringToCppSide() {
		return myString;
	}

I have the same problem sending C++ string to Java

#8

I copied and pasted your code and it is working here.

#9

Nothing to do, app crashes on Android 4.4 and Android 5, so I think the problem is related with my Eclipse on Windows… I will try on Eclipse on Ubuntu and I will let you know.

Thanks a lot for you help :smiley:

EDIT: I found this error in the LogCat, maybe this is the cause:

02-02 21:54:34.431: D/dalvikvm(25770): No JNI_OnLoad found in /data/app-lib/cc.openframeworks.androidAccelerometerExample-1/libneondetection.so 0x424913f8, skipping init

It seems that it can’t find a libreary in that folder… or I am totally wrong?

#10

Ooops sorry, I see now your problem.

You are writing Java code inside “OFActivity.java” but you need to write it inside “OFAndroid.java”

#11

Do you mean OF/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroid.java? It is the only one file named “OFAndroid.java”, and I wrote it in this way:

public class OFAndroid {

	String str= "myString";
private String getStringToCppSide() {
    		return str;
	}
    /* All other codes  of OFAndroid.java*/
    }

but it still doesn’t work

But… maybe if I teel you what I need, there is a better solution that I don’t know (my only problem is to pass strings between C++ and Java for now).

What I need is to get the string in openFrameworks part for Environment.GetExternalFolder(), because I need to save some images in a folder in “/DCIM/myFolder/image.jpg”. Then I need to pass the name of that file in the Media Scanner to make the image visible in gallery. Maybe there is a simpler way to do this.

Thank you very much!

#12

In the OFAndroid.java, instead of “str”, return this one and this should work:

private String getStringToCppSide() {
    return Environment.getExternalStorageDirectory().getAbsolutePath();
}
#14

Nothing to do, it doesn’t work. I tried in OFActivity.java in the srcJava folder, and OFAndroid.java in OF/addons/ofx/ofAndroidLib/src/cc/openframeworks/ folder (the only one folder containing this file)…

#15

Dear @kessondalef,

The code I shared you is a working code.
Please share your final implementation and I wil review it. And write please also the error message you get for this final code.

(For the implementation I shared you, use OF/addons/ofx/ofAndroidLib/src/cc/openframeworks/OFAndroid.java, not OFActivity.java)

#16

Yeah, sorry, you’re right.

This in the c++ part:

ofApp.h

#pragma once

#include "ofMain.h"
#include "ofxAndroid.h"

class ofApp : public ofxAndroidApp {
	
public:

	void setup();
	void update();
	void draw();
	void keyPressed(int key);
	void keyReleased(int key);
	void windowResized(int w, int h);

	void touchDown(int x, int y, int id);
	void touchMoved(int x, int y, int id);
	void touchUp(int x, int y, int id);
	void touchDoubleTap(int x, int y, int id);
	void touchCancelled(int x, int y, int id);
	void swipe(ofxAndroidSwipeDir swipeDir, int id);

	void pause();
	void stop();
	void resume();
	void reloadTextures();

	bool backPressed();
	void okPressed();
	void cancelPressed();
	
	bool isPhotoTaken;
	void sendStringtoJava(std::string message);

	ofVideoGrabber grabber;
};

ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup() {
	//Starting the camera
	grabber.initGrabber(1280, 720);
	
	// starting the variable
	isPhotoTaken = false;
}

//--------------------------------------------------------------
void ofApp::update() {
	// Update the camera
	grabber.update();
}

//--------------------------------------------------------------
void ofApp::draw() {
	ofBackground(0, 0, 0);
	
	// Visualize the camera
	grabber.draw(0, 0, ofGetWindowWidth(), ofGetWindowHeight());

	/*
	 * If isPhotoTaken, save a photo
	 * And send the name of the photo to the Java part
	 * then isPhotoTaken is false 
	 */
	
	if (isPhotoTaken) {
		ofImage myImage;
		myImage.grabScreen(0, 0, ofGetWindowHeight() / 0.75,
				ofGetWindowHeight());
		string photoName = "/sdcard/DCIM/myFolder/myPhoto"
				+ ofToString(ofGetYear()) + ofToString(ofGetMonth())
				+ ofToString(ofGetDay()) + ofToString(ofGetHours())
				+ ofToString(ofGetMinutes()) + ofToString(ofGetSeconds())
				+ ".jpg";
		myImage.saveImage(photoName);
		sendStringtoJava(photoName);
		isPhotoTaken = false;
	}
}

//--------------------------------------------------------------
void ofApp::touchDown(int x, int y, int id) {
	// Take the photo
	isPhotoTaken = true;
}

Ih the OF/addons/ofx/ofAndroidLib/src/cc/openframeworks/OFAndroid.java

package cc.openframeworks;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class OFAndroid {
	
	

String myString;
	
	

private void setStringFromCppSide(String message) {
	    myString = message;
	}
	
// All the code of OFAndroid.java
}

And this is the LogCat: http://pastebin.com/kCs1EKBC
(it is too long to paste here)

I am using openFrameworks 0.8.4 with Eclipse on Windows 8.1, with NDK r10b (r10d didn’t worked for me).

All I want is to take a photo, applying some filters and save it to the gallery.
For now I am stuck to the save process, because my photo doesn’t appear in the gallery (it saves it in /DCIM/myFolder/), so I need to call MediaScannerConnection in the Java part, and pass it the name of the file to add it in Media Library. I have the same problems if I try to pass Java Strings in the c++ part with your code.

Thank you very much for your help

(I can’t upload the source code directly here, because I have a bad internet connection… later I will upload directly the source code)

#17

This error means your JNI is working but there is a problem in the definition of setStringFromCppSide method (static or instance?). It is too late here, tomorrow morning I will try to reproduce it here.

#18

Hey @kessondalef,

We are going to release a big update of our game, why I am very busy here. Sorry I can’t reply quickly. Another problem, all the code I share you is working and I can’t reproduce your issue here.

As you have some definition problems, I change the code to the static version. You can find it below. I tested this code and it is completely working. Please do not change something, do not add some myString,etc… variables in the Java side before testing and seeing this code working. Try exactly this code.

OF/addons/ofx/ofAndroidLib/src/cc/openframeworks/OFAndroid.java:

static public boolean getStringToCppSide() {
    return "String from Java side!";
}

ofApp.h:

std::string getJavaString();

ofApp.cpp:

void ofApp::setup() {
    //add this line to the end of setup:
    ofLogNotice("ofApp.cpp") << "Received string:" << getJavaString();
}


std::string ofApp::getJavaString() {
    jmethodID midCallBackStatic = ofGetJNIEnv()->GetStaticMethodID(ofGetJavaOFAndroid(), "getStringToCppSide", "()Ljava/lang/String;");
    jstring resultJNIStr = (jstring)ofGetJNIEnv()->CallStaticObjectMethod(ofGetJavaOFAndroid(), midCallBackStatic);
    const char *resultCStr = ofGetJNIEnv()->GetStringUTFChars(resultJNIStr, NULL);
    std::string resultStr(resultCStr);
    ofGetJNIEnv()->ReleaseStringUTFChars(resultJNIStr, resultCStr);
    return resultStr;
}

Add this code and please check logcat for the “Received String:String from Java side!” notice.

Getting data from OFActvity and viceversa
#19

It’s ok, you are giving me a great help and I really appreciate it :smiley:

However, this code still doesn’t work. This is my code:

ofApp.h

#pragma once

#include "ofMain.h"
#include "ofxAndroid.h"

class ofApp : public ofxAndroidApp {
	
public:

	void setup();
	void update();
	void draw();
	void keyPressed(int key);
	void keyReleased(int key);
	void windowResized(int w, int h);

	void touchDown(int x, int y, int id);
	void touchMoved(int x, int y, int id);
	void touchUp(int x, int y, int id);
	void touchDoubleTap(int x, int y, int id);
	void touchCancelled(int x, int y, int id);
	void swipe(ofxAndroidSwipeDir swipeDir, int id);

	void pause();
	void stop();
	void resume();
	void reloadTextures();

	bool backPressed();
	void okPressed();
	void cancelPressed();
	
	std::string getJavaString();
};

ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup() {
	//add this line to the end of setup:
	ofLogNotice("ofApp.cpp") << "Received string:" << getJavaString();
}

//--------------------------------------------------------------
void ofApp::update() {
}

//--------------------------------------------------------------
void ofApp::draw() {
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key) {

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key) {

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h) {

}

//--------------------------------------------------------------
void ofApp::touchDown(int x, int y, int id) {
}

//--------------------------------------------------------------
void ofApp::touchMoved(int x, int y, int id) {
}

//--------------------------------------------------------------
void ofApp::touchUp(int x, int y, int id) {
}

//--------------------------------------------------------------
void ofApp::touchDoubleTap(int x, int y, int id) {

}

//--------------------------------------------------------------
void ofApp::touchCancelled(int x, int y, int id) {

}

//--------------------------------------------------------------
void ofApp::swipe(ofxAndroidSwipeDir swipeDir, int id) {

}

//--------------------------------------------------------------
void ofApp::pause() {

}

//--------------------------------------------------------------
void ofApp::stop() {

}

//--------------------------------------------------------------
void ofApp::resume() {

}

//--------------------------------------------------------------
void ofApp::reloadTextures() {

}

//--------------------------------------------------------------
bool ofApp::backPressed() {
	return false;
}

//--------------------------------------------------------------
void ofApp::okPressed() {

}

//--------------------------------------------------------------
void ofApp::cancelPressed() {

}

std::string ofApp::getJavaString() {
    jmethodID midCallBackStatic = ofGetJNIEnv()->GetStaticMethodID(ofGetJavaOFAndroid(), "getStringToCppSide", "()Ljava/lang/String;");
    jstring resultJNIStr = (jstring)ofGetJNIEnv()->CallStaticObjectMethod(ofGetJavaOFAndroid(), midCallBackStatic);
    const char *resultCStr = ofGetJNIEnv()->GetStringUTFChars(resultJNIStr, NULL);
    std::string resultStr(resultCStr);
    ofGetJNIEnv()->ReleaseStringUTFChars(resultJNIStr, resultCStr);
    return resultStr;
}

and OF/addons/ofx/ofAndroidLib/src/cc/openframeworks/OFAndroid.java:

package cc.openframeworks;

** All import statements **

public class OFAndroid {
	
	static public String getStringToCppSide() {
	    return "String from Java side!";
	}
	// All the rest of the code
}

But I’m still getting all that errors… http://pastebin.com/T9xR6xvK

Maybe I am wrong, but I think that it is a problem related to my configuration of Eclipse/openFrameworks on Windows… and in the console, I have a problem related to OFAndroid.java:

Description Resource Path Location Type
Syntax error on token(s), misplaced construct(s) OFAndroid.java /ofAndroidLib/src/cc/openframeworks line 1157 Java Problem

In the meanwhile, I will try on Linux to see if it is a problem of my configuration. Thank you very much for your help, and good luch with the update

EDIT: I just noticed that my OFAndroid.java is in OF/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroid.java, not in OF/addons/ofx/ofAndroidLib/src/cc/openframeworks/OFAndroid.java if it can help

#20

Well, I tried intance and static versions of the same code. Both codes are working here. I have no idea why you can not make them working. Maybe os difference, maybe threading issues… I don’t know.

What I can suggest you for now… Are the OFAndroid methods (like ofxAndroidIsOnline(), ofxAndroidIsWifiOnline(), ofxAndroidGetStringRes(string id), etc…) working? If yes, check ofxAndroidUtils.cpp. All of these methods are defined in this class and all of them call JNI methods. If they work for you, you can implement something your own with taking them as examples.

Good luck :smile:

#21

OK, after a few attempts I found the problem (I think): when I open Eclipse it give me an error related to Cygwin:

[2015-02-16 17:15:29 - Unable to launch cygpath. Is Cygwin on the path?] java.io.IOException: Cannot run program “cygpath”: CreateProcess error=2, The system cannot find the file specified

1 Like
#22

Hi! I was dealing with the same problem for the last two hours since I realized that ofAndroidLib needs to be Re-Builded in order to update the OFAndroid getStringToCppSide() method. After re-build everything worked well.