lib/android: the dalvik module is higher in the importation hierarchy
[nit.git] / lib / android / dalvik.nit
1 # This file is part of NIT (http://www.nitlanguage.org).
2 #
3 # Copyright 2012-2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Java related services specific to Android and its Dalvik VM
18 module dalvik
19
20 import activities
21
22 redef class App
23 # The main Java Activity of this application
24 fun native_activity: NativeActivity is abstract
25 end
26
27 extern class JavaClassLoader in "Java" `{java.lang.ClassLoader`}
28 super JavaObject
29 end
30
31 redef class Sys
32 # We cannot create a JVM on Android
33 #
34 # This method is not reachable on this platform anyway.
35 # `Sys::jvm` is implemented by the main activity modules.
36 redef fun create_default_jvm do abort
37
38 redef fun jni_env do return jvm.attach_current_thread
39
40 private var class_loader: nullable JavaObject = null
41 private var class_loader_method: nullable JMethodID = null
42 redef fun load_jclass(name)
43 do
44 var class_loader = self.class_loader
45 if class_loader == null then
46 find_class_loader app.native_activity
47 class_loader = self.class_loader
48 assert class_loader != null
49 end
50
51 var class_loader_method = self.class_loader_method
52 assert class_loader_method != null
53
54 return load_jclass_intern(class_loader, class_loader_method, name)
55 end
56
57 private fun find_class_loader(native_activity: NativeActivity) import jni_env, class_loader=, JavaObject.as nullable, class_loader_method=, JMethodID.as nullable `{
58 JNIEnv *env = Sys_jni_env(recv);
59
60 // Retrieve main activity
61 jclass class_activity = (*env)->GetObjectClass(env, native_activity);
62 if (class_activity == NULL) {
63 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed retrieving activity class");
64 (*env)->ExceptionDescribe(env);
65 exit(1);
66 }
67
68 jmethodID class_activity_getClassLoader = (*env)->GetMethodID(env, class_activity, "getClassLoader", "()Ljava/lang/ClassLoader;");
69 if (class_activity_getClassLoader == NULL) {
70 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed retrieving 'getClassLoader' method");
71 (*env)->ExceptionDescribe(env);
72 exit(1);
73 }
74
75 // Call activity.getClassLoader
76 jobject instance_class_loader = (*env)->CallObjectMethod(env, native_activity, class_activity_getClassLoader);
77 if (instance_class_loader == NULL) {
78 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed retrieving class loader instance");
79 (*env)->ExceptionDescribe(env);
80 exit(1);
81 }
82
83 jclass class_class_loader = (*env)->GetObjectClass(env, instance_class_loader);
84 if (class_class_loader == NULL) {
85 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed retrieving class of class loader");
86 (*env)->ExceptionDescribe(env);
87 exit(1);
88 }
89
90 // Get the method ClassLoader.findClass
91 jmethodID class_class_loader_findClass = (*env)->GetMethodID(env, class_class_loader, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
92 if (class_class_loader_findClass == NULL) {
93 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed retrieving 'findClass' method");
94 (*env)->ExceptionDescribe(env);
95 exit(1);
96 }
97
98 // Return the values to Nit
99 Sys_class_loader__assign(recv, JavaObject_as_nullable((*env)->NewGlobalRef(env, instance_class_loader)));
100 Sys_class_loader_method__assign(recv, JMethodID_as_nullable(class_class_loader_findClass));
101
102 // Clean up
103 (*env)->DeleteLocalRef(env, class_activity);
104 (*env)->DeleteLocalRef(env, instance_class_loader);
105 (*env)->DeleteLocalRef(env, class_class_loader);
106 `}
107
108 private fun load_jclass_intern(instance_class_loader: JavaObject, class_loader_findClass: JMethodID, name: NativeString): JClass import jni_env `{
109 JNIEnv *env = Sys_jni_env(recv);
110 jobject class_name = (*env)->NewStringUTF(env, name);
111
112 jclass java_class = (*env)->CallObjectMethod(env, instance_class_loader, class_loader_findClass, class_name);
113 if (java_class == NULL) {
114 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed loading targeted class");
115 (*env)->ExceptionDescribe(env);
116 exit(1);
117 }
118
119 (*env)->DeleteLocalRef(env, class_name);
120
121 return java_class;
122 `}
123 end