beeware/toga

Android calls python through chaquo to get the ui window built by toga, strange error “No module named 'org'”

Closed this issue · 6 comments

Describe the bug

Android calls python through chaquo to get the ui window built by toga, strange error No module named 'org'
Android has no problem calling python normal functions, the same environment

Steps to reproduce

Android calls python through chaquo to get the ui window built by toga, strange error No module named 'org'
Android has no problem calling python normal functions, the same environment.

testui.py :

import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW

def build(app):
    box = toga.Box(style=Pack(direction=COLUMN))

    label = toga.Label('Hello, Toga!', style=Pack(padding=(0, 5)))
    box.add(label)
    return box

def main():
    app = toga.App('My Toga App', 'com.test.toga', startup=build)
    app.main_loop()
    return app

PythonActivity.java :

package com.yangda.cardrecorder;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.chaquo.python.PyObject;
import com.chaquo.python.Python;
import com.chaquo.python.android.AndroidPlatform;
import android.util.Log;
//import org.beeware.android.toga.Toga;
//import org.beeware.android.toga.TogaActivity;

public class PythonActivity extends AppCompatActivity {
    private String TAG = "PythonActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ----
        Python py;
        try {
            if (!Python.isStarted()) {
                Log.d(TAG, "Starting Python");
                AndroidPlatform platform = new AndroidPlatform(this);
                platform.redirectStdioToLogcat();
                Python.start(platform);
            }
            py = Python.getInstance();
            Log.d(TAG, "Python instance: " + py.toString());

            // ---
            PyObject module = py.getModule("testui");
            Log.d(TAG, "Module loaded successfully");

            // ---
            PyObject dir = py.getBuiltins().callAttr("dir", module);
            Log.d(TAG, "Module attributes: " + dir.toString());

            // ---
            String moduleName = module.get("__name__").toString();
            Log.d(TAG, "Module name: " + moduleName);


            Log.d(TAG, "Calling attr");
            PyObject ui = module.callAttr("main");
        } catch (Exception e) {
            Log.e(TAG, "Error starting Python or calling module", e);
        }
    }

}

Expected behavior

Android calls python through chaquo to get the ui window built by toga, strange error No module named 'org'
Android has no problem calling python normal functions, the same environment

Screenshots

toga1
toga2

Environment

  • Operating System: android 9
  • Python version: 3.11.2
  • Software versions:
    • Briefcase: 0.3.18
    • Toga:
    • toga-android~=0.4.0

Logs

Starting Python
2024-07-17 18:54:22.064 19987-19987 PythonActivity          com.yangda.cardrecorder              D  Python instance: com.chaquo.python.Python@f83fd01
2024-07-17 18:54:23.365 19987-19987 PythonActivity          com.yangda.cardrecorder              D  Module loaded successfully
2024-07-17 18:54:23.366 19987-19987 PythonActivity          com.yangda.cardrecorder              D  Module attributes: ['COLUMN', 'Pack', 'ROW', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'build', 'main', 'toga']
2024-07-17 18:54:23.367 19987-19987 PythonActivity          com.yangda.cardrecorder              D  Module name: testui
2024-07-17 18:54:23.367 19987-19987 PythonActivity          com.yangda.cardrecorder              D  Calling attr
2024-07-17 18:54:23.918 19987-19987 PythonActivity          com.yangda.cardrecorder              E  Error starting Python or calling module
                                                                                                    com.chaquo.python.PyException: ModuleNotFoundError: No module named 'org'
                                                                                                    	at <python>.java.chaquopy.import_override(import.pxi:20)
                                                                                                    	at <python>.java.chaquopy.import_override(import.pxi:60)
                                                                                                    	at <python>.toga_android.app.<module>(app.py:11)
                                                                                                    	at <python>.java.chaquopy.import_override(import.pxi:60)
                                                                                                    	at <python>.toga_android.factory.<module>(factory.py:4)
                                                                                                    	at <python>.importlib._bootstrap._call_with_frames_removed(<frozen importlib._bootstrap>:219)
                                                                                                    	at <python>.importlib._bootstrap_external.exec_module(<frozen importlib._bootstrap_external>:843)
                                                                                                    	at <python>.java.android.importer.exec_module(importer.py:634)
                                                                                                    	at <python>.java.android.importer.exec_module(importer.py:721)
                                                                                                    	at <python>.importlib._bootstrap._load_unlocked(<frozen importlib._bootstrap>:671)
                                                                                                    	at <python>.importlib._bootstrap._find_and_load_unlocked(<frozen importlib._bootstrap>:975)
                                                                                                    	at <python>.importlib._bootstrap._find_and_load(<frozen importlib._bootstrap>:991)
                                                                                                    	at <python>.importlib._bootstrap._gcd_import(<frozen importlib._bootstrap>:1014)
                                                                                                    	at <python>.importlib.import_module(__init__.py:127)
                                                                                                    	at <python>.toga.platform.get_platform_factory(platform.py:114)
                                                                                                    	at <python>.toga.app.__init__(app.py:464)
                                                                                                    	at <python>.testui.main(testui.py:13)
                                                                                                    	at <python>.chaquopy_java.call(chaquopy_java.pyx:354)
                                                                                                    	at <python>.chaquopy_java.Java_com_chaquo_python_PyObject_callAttrThrowsNative(chaquopy_java.pyx:326)
                                                                                                    	at com.chaquo.python.PyObject.callAttrThrowsNative(Native Method)
                                                                                                    	at com.chaquo.python.PyObject.callAttrThrows(PyObject.java:232)
                                                                                                    	at com.chaquo.python.PyObject.callAttr(PyObject.java:221)
                                                                                                    	at com.yangda.cardrecorder.PythonActivity.onCreate(PythonActivity.java:43)
                                                                                                    	at android.app.Activity.performCreate(Activity.java:7144)
                                                                                                    	at android.app.Activity.performCreate(Activity.java:7135)
                                                                                                    	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
                                                                                                    	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2938)
                                                                                                    	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3093)
                                                                                                    	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
                                                                                                    	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
                                                                                                    	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
                                                                                                    	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1823)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:106)
                                                                                                    	at android.os.Looper.loop(Looper.java:193)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:6840)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:860)

Toga makes certain assumptions about the name and structure of your activity class. The standard activity class is here.

But rather than trying to replicate that, I strongly recommend that you develop your app with Briefcase, which will use the standard activity automatically. The first few pages of the BeeWare tutorial will lead you through how to do that on Android.

Firstly, thank you for your enthusiastic response

I need a permanent floating window, the same code so I have to use Android services to implement it instead of Android activities (toga can display normally,but not permanent), based on the briefcase official documentation

Android services call Python through chaquo (Android activity is normal), strange error “skia : --- Failed to create image decoder with message 'unimplemented'” , but i didn't use skia

Does the mechanism of briefcase not yet support displaying toga GUI for services, and only supports displaying toga GUI for activities? Is it true that EGL_reno, OpenGL renderer, skia, and toga have not been coordinated and processed properly from the underlying framework of Android?

beeware/briefcase#1956

Looking forward to your answer, thank you!

I have no idea what you mean by "normally but not permanent" when you're referring to windows, or what a "permanent floating" window means. A search for "Android permanent window" isn't revealing anything that looks like an API that might be related; The only references to "android floating windows" that I'm seeing seem to relate to floatingapps.net, which is a distinct product, not a generic Android API.

Briefcase is a mechanism for automating the process of getting Python code into an Android app, and Chaquopy is an API you can use in Python to invoke Java classes. It has no special knowledge of EGL_reno, OpenGL, skia or anything else of that nature - it is used to reference and invoke Java classes. If the class exists in the Java namespace, it should be possible to invoke it.

As I've already indicated on #2762, if you want help using Android APIs, then you need to consult an Android API guide. If you are having invoking a specific Android API with Chaquopy, then you need to tell us which specific API is causing problems.

permanent floating : i open a app (floating window), then open b app,The A app must be displayed on top of the B app window

normally but not permanent : i open a app (floating window), then open b app,The A app disappeared

Toga makes certain assumptions about the name and structure of your activity class. The standard activity class is here.

But rather than trying to replicate that, I strongly recommend that you develop your app with Briefcase, which will use the standard activity automatically. The first few pages of the BeeWare tutorial will lead you through how to do that on Android.

Firstly, thank you for your enthusiastic response

I need a permanent floating window, the same code so I have to use Android services to implement it instead of Android activities (toga can display normally,but not permanent), based on the briefcase official documentation

Android services call Python through chaquo (Android activity is normal), strange error “skia : --- Failed to create image decoder with message 'unimplemented'” , but i didn't use skia

Does the mechanism of briefcase not yet support displaying toga GUI for services, and only supports displaying toga GUI for activities? Is it true that EGL_reno, OpenGL renderer, skia, and toga have not been coordinated and processed properly from the underlying framework of Android?

beeware/briefcase#1956

permanent floating : i open a app (floating window), then open b app,The A app must be displayed on top of the B app window

normally but not permanent : i open a app (floating window), then open b app,The A app disappeared

Looking forward to your answer, thank you!

If that is a capability that is available to Android apps, then I have no idea how to achieve it. As I've indicated several times now, if you want advice on how to use Android APIs, you'll need to consult an Android API guide.

We are only in a position to advise on how to invoke Android APIs from Python - and in that case you'll need to tell us the specific API you can't invoke.