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