]> git.lizzy.rs Git - irrlicht.git/blob - examples/01.HelloWorld_Android/android_tools.cpp
Fix bug introduced in last merge from svn trunk
[irrlicht.git] / examples / 01.HelloWorld_Android / android_tools.cpp
1 // This file is part of the "Irrlicht Engine".
2 // For conditions of distribution and use, see copyright notice in irrlicht.h
3
4 #include "android_tools.h"
5 #include <android/log.h>        // for the occasional debugging, style: __android_log_print(ANDROID_LOG_VERBOSE, "Irrlicht", "%s\n", "We do log");
6
7 namespace irr 
8 {
9 namespace android
10 {
11
12 // Not all DisplayMetrics are available through the NDK. 
13 // So we access the Java classes with the JNI interface.
14 // You can access other Java classes available in Android in similar ways.
15 // Function based roughly on the code from here: http://stackoverflow.com/questions/13249164/android-using-jni-from-nativeactivity
16 bool getDisplayMetrics(android_app* app, SDisplayMetrics & metrics)
17 {
18         if (!app || !app->activity || !app->activity->vm )
19                 return false;
20         
21         JNIEnv* jni = 0;
22         app->activity->vm->AttachCurrentThread(&jni, NULL);
23         if (!jni )
24                 return false;
25
26         
27         // get all the classes we want to access from the JVM
28         jclass classNativeActivity = jni->FindClass("android/app/NativeActivity");
29         jclass classWindowManager = jni->FindClass("android/view/WindowManager");
30         jclass classDisplay = jni->FindClass("android/view/Display");
31         jclass classDisplayMetrics = jni->FindClass("android/util/DisplayMetrics");
32         
33         if (!classNativeActivity || !classWindowManager || !classDisplay || !classDisplayMetrics)
34         {
35                 app->activity->vm->DetachCurrentThread();
36                 return false;
37         }
38         
39         
40         // Get all the methods we want to access from the JVM classes
41         // Note: You can get the signatures (third parameter of GetMethodID) for all 
42         // functions of a class with the javap tool, like in the following example for class DisplayMetrics:
43         // javap -s -classpath myandroidpath/adt-bundle-linux-x86_64-20131030/sdk/platforms/android-10/android.jar android/util/DisplayMetrics
44         jmethodID idNativeActivity_getWindowManager = jni->GetMethodID( classNativeActivity
45                                                                                                 , "getWindowManager"
46                                                                                                 , "()Landroid/view/WindowManager;"); 
47         jmethodID idWindowManager_getDefaultDisplay = jni->GetMethodID( classWindowManager
48                                                                                                 , "getDefaultDisplay"
49                                                                                                 , "()Landroid/view/Display;");
50         jmethodID idDisplayMetrics_constructor = jni->GetMethodID( classDisplayMetrics
51                                                                                                                 , "<init>"
52                                                                                                                 , "()V");
53         jmethodID idDisplay_getMetrics = jni->GetMethodID( classDisplay
54                                                                                  , "getMetrics"
55                                                                                  , "(Landroid/util/DisplayMetrics;)V");
56         
57         if (!idNativeActivity_getWindowManager || !idWindowManager_getDefaultDisplay || !idDisplayMetrics_constructor 
58                 || !idDisplay_getMetrics)
59         {
60                 app->activity->vm->DetachCurrentThread();
61                 return false;
62         }
63         
64
65         // In Java the following code would be: getWindowManager().getDefaultDisplay().getMetrics(metrics);
66         // Note: If you need to call java functions in time-critical places you can split getting the jmethodID's 
67         // and calling the functions into separate functions as you only have to get the jmethodID's once.
68         jobject windowManager = jni->CallObjectMethod(app->activity->clazz, idNativeActivity_getWindowManager);
69         
70         if (!windowManager)
71         {
72                 app->activity->vm->DetachCurrentThread();
73                 return false;
74         }
75         jobject display = jni->CallObjectMethod(windowManager, idWindowManager_getDefaultDisplay);
76         if (!display)
77         {
78                 app->activity->vm->DetachCurrentThread();
79                 return false;
80         }
81         jobject displayMetrics = jni->NewObject( classDisplayMetrics, idDisplayMetrics_constructor);
82         if (!displayMetrics)
83         {
84                 app->activity->vm->DetachCurrentThread();
85                 return false;
86         }
87         jni->CallVoidMethod(display, idDisplay_getMetrics, displayMetrics);
88         
89         // access the fields of DisplayMetrics (we ignore the DENSITY constants)
90         jfieldID idDisplayMetrics_widthPixels = jni->GetFieldID( classDisplayMetrics, "widthPixels", "I");
91         jfieldID idDisplayMetrics_heightPixels = jni->GetFieldID( classDisplayMetrics, "heightPixels", "I");
92         jfieldID idDisplayMetrics_density = jni->GetFieldID( classDisplayMetrics, "density", "F");
93         jfieldID idDisplayMetrics_densityDpi = jni->GetFieldID( classDisplayMetrics, "densityDpi", "I");
94         jfieldID idDisplayMetrics_scaledDensity = jni->GetFieldID( classDisplayMetrics, "scaledDensity", "F");
95         jfieldID idDisplayMetrics_xdpi = jni->GetFieldID(classDisplayMetrics, "xdpi", "F");
96         jfieldID idDisplayMetrics_ydpi = jni->GetFieldID(classDisplayMetrics, "ydpi", "F");
97         
98         if ( idDisplayMetrics_widthPixels )
99                 metrics.widthPixels = jni->GetIntField(displayMetrics, idDisplayMetrics_widthPixels);
100         if ( idDisplayMetrics_heightPixels )
101                 metrics.heightPixels = jni->GetIntField(displayMetrics, idDisplayMetrics_heightPixels);
102         if (idDisplayMetrics_density )
103                 metrics.density = jni->GetFloatField(displayMetrics, idDisplayMetrics_density);
104         if (idDisplayMetrics_densityDpi)
105                 metrics.densityDpi = jni->GetIntField(displayMetrics, idDisplayMetrics_densityDpi);
106         if (idDisplayMetrics_scaledDensity)
107                 metrics.scaledDensity = jni->GetFloatField(displayMetrics, idDisplayMetrics_scaledDensity);
108         if ( idDisplayMetrics_xdpi )
109                 metrics.xdpi = jni->GetFloatField(displayMetrics, idDisplayMetrics_xdpi);
110         if ( idDisplayMetrics_ydpi )
111                 metrics.ydpi = jni->GetFloatField(displayMetrics, idDisplayMetrics_ydpi);
112         
113         app->activity->vm->DetachCurrentThread();
114         return true;
115 }
116
117 void setSoftInputVisibility(android_app* app, bool visible)
118 {
119         // NOTE: Unfortunately ANativeActivity_showSoftInput from the NDK does not work and Google does not care.
120         // This is based on the solution from @Ratamovic from here: http://stackoverflow.com/questions/5864790/how-to-show-the-soft-keyboard-on-native-activity
121         
122         if (!app || !app->activity || !app->activity->vm )
123                 return;
124         
125         JNIEnv* jni = 0;
126         app->activity->vm->AttachCurrentThread(&jni, NULL);
127         if (!jni )
128                 return;
129         
130         // get all the classes we want to access from the JVM (could be cached)
131         jclass classNativeActivity = jni->FindClass("android/app/NativeActivity");
132         jclass classInputMethodManager = jni->FindClass("android/view/inputmethod/InputMethodManager");
133         jclass classWindow = jni->FindClass("android/view/Window");
134         jclass classView = jni->FindClass("android/view/View");
135         
136         if (classNativeActivity && classInputMethodManager && classWindow)
137         {
138                 // Get all the methods we want to access from the JVM classes (could be cached)
139                 jmethodID mid_getSystemService = jni->GetMethodID(classNativeActivity, "getSystemService","(Ljava/lang/String;)Ljava/lang/Object;");
140                 jmethodID mid_showSoftInput = jni->GetMethodID(classInputMethodManager, "showSoftInput", "(Landroid/view/View;I)Z");
141                 
142                 jmethodID mid_hideSoftInput = jni->GetMethodID(classInputMethodManager, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z");
143                 jmethodID mid_getWindow = jni->GetMethodID(classNativeActivity, "getWindow", "()Landroid/view/Window;");
144                 jmethodID mid_getWindowToken = jni->GetMethodID(classView, "getWindowToken", "()Landroid/os/IBinder;");
145                 jmethodID mid_getDecorView = jni->GetMethodID(classWindow, "getDecorView", "()Landroid/view/View;");
146
147                 if ( mid_getSystemService && mid_showSoftInput && mid_hideSoftInput && mid_getWindow && mid_getDecorView && mid_getWindowToken )
148                 {
149                         jstring paramInput = jni->NewStringUTF("input_method"); 
150                         jobject objInputMethodManager = jni->CallObjectMethod(app->activity->clazz, mid_getSystemService, paramInput); 
151                         jni->DeleteLocalRef(paramInput); 
152
153                         jobject objWindow = jni->CallObjectMethod(app->activity->clazz, mid_getWindow);
154                         
155                         if ( visible && objInputMethodManager && objWindow)
156                         {
157                                 jobject objDecorView = jni->CallObjectMethod(objWindow, mid_getDecorView);                              
158                                 if ( objDecorView )
159                                 {
160                                         int showFlags = 0;
161                                         jni->CallBooleanMethod(objInputMethodManager, mid_showSoftInput, objDecorView, showFlags);
162                                 }
163                         }
164                         else if ( !visible && objInputMethodManager && objWindow )
165                         {
166                                 jobject objDecorView = jni->CallObjectMethod(objWindow, mid_getDecorView);                              
167                                 if ( objDecorView )
168                                 {
169                                         jobject objBinder = jni->CallObjectMethod(objDecorView, mid_getWindowToken);                                                    
170                                         if ( objBinder )
171                                         {
172                                                 int hideFlags = 0;
173                                                 jni->CallBooleanMethod(objInputMethodManager, mid_hideSoftInput, objBinder, hideFlags);
174                                         }
175                                 }
176                         }
177                 }
178         }
179         
180         app->activity->vm->DetachCurrentThread();       
181 }
182
183 } // namespace android
184 } // namespace irr