b1dae815075cf1886ae1e226d08e03e18d4195f7
[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 # Main Java Activity of this application
24 #
25 # Require: A Nit activity is currently running.
26 fun native_activity: NativeActivity is abstract
27
28 # Current reference context, either an activity or a service
29 fun native_context: NativeContext do return native_activity
30 end
31
32 redef class Sys
33
34 # We cannot create a JVM on Android
35 #
36 # This method is not reachable on this platform anyway.
37 # `Sys::jvm` is implemented by the main activity modules.
38 redef fun create_default_jvm do abort
39
40 redef fun jni_env do return jvm.attach_current_thread
41
42 private var class_loader: nullable JavaObject = null
43
44 private var class_loader_method: nullable JMethodID = null
45
46 redef fun load_jclass(name)
47 do
48 var class_loader = self.class_loader
49 if class_loader == null then
50 find_class_loader app.native_context
51 class_loader = self.class_loader
52 assert class_loader != null
53 end
54
55 var class_loader_method = self.class_loader_method
56 assert class_loader_method != null
57
58 return load_jclass_intern(class_loader, class_loader_method, name)
59 end
60
61 private fun find_class_loader(native_context: NativeContext) import jni_env, class_loader=, JavaObject.as nullable, class_loader_method=, JMethodID.as nullable `{
62 JNIEnv *env = Sys_jni_env(self);
63
64 // Retrieve main activity
65 jclass class_context = (*env)->GetObjectClass(env, native_context);
66 if (class_context == NULL) {
67 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed to retrieve activity class");
68 (*env)->ExceptionDescribe(env);
69 exit(1);
70 }
71
72 jmethodID class_activity_getClassLoader = (*env)->GetMethodID(env, class_context, "getClassLoader", "()Ljava/lang/ClassLoader;");
73 if (class_activity_getClassLoader == NULL) {
74 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed to retrieve 'getClassLoader' method");
75 (*env)->ExceptionDescribe(env);
76 exit(1);
77 }
78
79 // Call activity.getClassLoader
80 jobject instance_class_loader = (*env)->CallObjectMethod(env, native_context, class_activity_getClassLoader);
81 if (instance_class_loader == NULL) {
82 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed to retrieve class loader instance");
83 (*env)->ExceptionDescribe(env);
84 exit(1);
85 }
86
87 jclass class_class_loader = (*env)->GetObjectClass(env, instance_class_loader);
88 if (class_class_loader == NULL) {
89 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed to retrieve class of class loader");
90 (*env)->ExceptionDescribe(env);
91 exit(1);
92 }
93
94 // Get the method ClassLoader.findClass
95 jmethodID class_class_loader_findClass = (*env)->GetMethodID(env, class_class_loader, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
96 if (class_class_loader_findClass == NULL) {
97 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed to retrieve 'findClass' method");
98 (*env)->ExceptionDescribe(env);
99 exit(1);
100 }
101
102 // Return the values to Nit
103 Sys_class_loader__assign(self, JavaObject_as_nullable((*env)->NewGlobalRef(env, instance_class_loader)));
104 Sys_class_loader_method__assign(self, JMethodID_as_nullable(class_class_loader_findClass));
105
106 // Clean up
107 (*env)->DeleteLocalRef(env, class_context);
108 (*env)->DeleteLocalRef(env, instance_class_loader);
109 (*env)->DeleteLocalRef(env, class_class_loader);
110 `}
111
112 private fun load_jclass_intern(instance_class_loader: JavaObject, class_loader_findClass: JMethodID, name: NativeString): JClass import jni_env `{
113 JNIEnv *env = Sys_jni_env(self);
114 jobject class_name = (*env)->NewStringUTF(env, name);
115
116 jclass java_class = (*env)->CallObjectMethod(env, instance_class_loader, class_loader_findClass, class_name);
117 if (java_class == NULL) {
118 __android_log_print(ANDROID_LOG_ERROR, "Nit", "Failed loading targeted class");
119 (*env)->ExceptionDescribe(env);
120 exit(1);
121 }
122
123 (*env)->DeleteLocalRef(env, class_name);
124
125 return java_class;
126 `}
127 end