Call uno method of instance in different file

Hi,

Using CameraPanel example combined with https://www.fusetools.com/community/forums/howto_discussions/render_dynamically_an_image_from_java_bitmap.
The later is meant to render a bitmap, which will be passed from a uno file in the CameraPanel project:

The uno file in CameraPanel tries to call UpdateBitmap in JavaBitmap.uno:

using Uno;
using Uno.Permissions;
using Uno.Graphics;
using Uno.Threading;
using Uno.Compiler.ExportTargetInterop;
using OpenGL;
using Android.android.app;

[TargetSpecificImplementationAttribute]
public extern(Android) class Camera
{
...
  [Foreign(Language.Java)]
  void CaptureAndProcess()
  @{
   ... capture frame, process it, put into newBitmap
   ==> call to JavaBitmap (not working):
   final Preview.JavaBitmap javaBitmap = (Preview.JavaBitmap)@{JavaBitmap:Of(_this).Handle:Get()};
   
   javaBitmap.UpdateBitmap(newBitmap); 
  @}
...

JavaBitmap.uno:

using Uno;
using Uno.Compiler.ExportTargetInterop;
using Uno.Graphics;
using Fuse.Resources;

[ForeignInclude(Language.Java, "android.graphics.*")]
public class JavaBitmap
{
    public JavaBitmap()
    {
        //Preview.PreviewPage.textureImageSource.Texture = CreateANiceTexture();
    }

    public UpdateBitmap(Java.Object bitmap)
    {
        Preview.PreviewPage.textureImageSource.Texture = CreateANiceTexture(bitmap);
    }

    public texture2D CreateANiceTexture(Java.Object bitmap)
    {
        if defined(Android)
            return CreateTextureFromJavaBitmap(bitmap);
        throw new Exception("no");
    }
...

CameraPanel files are in /Preview/Camera.
JavaBitmap is in /Preview.

Each one of them feeds the content of Panels.
(JavaBitmap.uno is linked to:

<Panel>
   <TextureImageSource ux:Global="textureImageSource"/>
   <JavaBitmap ux:Global="javaBitmap"/>
   <Image Source="textureImageSource" />
</Panel>

They work well separately, the question is how to call UpdateBitmap(bitmap) from the other uno file.

First of all, UpdateBitmap() is missing its return type (assuming void).

Secondly, it looks like you are trying to call the Uno method from Java, is this what you intend?

Thanks for the reply Anders; yes (the return type is indeed missing, found that after the post) and the uno method should be called at the end of the Java method

the Preview.JavaBitmap that you are using in the java foreign block, is that a Java or Uno type?

Uno types cannot be used directly in a foreign block, you need to use macros to do that.

My suggestion is to just pass in a callback instead:

[Foreign(Language.Java)]
void CaptureAndProcess(Action<Java.Object> updateBitmap)
@{
	...
	updateBitmap.run(bitmap);
@}

Then you dont need to deal with macros at all :slight_smile:

Hi Vegard and thanks for the answer!

Ok so I pass an Action and call the corresponding method from javaBitmap.uno inside the foreign code. Still, I’m struggling to link the Action<Java.Object> with the JavaBitmap.uno instance:

In UX:

<Panel >
	<TextureImageSource ux:Global="textureImageSource" />
	<JavaBitmap ux:Global="javaBitmap"/> => Defined in JavaBitmap.uno
	<Image Source="textureImageSource" />
</Panel>

<CameraStream>
	<CameraVisual Camera="cam" Facing="Front" >
		<Clicked >
			<Callback Handler="{singleTap}" /> => This end up calling (via JS then uno) CaptureAndProcess method, which needs to call a JavaBitmap.uno method
		</Clicked>
	</CameraVisual>
	<Camera ux:Global="cam" />
	 <CameraExtended ux:Global="CameraExtended" Camera="cam" />
</CameraStream>

In the code above, I see that Camera=“cam” is passed as UX parameter to several objects, which are defined in UNO. Do you thing I could do the same with the JavaBitmap object? passing it to the Camera classes so I can call JavaBitmap from CaptureAndProcess method?

FYI, JavaBitmap.uno has a globalModule tag:

[UXGlobalModule]
public class JavaBitmap : NativeModule
{
    static readonly JavaBitmap _instance;

    public JavaBitmap()
    {
        if(_instance != null)return;
        _instance = this;

        Resource.SetGlobalKey(_instance, "JavaBitmap");

Hmm, yeah, not sure if passing Uno objects around through UX is a good idea.

But since your JavaBitmap is a singleton already you can add a public property for it and then access it from your camera class:


[UXGlobalModule]
public class JavaBitmap : NativeModule
{
	public static JavaBitmap Singleton
	{
		get { return _instance; }
	}
[TargetSpecificImplementationAttribute]
public extern(Android) class Camera
{

	void SomeMethod()
	{
		CaptureAndProcess(JavaBitmap.Singleton.UpdateBitmap);
	}

	[Foreign(Language.Java)]
	void CaptureAndProcess(Action<Java.Object> updateBitmap)
	@{

Hi Vegard and sorry for the late reply; when compiling, the JavaBitmap.uno class is not found (There is no identifier named ‘JavaBitmap’ accessible in this scope. Did you mean ‘JavaBitmap’? ), I guess this is due to the fact that:

MainView
   /Preview/
          JavaBitmap.uno
          /Camera/
                Camera.uno

How can I “import” JavaBitmap.uno from Camera.uno?

The project contains the main .unoproj which imports the cameraPanel .unoproj:

...
  "Projects":[
    "Preview/Camera/CameraStream_include.unoproj"
  ],
...

I see that the JavaBitmap.uno is not included in neither of those .unoproj. I tried including it in each one of them, but getting the same error.

Take a look at this guide for how to use NativeModules.

Hi Anders,

I did, still I could not find an example on how to call a uno method in file A from another uno method in file B.

Getting:

MyClass.MyMethod(Uno.Action<Java.Object>)' has some invalid arguments (<method_group>)

MyMethod is called, as follows:

MyMethod(Test.Singleton.TestMe);

I built Test, trying to follow the indications in the Docs:

using Uno;
using Uno.Compiler.ExportTargetInterop;
using Uno.Threading;
using Fuse;
using Fuse.Resources;
using Fuse.Scripting;
using Uno.IO;
using Uno.UX;

[UXGlobalModule]
public class Test : NativeModule
{
    static readonly Test _instance;

    public static Test Singleton
    {
        get { return _instance; }
    }

    public Test()
    {
        if(_instance != null)return;
        _instance = this;

        Resource.SetGlobalKey(_instance, "Test");

        AddMember(new NativeFunction("TestMe", (NativeCallback)TestMe));

    }
    object[] TestMe(Fuse.Scripting.Context context, object[] args)
    {
      return null;
    }
}

Both classes (MyClass, and the one calling MyTest) are not in the same folder.

Thanks in advance for your help,

What exactly are you trying to achieve?

Hi Anders,

This issue has recently been resolved by Bolav via Slack, I had to post the adopted solution here:

The goal was to save a byte[], generated in Java, to be used by the same Java method on future calls.
The current solution is to store the data in the Uno class containing the Java method as JavaObject, then obtaining/updating that data from the Java method using @{JavaObjectVariable:Get() / Set()}