Android: Using JNI from NativeActivity

Peter Jankuliak :

We are developing an OpenGL game on android using the NativeActivity class. So far everything went OK, but now we need to access some functionality that only seems to be available from Java.

There are more, but the first one we thought would be useful was accessing the display DPI. As described here the Java code looks like this:

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

And here is the unfortunate corresponding C++ code:

// My checking routine.
#define JNI_ASSERT(jni, cond) { \
  if (!(cond)) {\
    std::stringstream ss; \
    ss << __FILE__ << ":" << __LINE__; \
    throw std::runtime_error(ss.str()); \
  } \
  if (jni->ExceptionCheck()) { \
    std::stringstream ss; \
    ss << __FILE__ << ":" << __LINE__; \
    throw std::runtime_error("Exception: " + ss.str()); \
  } \
}

void print_dpi(android_app* app) {
  JNIEnv* jni;
  app->activity->vm->AttachCurrentThread(&jni, NULL);

  jclass activityClass = jni->FindClass("android/app/NativeActivity");
  JNI_ASSERT(jni, activityClass);

  jmethodID getWindowManager = jni->GetMethodID
                                    ( activityClass
                                    , "getWindowManager"
                                    , "()Landroid/view/WindowManager;"); 
  JNI_ASSERT(jni, getWindowManager);

  jobject wm = jni->CallObjectMethod(app->activity->clazz, getWindowManager);
  JNI_ASSERT(jni, wm);

  jclass windowManagerClass = jni->FindClass("android/view/WindowManager");
  JNI_ASSERT(jni, windowManagerClass);

  jmethodID getDefaultDisplay = jni->GetMethodID( windowManagerClass
                                                , "getDefaultDisplay"
                                                , "()Landroid/view/Display;");
  JNI_ASSERT(jni, getDefaultDisplay);

  jobject display = jni->CallObjectMethod(wm, getDefaultDisplay);
  JNI_ASSERT(jni, display);

  jclass displayClass = jni->FindClass("android/view/Display");
  JNI_ASSERT(jni, displayClass);

  // Check if everything is OK so far, it is, the values it prints
  // are sensible.
  { 
    jmethodID getWidth = jni->GetMethodID(displayClass, "getWidth", "()I");
    JNI_ASSERT(jni, getWidth);

    jmethodID getHeight = jni->GetMethodID(displayClass, "getHeight", "()I");
    JNI_ASSERT(jni, getHeight);

    int width = jni->CallIntMethod(display, getWidth);
    JNI_ASSERT(jni, true);
    log("Width: ", width); // Width: 320

    int height = jni->CallIntMethod(display, getHeight);
    JNI_ASSERT(jni, true);
    log("Height: ", height); // Height: 480
  }

  jclass displayMetricsClass = jni->FindClass("android/util/DisplayMetrics");
  JNI_ASSERT(jni, displayMetricsClass);

  jmethodID displayMetricsConstructor = jni->GetMethodID( displayMetricsClass
                                                        , "<init>", "()V");
  JNI_ASSERT(jni, displayMetricsConstructor);

  jobject displayMetrics = jni->NewObject( displayMetricsClass
                                         , displayMetricsConstructor);
  JNI_ASSERT(jni, displayMetrics);

  jmethodID getMetrics = jni->GetMethodID( displayClass
                                         , "getMetrics"
                                         , "(Landroid/util/DisplayMetrics;)V");
  JNI_ASSERT(jni, getMetrics);

  jni->CallVoidMethod(display, getMetrics, displayMetrics);
  JNI_ASSERT(jni, true);

  {
    jfieldID xdpi_id = jni->GetFieldID(displayMetricsClass, "xdpi", "F");
    JNI_ASSERT(jni, xdpi_id);

    float xdpi = jni->GetFloatField(displayMetricsClass, xdpi_id);
    JNI_ASSERT(jni, true);

    log("XDPI: ", xdpi); // XDPI: 0
  }

  {
    jfieldID height_id = jni->GetFieldID( displayMetricsClass
                                        , "heightPixels", "I");
    JNI_ASSERT(jni, height_id);

    int height = jni->GetIntField(displayMetricsClass, height_id);
    JNI_ASSERT(jni, true);

    log("Height: ", height); // Height: 0
  }
  // TODO: Delete objects here.
  app->activity->vm->DetachCurrentThread();
}

The code outputs:

Width: 320
Height: 480
XDPI: 0
Height: 0

It's as if the displayMetrics object did not get set in the call

jni->CallVoidMethod(display, getMetrics, displayMetrics);

Is it the case that JNI wouldn't allow me to use an argument as a return value? If so, how can we go around it given that we're using the NativeActivity glue.

Peter Jankuliak :

Ech, I've been staring at the code for couple of hours and didn't see it. Then left the desk, came back and there it was:

Instead of these two lines

float xdpi = jni->GetFloatField(displayMetricsClass, xdpi_id);
int height = jni->GetIntField(displayMetricsClass, height_id);

I should have used:

float xdpi = jni->GetFloatField(displayMetrics, xdpi_id);
int height = jni->GetIntField(displayMetrics, height_id);

Doh :)

(at least it can serve as an example if someone wants to get DPI the hard way :) )

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Remove a contentView from NativeActivity

From Java

Using GetDirectBufferAddress from JNI

From Dev

Android ffmpeg: create video from sequence of images using jni

From Dev

Unable to make JNI call from c++ to java in android lollipop using jni

From Dev

Showing an Android PopupWindow over a NativeActivity

From Dev

Android Java Access from JNI

From Dev

Android NDK NativeActivity Memory Management Needed?

From Dev

Android NativeActivity: AttachCurrentThread JNIInvokeInterface is not a structure or union

From Dev

Can we use Vuforia with NativeActivity on Android

From Dev

Use Kotlin/Native prebuilt shared library from an Android application using JNI

From Dev

How to pass a Data from native c binary to android model using JNI?

From Java

JNI error: while using android apksignertool

From Dev

undefined reference to 'multiply' using JNI in android

From Dev

Opencv passing Mat from Android to JNI error

From Java

Keeping java methods called from Android JNI

From Dev

android jni from static to non static methods

From Dev

Obscuring JNI Code From End Users in Android

From Dev

int returned from android jni is the wrong value

From Java

Passing a pointer from JNI to Java using a long

From Java

Using jvm.h from JNI

From Dev

Call fortran dll from java using JNI

From Dev

How to pass an object from the application which hosts the WorkflowApplication to a NativeActivity

From Java

Android JNI - Call function on Android UI thread from C++

From Dev

Using OpenCL with Android JNI produces slow code due to some overhead

From Dev

How to properly pass an asset FileDescriptor to FFmpeg using JNI in Android

From Dev

How to get app package name or applicationId using JNI android

From Dev

Store pre generated files on Android device and access them using JNI

From Dev

Call a function in java from C outside of a JNI function (Android)?

From Java

JNI on Android: How to retrieve a string from Java code?

Related Related

  1. 1

    Remove a contentView from NativeActivity

  2. 2

    Using GetDirectBufferAddress from JNI

  3. 3

    Android ffmpeg: create video from sequence of images using jni

  4. 4

    Unable to make JNI call from c++ to java in android lollipop using jni

  5. 5

    Showing an Android PopupWindow over a NativeActivity

  6. 6

    Android Java Access from JNI

  7. 7

    Android NDK NativeActivity Memory Management Needed?

  8. 8

    Android NativeActivity: AttachCurrentThread JNIInvokeInterface is not a structure or union

  9. 9

    Can we use Vuforia with NativeActivity on Android

  10. 10

    Use Kotlin/Native prebuilt shared library from an Android application using JNI

  11. 11

    How to pass a Data from native c binary to android model using JNI?

  12. 12

    JNI error: while using android apksignertool

  13. 13

    undefined reference to 'multiply' using JNI in android

  14. 14

    Opencv passing Mat from Android to JNI error

  15. 15

    Keeping java methods called from Android JNI

  16. 16

    android jni from static to non static methods

  17. 17

    Obscuring JNI Code From End Users in Android

  18. 18

    int returned from android jni is the wrong value

  19. 19

    Passing a pointer from JNI to Java using a long

  20. 20

    Using jvm.h from JNI

  21. 21

    Call fortran dll from java using JNI

  22. 22

    How to pass an object from the application which hosts the WorkflowApplication to a NativeActivity

  23. 23

    Android JNI - Call function on Android UI thread from C++

  24. 24

    Using OpenCL with Android JNI produces slow code due to some overhead

  25. 25

    How to properly pass an asset FileDescriptor to FFmpeg using JNI in Android

  26. 26

    How to get app package name or applicationId using JNI android

  27. 27

    Store pre generated files on Android device and access them using JNI

  28. 28

    Call a function in java from C outside of a JNI function (Android)?

  29. 29

    JNI on Android: How to retrieve a string from Java code?

HotTag

Archive