lib/android: fix manipulation of Java stack from assets_and_resources
[nit.git] / lib / android / assets_and_resources.nit
index ba304bd..baf4e4a 100644 (file)
@@ -24,7 +24,7 @@
 # impossible for you to compile the apk correctly
 module assets_and_resources
 
-import native_app_glue
+import dalvik
 import java
 import java::io
 
@@ -44,24 +44,26 @@ in "Java" `{
 
 # AssetManager from Java, used by `AssetManager` to access resources in `assets` app's directory
 # This is a low-level class, use `AssetManager` instead
-extern class NativeAssetManager in "Java" `{ android.content.res.AssetManager `}
+private extern class NativeAssetManager in "Java" `{ android.content.res.AssetManager `}
        super JavaObject
-       redef type SELF: NativeAssetManager
 
-       fun close in "Java" `{ recv.close(); `}
+       # Close this asset manager
+       fun close in "Java" `{ self.close(); `}
 
+       # Get the locales that this assets manager contains data for
        fun get_locales: Array[JavaString] import Array[JavaString], Array[JavaString].add in "Java" `{
                int arr = new_Array_of_JavaString();
-               for (String s : recv.getLocales()) {
+               for (String s : self.getLocales()) {
                        Array_of_JavaString_add(arr, s);
                }
                return arr;
        `}
 
+       # String Array of all the assets at the given path
        fun list(path: JavaString): Array[JavaString] import Array[JavaString], Array[JavaString].add  in "Java" `{
                int arr = new_Array_of_JavaString();
                try {
-                       for (String s : recv.list(path)) {
+                       for (String s : self.list(path)) {
                                Array_of_JavaString_add(arr, s);
                        }
                }catch (IOException e) {
@@ -71,46 +73,55 @@ extern class NativeAssetManager in "Java" `{ android.content.res.AssetManager `}
                return arr;
        `}
 
+       # Open an asset using ACCESS_STREAMING mode
        fun open(file_name: JavaString): NativeInputStream in "Java" `{
                InputStream stream = null;
                try {
-                       stream = recv.open(file_name);
+                       stream = self.open(file_name);
                }catch (IOException e) {
                        Log.e("Error while opening " + file_name, e.getMessage());
-                       e.printStackTrace();
+                       return null;
                }
                return stream;
        `}
 
+       # Open an asset and return it's file descriptor
        fun open_fd(file_name: JavaString): NativeAssetFileDescriptor in "Java" `{
                AssetFileDescriptor afd = null;
                try {
-                       afd = recv.openFd(file_name);
+                       afd = self.openFd(file_name);
                }catch(IOException e){
                        Log.e("Error while opening " + file_name, e.getMessage());
-                       e.printStackTrace();
+                       return null;
                }
                return afd;
        `}
 
+       # Open a ,non-asset and return it's file descriptor
        fun open_non_asset_fd(file_name: JavaString): NativeAssetFileDescriptor in "Java" `{
                AssetFileDescriptor afd = null;
                try {
-                       afd =  recv.openNonAssetFd(file_name);
+                       afd =  self.openNonAssetFd(file_name);
                }catch(IOException e){
                        Log.e("Error while opening " + file_name, e.getMessage());
-                       e.printStackTrace();
+                       return null;
                }
                return afd;
        `}
+
+       # HACK for bug #845
+       redef fun new_global_ref import sys, Sys.jni_env `{
+               Sys sys = NativeAssetManager_sys(self);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, self);
+       `}
 end
 
 # Assets manager using a `NativeAssetManager` to manage android assets
 class AssetManager
-       # Native asset manager
-       var native_assets_manager: NativeAssetManager
 
-       init(app: App) do self.native_assets_manager = app.assets.new_global_ref
+       # Native asset manager
+       private var native_assets_manager: NativeAssetManager = app.native_activity.assets.new_global_ref is lazy
 
        # Close this asset manager
        fun close do native_assets_manager.close
@@ -127,7 +138,7 @@ class AssetManager
 
        # Return a string array of all the assets at the given path
        fun list(path: String): Array[String] do
-               sys.jni_env.push_local_frame(1)
+               sys.jni_env.push_local_frame(8)
                var java_array = native_assets_manager.list(path.to_java_string)
                var nit_array = new Array[String]
                for s in java_array do
@@ -138,30 +149,32 @@ class AssetManager
        end
 
        # Open an asset using ACCESS_STREAMING mode, returning a NativeInputStream
-       fun open(file_name: String): NativeInputStream do
+       private fun open(file_name: String): NativeInputStream do
+               sys.jni_env.push_local_frame(2)
                var return_value =  native_assets_manager.open(file_name.to_java_string)
-               return return_value
+               return return_value.pop_from_local_frame
        end
 
        # Open an asset using it's name and returning a NativeAssetFileDescriptor
        # `file_name` is
-       fun open_fd(file_name: String): NativeAssetFileDescriptor do
-               var return_value = native_assets_manager.open_fd(file_name.to_java_string)
+       private fun open_fd(file_name: String): NativeAssetFileDescriptor do
+               sys.jni_env.push_local_frame(2)
+               var return_value = native_assets_manager.open_fd(file_name.to_java_string).new_global_ref
+               sys.jni_env.pop_local_frame
                return return_value
        end
 
        # Open a file that is not an asset returning a NativeAssetFileDescriptor
-       fun open_non_asset_fd(file_name: String): NativeAssetFileDescriptor do
+       private fun open_non_asset_fd(file_name: String): NativeAssetFileDescriptor do
                var return_value =  native_assets_manager.open_non_asset_fd(file_name.to_java_string)
                return return_value
        end
 
        # Return a bitmap from the assets
-       fun bitmap(name: String): NativeBitmap do
-               sys.jni_env.push_local_frame(1)
+       private fun bitmap(name: String): NativeBitmap do
+               sys.jni_env.push_local_frame 2
                var return_value = new NativeBitmap.from_stream(native_assets_manager.open(name.to_java_string))
-               sys.jni_env.pop_local_frame
-               return return_value
+               return return_value.pop_from_local_frame
        end
 
        # Deallocate the global reference allocated by AssetManager
@@ -170,36 +183,41 @@ end
 
 # Resource manager for android resources placed in the `res` folder of your app
 # This is a low-level class, use `ResourcesManager` instead
-extern class NativeResources in "Java" `{ android.content.res.Resources `}
+private extern class NativeResources in "Java" `{ android.content.res.Resources `}
        super JavaObject
-       redef type SELF: NativeResources
-
-       fun get_assets:NativeAssetManager in "Java" `{ return recv.getAssets(); `}
-       fun get_color(id: Int): Int in "Java" `{ return recv.getColor((int)id); `}
-       fun get_boolean(id: Int): Bool in "Java" `{ return recv.getBoolean((int)id); `}
-       fun get_dimension(id: Int): Int in "Java" `{ return (int)recv.getDimension((int)id); `}
-       fun get_drawable(id: Int): NativeDrawable in "Java" `{ return recv.getDrawable((int)id); `}
-       fun get_identifier(name, def_type, def_package: JavaString): Int in "Java" `{ return recv.getIdentifier(name, def_type, def_package); `}
-       fun get_integer(id: Int): Int in "Java" `{ return recv.getInteger((int)id); `}
-       fun get_string(id: Int): JavaString in "Java" `{ return recv.getString((int)id); `}
-       fun get_resource_entry_name(resid: Int): JavaString in "Java" `{ return recv.getResourceEntryName((int)resid); `}
-       fun get_resource_name(resid: Int): JavaString in "Java" `{ return recv.getResourceName((int)resid); `}
-       fun get_resource_pakage_name(resid: Int): JavaString in "Java" `{ return recv.getResourcePackageName((int)resid); `}
-       fun get_resource_type_name(resid: Int): JavaString in "Java" `{ return recv.getResourceTypeName((int)resid); `}
+
+       fun get_assets:NativeAssetManager in "Java" `{ return self.getAssets(); `}
+       fun get_color(id: Int): Int in "Java" `{ return self.getColor((int)id); `}
+       fun get_boolean(id: Int): Bool in "Java" `{ return self.getBoolean((int)id); `}
+       fun get_dimension(id: Int): Int in "Java" `{ return (int)self.getDimension((int)id); `}
+       fun get_drawable(id: Int): NativeDrawable in "Java" `{ return self.getDrawable((int)id); `}
+       fun get_identifier(name, def_type, def_package: JavaString): Int in "Java" `{ return self.getIdentifier(name, def_type, def_package); `}
+       fun get_integer(id: Int): Int in "Java" `{ return self.getInteger((int)id); `}
+       fun get_string(id: Int): JavaString in "Java" `{ return self.getString((int)id); `}
+       fun get_resource_entry_name(resid: Int): JavaString in "Java" `{ return self.getResourceEntryName((int)resid); `}
+       fun get_resource_name(resid: Int): JavaString in "Java" `{ return self.getResourceName((int)resid); `}
+       fun get_resource_pakage_name(resid: Int): JavaString in "Java" `{ return self.getResourcePackageName((int)resid); `}
+       fun get_resource_type_name(resid: Int): JavaString in "Java" `{ return self.getResourceTypeName((int)resid); `}
+
+       # HACK for bug #845
+       redef fun new_global_ref import sys, Sys.jni_env `{
+               Sys sys = NativeResources_sys(self);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, self);
+       `}
 end
 
 # Resource manager for android resources placed in the `res` folder of your app
 class ResourcesManager
        # Native resources
-       var android_resources: NativeResources
+       private var android_resources: NativeResources
 
        # The name of the app_package
-       var app_package: String
+       private var app_package: String
 
-       init(res: NativeResources, app_package: String)
+       private init native(res: NativeResources, app_package: String)
        do
-               self.android_resources = res.new_global_ref
-               self.app_package = app_package
+               init(res.new_global_ref, app_package)
        end
 
        # Get a color from resources
@@ -254,7 +272,7 @@ class ResourcesManager
        end
 
        # Get a drawable from `res/drawable` folder
-       fun drawable(name: String): NativeDrawable do
+       private fun drawable(name: String): NativeDrawable do
                sys.jni_env.push_local_frame(3)
                var return_value = android_resources.get_drawable(android_resources.get_identifier(name.to_java_string, "drawable".to_java_string, app_package.to_java_string))
                sys.jni_env.pop_local_frame
@@ -274,9 +292,8 @@ class ResourcesManager
 end
 
 # An android Bitmap, get an instance using the AssetManager or the ResourceManager
-extern class NativeBitmap in "Java" `{ android.graphics.Bitmap `}
+private extern class NativeBitmap in "Java" `{ android.graphics.Bitmap `}
        super JavaObject
-       redef type SELF: NativeBitmap
 
        # Create a NativeBitmap from a NativeInputStream retrieved with `open` function of the AssetManager
        # Called by the AssetManager
@@ -285,25 +302,57 @@ extern class NativeBitmap in "Java" `{ android.graphics.Bitmap `}
        # Create a NativeBitmap using a resource ID and the NativeResources
        # Called by the ResourceManager
        new from_resources(res: NativeResources, id: Int) in "Java" `{ return BitmapFactory.decodeResource(res, (int)id); `}
-       fun width: Int in "Java" `{ return recv.getWidth(); `}
-       fun height: Int in "Java" `{ return recv.getHeight(); `}
+
+       # Width in pixels
+       #
+       # Wraps Java: `int android.graphics.Bitmap.getWidth()`
+       fun width: Int in "Java" `{ return self.getWidth(); `}
+
+       # Height in pixels
+       #
+       # Wraps Java: `int android.graphics.Bitmap.getHeight()`
+       fun height: Int in "Java" `{ return self.getHeight(); `}
+
+       # Number of bytes per row
+       #
+       # Wraps Java: `int android.graphics.Bitmap.getRowBytes()`
+       fun row_bytes: Int in "Java" `{
+               return self.getRowBytes();
+       `}
+
+       # Does this bitmap has an alpha channel?
+       #
+       # Wraps Java: `boolean android.graphics.Bitmap.hasAlpha()`
+       fun has_alpha: Bool in "Java" `{
+               return self.hasAlpha();
+       `}
+
+       # HACK for bug #845
+       redef fun new_global_ref import sys, Sys.jni_env `{
+               Sys sys = NativeBitmap_sys(self);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, self);
+       `}
+
+       redef fun pop_from_local_frame_with_env(jni_env) `{
+               return (*jni_env)->PopLocalFrame(jni_env, self);
+       `}
 end
 
 # Android AssetFileDescriptor, can be retrieve by AssetManager and used to load a sound in a SoundPool
 extern class NativeAssetFileDescriptor in "Java" `{ android.content.res.AssetFileDescriptor `}
        super JavaObject
-       redef type SELF: NativeAssetFileDescriptor
 
        fun close in "Java" `{
                try {
-                       recv.close();
+                       self.close();
                }catch(IOException e){
                        e.printStackTrace();
                }
        `}
        fun create_input_stream: NativeFileInputStream in "Java" `{
                try {
-                       return recv.createInputStream();
+                       return self.createInputStream();
                }catch(IOException e){
                        Log.e("Error creating input_stream", e.getMessage());
                        e.printStackTrace();
@@ -312,48 +361,68 @@ extern class NativeAssetFileDescriptor in "Java" `{ android.content.res.AssetFil
        `}
        fun create_output_stream: NativeFileOutputStream in "Java" `{
                try {
-                       return recv.createOutputStream();
+                       return self.createOutputStream();
                }catch(IOException e){
                        Log.e("Error creating output stream", e.getMessage());
                        e.printStackTrace();
                        return null;
                }
        `}
-       fun describe_contents: Int in "Java" `{ return (int)recv.describeContents(); `}
-       fun declared_length: Int in "Java" `{ return (int)recv.getDeclaredLength(); `}
-       # fun extras: Bundle in "Java" `{ return recv.getExtras(); `}
+       fun describe_contents: Int in "Java" `{ return (int)self.describeContents(); `}
+       fun declared_length: Int in "Java" `{ return (int)self.getDeclaredLength(); `}
+       # fun extras: Bundle in "Java" `{ return self.getExtras(); `}
 
-       fun  file_descriptor: NativeFileDescriptor in "Java" `{
-               FileDescriptor fd =  recv.getFileDescriptor();
+       fun file_descriptor: NativeFileDescriptor in "Java" `{
+               FileDescriptor fd =  self.getFileDescriptor();
                if (fd == null) {
                        Log.e("AssetFileDesciptorError", "Can't retrieve the FileDescriptor of this AssetFileDescriptor");
                }
                return fd;
        `}
 
-       fun length: Int in "Java" `{ return (int)recv.getLength(); `}
-       fun start_offset: Int in "Java" `{ return (int)recv.getStartOffset(); `}
-       redef fun to_s: String import JavaString.to_s in "Java" `{ return JavaString_to_s(recv.toString()); `}
+       fun length: Int in "Java" `{ return (int)self.getLength(); `}
+       fun start_offset: Int in "Java" `{ return (int)self.getStartOffset(); `}
+       redef fun to_s import JavaString.to_s in "Java" `{ return JavaString_to_s(self.toString()); `}
+
+       # HACK for bug #845
+       redef fun new_global_ref import sys, Sys.jni_env `{
+               Sys sys = NativeAssetFileDescriptor_sys(self);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, self);
+       `}
 end
 
 # Native class representing something drawable, can be retrieved from the resources
 # will be used by the GUI
-extern class NativeDrawable in "Java" `{ android.graphics.drawable.Drawable `}
+private extern class NativeDrawable in "Java" `{ android.graphics.drawable.Drawable `}
 end
 
 redef class App
        # Resource Manager used to manage resources placed in the `res` folder of the app
-       fun resource_manager: ResourcesManager is cached do return new ResourcesManager(self.resources, self.package_name.to_s)
+       var resource_manager: ResourcesManager is lazy do
+               var res = native_activity.resources
+               var pkg = native_activity.package_name
+               return new ResourcesManager.native(res, pkg.to_s)
+       end
 
        # Assets Manager used to manage resources placed in the `assets` folder of the app
-       fun asset_manager: AssetManager is cached do return new AssetManager(self)
+       var asset_manager: AssetManager is lazy do return new AssetManager
+end
+
+redef extern class NativeActivity
 
        # Get the native AssetsManager of the application, used to initialize the nit's AssetManager
-       private fun assets: NativeAssetManager import native_activity in "Java" `{ return App_native_activity(recv).getAssets(); `}
+       private fun assets: NativeAssetManager in "Java" `{
+               return self.getAssets();
+       `}
 
        # Get the package name of the application
-       private fun package_name: JavaString import native_activity in "Java" `{ return App_native_activity(recv).getPackageName(); `}
+       private fun package_name: JavaString in "Java" `{
+               return self.getPackageName();
+       `}
 
        # Get the native ResourceManager of the application, used to initialize the nit's ResourceManager
-       private fun resources: NativeResources import native_activity in "Java" `{ return App_native_activity(recv).getResources(); `}
+       private fun resources: NativeResources in "Java" `{
+               return self.getResources();
+       `}
 end