assets_and_ressources : global ref fixes
[nit.git] / lib / android / assets_and_resources.nit
1 # this file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014 Romain Chanoir <romain.chanoir@viacesi.fr>
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 # Android Assets and Resources Management
18 #
19 # Use the ResourceManager to retrieve resources from the `res` folder of your app
20 # Use the AssetManager to retrieve resources files from the `assets` folder of your app
21 # both are available from `App`
22 # If you write your own resources in your NIT project part of the application,
23 # you are obliged to set a string resource with the name "app_name" or it will be
24 # impossible for you to compile the apk correctly
25 module assets_and_resources
26
27 import native_app_glue
28 import java
29 import java::io
30
31 in "Java" `{
32 import android.content.res.AssetManager;
33 import android.content.res.AssetFileDescriptor;
34 import android.content.res.Resources;
35 import android.content.res.XmlResourceParser;
36 import java.io.IOException;
37 import android.graphics.Bitmap;
38 import android.graphics.BitmapFactory;
39 import android.graphics.drawable.Drawable;
40 import java.io.InputStream;
41 import android.util.Log;
42 import java.io.FileDescriptor;
43 `}
44
45 # AssetManager from Java, used by `AssetManager` to access resources in `assets` app's directory
46 # This is a low-level class, use `AssetManager` instead
47 extern class NativeAssetManager in "Java" `{ android.content.res.AssetManager `}
48 super JavaObject
49
50 fun close in "Java" `{ recv.close(); `}
51
52 fun get_locales: Array[JavaString] import Array[JavaString], Array[JavaString].add in "Java" `{
53 int arr = new_Array_of_JavaString();
54 for (String s : recv.getLocales()) {
55 Array_of_JavaString_add(arr, s);
56 }
57 return arr;
58 `}
59
60 fun list(path: JavaString): Array[JavaString] import Array[JavaString], Array[JavaString].add in "Java" `{
61 int arr = new_Array_of_JavaString();
62 try {
63 for (String s : recv.list(path)) {
64 Array_of_JavaString_add(arr, s);
65 }
66 }catch (IOException e) {
67 Log.e("Error retrieving the list of assets at 'path' ", e.getMessage());
68 e.printStackTrace();
69 }
70 return arr;
71 `}
72
73 fun open(file_name: JavaString): NativeInputStream in "Java" `{
74 InputStream stream = null;
75 try {
76 stream = recv.open(file_name);
77 }catch (IOException e) {
78 Log.e("Error while opening " + file_name, e.getMessage());
79 e.printStackTrace();
80 }
81 return stream;
82 `}
83
84 fun open_fd(file_name: JavaString): NativeAssetFileDescriptor in "Java" `{
85 AssetFileDescriptor afd = null;
86 try {
87 afd = recv.openFd(file_name);
88 }catch(IOException e){
89 Log.e("Error while opening " + file_name, e.getMessage());
90 e.printStackTrace();
91 }
92 return afd;
93 `}
94
95 fun open_non_asset_fd(file_name: JavaString): NativeAssetFileDescriptor in "Java" `{
96 AssetFileDescriptor afd = null;
97 try {
98 afd = recv.openNonAssetFd(file_name);
99 }catch(IOException e){
100 Log.e("Error while opening " + file_name, e.getMessage());
101 e.printStackTrace();
102 }
103 return afd;
104 `}
105
106 # HACK for bug #845
107 redef fun new_global_ref import sys, Sys.jni_env `{
108 Sys sys = NativeResources_sys(recv);
109 JNIEnv *env = Sys_jni_env(sys);
110 return (*env)->NewGlobalRef(env, recv);
111 `}
112 end
113
114 # Assets manager using a `NativeAssetManager` to manage android assets
115 class AssetManager
116 # Native asset manager
117 var native_assets_manager: NativeAssetManager
118
119 init(app: App) do self.native_assets_manager = app.assets.new_global_ref
120
121 # Close this asset manager
122 fun close do native_assets_manager.close
123
124 # Get the locales that this assets manager contains data for
125 fun locales: Array[String] do
126 var java_array = native_assets_manager.get_locales
127 var nit_array = new Array[String]
128 for s in java_array do
129 nit_array.add(s.to_s)
130 end
131 return nit_array
132 end
133
134 # Return a string array of all the assets at the given path
135 fun list(path: String): Array[String] do
136 sys.jni_env.push_local_frame(1)
137 var java_array = native_assets_manager.list(path.to_java_string)
138 var nit_array = new Array[String]
139 for s in java_array do
140 nit_array.add(s.to_s)
141 end
142 sys.jni_env.pop_local_frame
143 return nit_array
144 end
145
146 # Open an asset using ACCESS_STREAMING mode, returning a NativeInputStream
147 fun open(file_name: String): NativeInputStream do
148 sys.jni_env.push_local_frame(1)
149 var return_value = native_assets_manager.open(file_name.to_java_string)
150 sys.jni_env.pop_local_frame
151 return return_value
152 end
153
154 # Open an asset using it's name and returning a NativeAssetFileDescriptor
155 # `file_name` is
156 fun open_fd(file_name: String): NativeAssetFileDescriptor do
157 sys.jni_env.push_local_frame(1)
158 var return_value = native_assets_manager.open_fd(file_name.to_java_string).new_global_ref
159 sys.jni_env.pop_local_frame
160 return return_value
161 end
162
163 # Open a file that is not an asset returning a NativeAssetFileDescriptor
164 fun open_non_asset_fd(file_name: String): NativeAssetFileDescriptor do
165 var return_value = native_assets_manager.open_non_asset_fd(file_name.to_java_string)
166 return return_value
167 end
168
169 # Return a bitmap from the assets
170 fun bitmap(name: String): NativeBitmap do
171 sys.jni_env.push_local_frame(1)
172 var return_value = new NativeBitmap.from_stream(native_assets_manager.open(name.to_java_string)).new_global_ref
173 sys.jni_env.pop_local_frame
174 return return_value
175 end
176
177 # Deallocate the global reference allocated by AssetManager
178 fun destroy do self.native_assets_manager.delete_global_ref
179 end
180
181 # Resource manager for android resources placed in the `res` folder of your app
182 # This is a low-level class, use `ResourcesManager` instead
183 extern class NativeResources in "Java" `{ android.content.res.Resources `}
184 super JavaObject
185
186 fun get_assets:NativeAssetManager in "Java" `{ return recv.getAssets(); `}
187 fun get_color(id: Int): Int in "Java" `{ return recv.getColor((int)id); `}
188 fun get_boolean(id: Int): Bool in "Java" `{ return recv.getBoolean((int)id); `}
189 fun get_dimension(id: Int): Int in "Java" `{ return (int)recv.getDimension((int)id); `}
190 fun get_drawable(id: Int): NativeDrawable in "Java" `{ return recv.getDrawable((int)id); `}
191 fun get_identifier(name, def_type, def_package: JavaString): Int in "Java" `{ return recv.getIdentifier(name, def_type, def_package); `}
192 fun get_integer(id: Int): Int in "Java" `{ return recv.getInteger((int)id); `}
193 fun get_string(id: Int): JavaString in "Java" `{ return recv.getString((int)id); `}
194 fun get_resource_entry_name(resid: Int): JavaString in "Java" `{ return recv.getResourceEntryName((int)resid); `}
195 fun get_resource_name(resid: Int): JavaString in "Java" `{ return recv.getResourceName((int)resid); `}
196 fun get_resource_pakage_name(resid: Int): JavaString in "Java" `{ return recv.getResourcePackageName((int)resid); `}
197 fun get_resource_type_name(resid: Int): JavaString in "Java" `{ return recv.getResourceTypeName((int)resid); `}
198
199 # HACK for bug #845
200 redef fun new_global_ref import sys, Sys.jni_env `{
201 Sys sys = NativeResources_sys(recv);
202 JNIEnv *env = Sys_jni_env(sys);
203 return (*env)->NewGlobalRef(env, recv);
204 `}
205 end
206
207 # Resource manager for android resources placed in the `res` folder of your app
208 class ResourcesManager
209 # Native resources
210 var android_resources: NativeResources
211
212 # The name of the app_package
213 var app_package: String
214
215 init(res: NativeResources, app_package: String)
216 do
217 self.android_resources = res.new_global_ref
218 self.app_package = app_package
219 end
220
221 # Get a color from resources
222 fun color(name: String): Int do
223 sys.jni_env.push_local_frame(3)
224 var return_value = android_resources.get_color(android_resources.get_identifier(name.to_java_string, "color".to_java_string, app_package.to_java_string))
225 sys.jni_env.pop_local_frame
226 return return_value
227 end
228
229 # Get a `Bool` from resources
230 fun boolean(name: String): Bool do
231 sys.jni_env.push_local_frame(3)
232 var return_value = android_resources.get_boolean(android_resources.get_identifier(name.to_java_string, "bool".to_java_string, app_package.to_java_string))
233 sys.jni_env.pop_local_frame
234 return return_value
235 end
236
237 # Get a dimension from resources
238 # A dimension is specified with a number followed by a unit of measure
239 fun dimension(name: String): Int do
240 sys.jni_env.push_local_frame(3)
241 var return_value = android_resources.get_dimension(android_resources.get_identifier(name.to_java_string, "dimen".to_java_string, app_package.to_java_string))
242 sys.jni_env.pop_local_frame
243 return return_value
244 end
245
246 # Get an `Integer` from resources
247 fun integer(name: String): Int do
248 sys.jni_env.push_local_frame(3)
249 var return_value = android_resources.get_integer(android_resources.get_identifier(name.to_java_string, "integer".to_java_string, app_package.to_java_string))
250 sys.jni_env.pop_local_frame
251 return return_value
252 end
253
254
255 # Get a `String` from resources
256 fun string(name: String): String do
257 sys.jni_env.push_local_frame(3)
258 var return_value = android_resources.get_string(android_resources.get_identifier(name.to_java_string, "string".to_java_string, app_package.to_java_string)).to_s
259 sys.jni_env.pop_local_frame
260 return return_value
261 end
262
263 # Get a resource ID from one resource in `res/raw`folder
264 # you may use this to retrieve the id of a sound for example
265 fun raw_id(name: String): Int do
266 sys.jni_env.push_local_frame(3)
267 var return_value = android_resources.get_identifier(name.to_java_string, "raw".to_java_string, app_package.to_java_string)
268 sys.jni_env.pop_local_frame
269 return return_value
270 end
271
272 # Get a drawable from `res/drawable` folder
273 fun drawable(name: String): NativeDrawable do
274 sys.jni_env.push_local_frame(3)
275 var return_value = android_resources.get_drawable(android_resources.get_identifier(name.to_java_string, "drawable".to_java_string, app_package.to_java_string))
276 sys.jni_env.pop_local_frame
277 return return_value
278 end
279
280 # Get and ID from a specific resource in `res/res_type` folder
281 fun other_id(name, res_type: String): Int do
282 sys.jni_env.push_local_frame(3)
283 var return_value = android_resources.get_identifier(name.to_java_string, res_type.to_java_string, app_package.to_java_string)
284 sys.jni_env.pop_local_frame
285 return return_value
286 end
287
288 # Deallocate global reference allocated by ResourcesManager
289 fun destroy do self.android_resources.delete_global_ref
290 end
291
292 # An android Bitmap, get an instance using the AssetManager or the ResourceManager
293 extern class NativeBitmap in "Java" `{ android.graphics.Bitmap `}
294 super JavaObject
295
296 # Create a NativeBitmap from a NativeInputStream retrieved with `open` function of the AssetManager
297 # Called by the AssetManager
298 new from_stream(input_stream: NativeInputStream) in "Java" `{ return BitmapFactory.decodeStream(input_stream); `}
299
300 # Create a NativeBitmap using a resource ID and the NativeResources
301 # Called by the ResourceManager
302 new from_resources(res: NativeResources, id: Int) in "Java" `{ return BitmapFactory.decodeResource(res, (int)id); `}
303 fun width: Int in "Java" `{ return recv.getWidth(); `}
304 fun height: Int in "Java" `{ return recv.getHeight(); `}
305
306 # HACK for bug #845
307 redef fun new_global_ref import sys, Sys.jni_env `{
308 Sys sys = NativeResources_sys(recv);
309 JNIEnv *env = Sys_jni_env(sys);
310 return (*env)->NewGlobalRef(env, recv);
311 `}
312
313 end
314
315 # Android AssetFileDescriptor, can be retrieve by AssetManager and used to load a sound in a SoundPool
316 extern class NativeAssetFileDescriptor in "Java" `{ android.content.res.AssetFileDescriptor `}
317 super JavaObject
318
319 fun close in "Java" `{
320 try {
321 recv.close();
322 }catch(IOException e){
323 e.printStackTrace();
324 }
325 `}
326 fun create_input_stream: NativeFileInputStream in "Java" `{
327 try {
328 return recv.createInputStream();
329 }catch(IOException e){
330 Log.e("Error creating input_stream", e.getMessage());
331 e.printStackTrace();
332 return null;
333 }
334 `}
335 fun create_output_stream: NativeFileOutputStream in "Java" `{
336 try {
337 return recv.createOutputStream();
338 }catch(IOException e){
339 Log.e("Error creating output stream", e.getMessage());
340 e.printStackTrace();
341 return null;
342 }
343 `}
344 fun describe_contents: Int in "Java" `{ return (int)recv.describeContents(); `}
345 fun declared_length: Int in "Java" `{ return (int)recv.getDeclaredLength(); `}
346 # fun extras: Bundle in "Java" `{ return recv.getExtras(); `}
347
348 fun file_descriptor: NativeFileDescriptor in "Java" `{
349 FileDescriptor fd = recv.getFileDescriptor();
350 if (fd == null) {
351 Log.e("AssetFileDesciptorError", "Can't retrieve the FileDescriptor of this AssetFileDescriptor");
352 }
353 return fd;
354 `}
355
356 fun length: Int in "Java" `{ return (int)recv.getLength(); `}
357 fun start_offset: Int in "Java" `{ return (int)recv.getStartOffset(); `}
358 redef fun to_s: String import JavaString.to_s in "Java" `{ return JavaString_to_s(recv.toString()); `}
359
360 # HACK for bug #845
361 redef fun new_global_ref import sys, Sys.jni_env `{
362 Sys sys = NativeResources_sys(recv);
363 JNIEnv *env = Sys_jni_env(sys);
364 return (*env)->NewGlobalRef(env, recv);
365 `}
366 end
367
368 # Native class representing something drawable, can be retrieved from the resources
369 # will be used by the GUI
370 extern class NativeDrawable in "Java" `{ android.graphics.drawable.Drawable `}
371 end
372
373 redef class App
374 # Resource Manager used to manage resources placed in the `res` folder of the app
375 fun resource_manager: ResourcesManager is cached do return new ResourcesManager(self.resources, self.package_name.to_s)
376
377 # Assets Manager used to manage resources placed in the `assets` folder of the app
378 fun asset_manager: AssetManager is cached do return new AssetManager(self)
379
380 # Get the native AssetsManager of the application, used to initialize the nit's AssetManager
381 private fun assets: NativeAssetManager import native_activity in "Java" `{ return App_native_activity(recv).getAssets(); `}
382
383 # Get the package name of the application
384 private fun package_name: JavaString import native_activity in "Java" `{ return App_native_activity(recv).getPackageName(); `}
385
386 # Get the native ResourceManager of the application, used to initialize the nit's ResourceManager
387 private fun resources: NativeResources import native_activity in "Java" `{ return App_native_activity(recv).getResources(); `}
388 end