diff options
Diffstat (limited to 'examples/01.HelloWorld_Android/android_tools.cpp')
-rw-r--r-- | examples/01.HelloWorld_Android/android_tools.cpp | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/examples/01.HelloWorld_Android/android_tools.cpp b/examples/01.HelloWorld_Android/android_tools.cpp new file mode 100644 index 0000000..758a0a8 --- /dev/null +++ b/examples/01.HelloWorld_Android/android_tools.cpp @@ -0,0 +1,184 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "android_tools.h" +#include <android/log.h> // for the occasional debugging, style: __android_log_print(ANDROID_LOG_VERBOSE, "Irrlicht", "%s\n", "We do log"); + +namespace irr +{ +namespace android +{ + +// Not all DisplayMetrics are available through the NDK. +// So we access the Java classes with the JNI interface. +// You can access other Java classes available in Android in similar ways. +// Function based roughly on the code from here: http://stackoverflow.com/questions/13249164/android-using-jni-from-nativeactivity +bool getDisplayMetrics(android_app* app, SDisplayMetrics & metrics) +{ + if (!app || !app->activity || !app->activity->vm ) + return false; + + JNIEnv* jni = 0; + app->activity->vm->AttachCurrentThread(&jni, NULL); + if (!jni ) + return false; + + + // get all the classes we want to access from the JVM + jclass classNativeActivity = jni->FindClass("android/app/NativeActivity"); + jclass classWindowManager = jni->FindClass("android/view/WindowManager"); + jclass classDisplay = jni->FindClass("android/view/Display"); + jclass classDisplayMetrics = jni->FindClass("android/util/DisplayMetrics"); + + if (!classNativeActivity || !classWindowManager || !classDisplay || !classDisplayMetrics) + { + app->activity->vm->DetachCurrentThread(); + return false; + } + + + // Get all the methods we want to access from the JVM classes + // Note: You can get the signatures (third parameter of GetMethodID) for all + // functions of a class with the javap tool, like in the following example for class DisplayMetrics: + // javap -s -classpath myandroidpath/adt-bundle-linux-x86_64-20131030/sdk/platforms/android-10/android.jar android/util/DisplayMetrics + jmethodID idNativeActivity_getWindowManager = jni->GetMethodID( classNativeActivity + , "getWindowManager" + , "()Landroid/view/WindowManager;"); + jmethodID idWindowManager_getDefaultDisplay = jni->GetMethodID( classWindowManager + , "getDefaultDisplay" + , "()Landroid/view/Display;"); + jmethodID idDisplayMetrics_constructor = jni->GetMethodID( classDisplayMetrics + , "<init>" + , "()V"); + jmethodID idDisplay_getMetrics = jni->GetMethodID( classDisplay + , "getMetrics" + , "(Landroid/util/DisplayMetrics;)V"); + + if (!idNativeActivity_getWindowManager || !idWindowManager_getDefaultDisplay || !idDisplayMetrics_constructor + || !idDisplay_getMetrics) + { + app->activity->vm->DetachCurrentThread(); + return false; + } + + + // In Java the following code would be: getWindowManager().getDefaultDisplay().getMetrics(metrics); + // Note: If you need to call java functions in time-critical places you can split getting the jmethodID's + // and calling the functions into separate functions as you only have to get the jmethodID's once. + jobject windowManager = jni->CallObjectMethod(app->activity->clazz, idNativeActivity_getWindowManager); + + if (!windowManager) + { + app->activity->vm->DetachCurrentThread(); + return false; + } + jobject display = jni->CallObjectMethod(windowManager, idWindowManager_getDefaultDisplay); + if (!display) + { + app->activity->vm->DetachCurrentThread(); + return false; + } + jobject displayMetrics = jni->NewObject( classDisplayMetrics, idDisplayMetrics_constructor); + if (!displayMetrics) + { + app->activity->vm->DetachCurrentThread(); + return false; + } + jni->CallVoidMethod(display, idDisplay_getMetrics, displayMetrics); + + // access the fields of DisplayMetrics (we ignore the DENSITY constants) + jfieldID idDisplayMetrics_widthPixels = jni->GetFieldID( classDisplayMetrics, "widthPixels", "I"); + jfieldID idDisplayMetrics_heightPixels = jni->GetFieldID( classDisplayMetrics, "heightPixels", "I"); + jfieldID idDisplayMetrics_density = jni->GetFieldID( classDisplayMetrics, "density", "F"); + jfieldID idDisplayMetrics_densityDpi = jni->GetFieldID( classDisplayMetrics, "densityDpi", "I"); + jfieldID idDisplayMetrics_scaledDensity = jni->GetFieldID( classDisplayMetrics, "scaledDensity", "F"); + jfieldID idDisplayMetrics_xdpi = jni->GetFieldID(classDisplayMetrics, "xdpi", "F"); + jfieldID idDisplayMetrics_ydpi = jni->GetFieldID(classDisplayMetrics, "ydpi", "F"); + + if ( idDisplayMetrics_widthPixels ) + metrics.widthPixels = jni->GetIntField(displayMetrics, idDisplayMetrics_widthPixels); + if ( idDisplayMetrics_heightPixels ) + metrics.heightPixels = jni->GetIntField(displayMetrics, idDisplayMetrics_heightPixels); + if (idDisplayMetrics_density ) + metrics.density = jni->GetFloatField(displayMetrics, idDisplayMetrics_density); + if (idDisplayMetrics_densityDpi) + metrics.densityDpi = jni->GetIntField(displayMetrics, idDisplayMetrics_densityDpi); + if (idDisplayMetrics_scaledDensity) + metrics.scaledDensity = jni->GetFloatField(displayMetrics, idDisplayMetrics_scaledDensity); + if ( idDisplayMetrics_xdpi ) + metrics.xdpi = jni->GetFloatField(displayMetrics, idDisplayMetrics_xdpi); + if ( idDisplayMetrics_ydpi ) + metrics.ydpi = jni->GetFloatField(displayMetrics, idDisplayMetrics_ydpi); + + app->activity->vm->DetachCurrentThread(); + return true; +} + +void setSoftInputVisibility(android_app* app, bool visible) +{ + // NOTE: Unfortunately ANativeActivity_showSoftInput from the NDK does not work and Google does not care. + // This is based on the solution from @Ratamovic from here: http://stackoverflow.com/questions/5864790/how-to-show-the-soft-keyboard-on-native-activity + + if (!app || !app->activity || !app->activity->vm ) + return; + + JNIEnv* jni = 0; + app->activity->vm->AttachCurrentThread(&jni, NULL); + if (!jni ) + return; + + // get all the classes we want to access from the JVM (could be cached) + jclass classNativeActivity = jni->FindClass("android/app/NativeActivity"); + jclass classInputMethodManager = jni->FindClass("android/view/inputmethod/InputMethodManager"); + jclass classWindow = jni->FindClass("android/view/Window"); + jclass classView = jni->FindClass("android/view/View"); + + if (classNativeActivity && classInputMethodManager && classWindow) + { + // Get all the methods we want to access from the JVM classes (could be cached) + jmethodID mid_getSystemService = jni->GetMethodID(classNativeActivity, "getSystemService","(Ljava/lang/String;)Ljava/lang/Object;"); + jmethodID mid_showSoftInput = jni->GetMethodID(classInputMethodManager, "showSoftInput", "(Landroid/view/View;I)Z"); + + jmethodID mid_hideSoftInput = jni->GetMethodID(classInputMethodManager, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z"); + jmethodID mid_getWindow = jni->GetMethodID(classNativeActivity, "getWindow", "()Landroid/view/Window;"); + jmethodID mid_getWindowToken = jni->GetMethodID(classView, "getWindowToken", "()Landroid/os/IBinder;"); + jmethodID mid_getDecorView = jni->GetMethodID(classWindow, "getDecorView", "()Landroid/view/View;"); + + if ( mid_getSystemService && mid_showSoftInput && mid_hideSoftInput && mid_getWindow && mid_getDecorView && mid_getWindowToken ) + { + jstring paramInput = jni->NewStringUTF("input_method"); + jobject objInputMethodManager = jni->CallObjectMethod(app->activity->clazz, mid_getSystemService, paramInput); + jni->DeleteLocalRef(paramInput); + + jobject objWindow = jni->CallObjectMethod(app->activity->clazz, mid_getWindow); + + if ( visible && objInputMethodManager && objWindow) + { + jobject objDecorView = jni->CallObjectMethod(objWindow, mid_getDecorView); + if ( objDecorView ) + { + int showFlags = 0; + jni->CallBooleanMethod(objInputMethodManager, mid_showSoftInput, objDecorView, showFlags); + } + } + else if ( !visible && objInputMethodManager && objWindow ) + { + jobject objDecorView = jni->CallObjectMethod(objWindow, mid_getDecorView); + if ( objDecorView ) + { + jobject objBinder = jni->CallObjectMethod(objDecorView, mid_getWindowToken); + if ( objBinder ) + { + int hideFlags = 0; + jni->CallBooleanMethod(objInputMethodManager, mid_hideSoftInput, objBinder, hideFlags); + } + } + } + } + } + + app->activity->vm->DetachCurrentThread(); +} + +} // namespace android +} // namespace irr |