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