From 2abaa319a5105eb7ee4b7438a1a4a52f9ce5a621 Mon Sep 17 00:00:00 2001 From: Mirko Galimberti Date: Sun, 16 Mar 2025 20:26:53 +0100 Subject: [PATCH 1/2] Add SDL3 bootstrap --- pythonforandroid/bootstrap.py | 21 +- .../bootstraps/common/build/build.py | 16 +- .../build/jni/application/src/Android.mk | 5 +- .../common/build/jni/application/src/start.c | 8 +- .../java/org/kivy/android/PythonUtil.java | 4 + .../jni/application/src/bootstrap_name.h | 1 - .../sdl2/build/jni/application/src/Android.mk | 22 + pythonforandroid/bootstraps/sdl3/__init__.py | 56 ++ .../bootstraps/sdl3/build/.gitignore | 14 + .../bootstraps/sdl3/build/blacklist.txt | 84 +++ .../bootstraps/sdl3/build/jni/Application.mk | 8 + .../sdl3/build/jni/application/src/Android.mk | 22 + .../jni/application/src/Android_static.mk | 13 + .../jni/application/src/bootstrap_name.h | 5 + .../sdl3/build/src/main/assets/.gitkeep | 0 .../sdl3/build/src/main/java/.gitkeep | 0 .../android/GenericBroadcastReceiver.java | 19 + .../GenericBroadcastReceiverCallback.java | 8 + .../java/org/kivy/android/PythonActivity.java | 645 ++++++++++++++++++ .../org/kivy/android/launcher/Project.java | 99 +++ .../kivy/android/launcher/ProjectAdapter.java | 35 + .../kivy/android/launcher/ProjectChooser.java | 90 +++ .../sdl3/build/src/main/jniLibs/.gitkeep | 0 .../sdl3/build/src/main/libs/.gitkeep | 0 .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 2683 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 1698 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 3872 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 6874 bytes .../sdl3/build/src/main/res/drawable/.gitkeep | 0 .../src/main/res/layout/chooser_item.xml | 39 ++ .../sdl3/build/src/main/res/layout/main.xml | 13 + .../src/main/res/layout/project_chooser.xml | 22 + .../src/main/res/layout/project_empty.xml | 15 + .../src/main/res/mipmap-anydpi-v26/.gitkeep | 0 .../sdl3/build/src/main/res/mipmap/.gitkeep | 0 .../build/src/patches/SDLActivity.java.patch | 49 ++ .../build/templates/AndroidManifest.tmpl.xml | 144 ++++ .../sdl3/build/templates/strings.tmpl.xml | 17 + .../jni/application/src/bootstrap_name.h | 1 - .../jni/application/src/bootstrap_name.h | 1 - .../jni/application/src/bootstrap_name.h | 1 - pythonforandroid/build.py | 4 + pythonforandroid/recipes/android/__init__.py | 15 +- .../recipes/android/src/android/_android.pyx | 2 +- pythonforandroid/recipes/android/src/setup.py | 3 +- .../recipes/genericndkbuild/__init__.py | 2 +- pythonforandroid/recipes/kivy/__init__.py | 20 +- pythonforandroid/recipes/pyjnius/__init__.py | 7 +- .../recipes/pyjnius/sdl3_jnienv_getter.patch | 24 + pythonforandroid/recipes/sdl2/__init__.py | 2 + pythonforandroid/recipes/sdl3/__init__.py | 57 ++ .../recipes/sdl3_image/__init__.py | 41 ++ .../recipes/sdl3_image/enable-webp.patch | 12 + .../recipes/sdl3_mixer/__init__.py | 45 ++ .../recipes/sdl3_mixer/disable-libgme.patch | 12 + pythonforandroid/recipes/sdl3_ttf/__init__.py | 39 ++ tests/test_bootstrap.py | 17 +- tests/test_graph.py | 4 +- 58 files changed, 1742 insertions(+), 41 deletions(-) create mode 100644 pythonforandroid/bootstraps/sdl2/build/jni/application/src/Android.mk create mode 100644 pythonforandroid/bootstraps/sdl3/__init__.py create mode 100644 pythonforandroid/bootstraps/sdl3/build/.gitignore create mode 100644 pythonforandroid/bootstraps/sdl3/build/blacklist.txt create mode 100644 pythonforandroid/bootstraps/sdl3/build/jni/Application.mk create mode 100644 pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android.mk create mode 100644 pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android_static.mk create mode 100644 pythonforandroid/bootstraps/sdl3/build/jni/application/src/bootstrap_name.h create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/assets/.gitkeep create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/.gitkeep create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/PythonActivity.java create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/Project.java create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/jniLibs/.gitkeep create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/libs/.gitkeep create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable/.gitkeep create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/chooser_item.xml create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/main.xml create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_chooser.xml create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_empty.xml create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap-anydpi-v26/.gitkeep create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap/.gitkeep create mode 100644 pythonforandroid/bootstraps/sdl3/build/src/patches/SDLActivity.java.patch create mode 100644 pythonforandroid/bootstraps/sdl3/build/templates/AndroidManifest.tmpl.xml create mode 100644 pythonforandroid/bootstraps/sdl3/build/templates/strings.tmpl.xml create mode 100644 pythonforandroid/recipes/pyjnius/sdl3_jnienv_getter.patch create mode 100644 pythonforandroid/recipes/sdl3/__init__.py create mode 100644 pythonforandroid/recipes/sdl3_image/__init__.py create mode 100644 pythonforandroid/recipes/sdl3_image/enable-webp.patch create mode 100644 pythonforandroid/recipes/sdl3_mixer/__init__.py create mode 100644 pythonforandroid/recipes/sdl3_mixer/disable-libgme.patch create mode 100644 pythonforandroid/recipes/sdl3_ttf/__init__.py diff --git a/pythonforandroid/bootstrap.py b/pythonforandroid/bootstrap.py index 8bbbcf0eb6..9088a39c8d 100755 --- a/pythonforandroid/bootstrap.py +++ b/pythonforandroid/bootstrap.py @@ -39,7 +39,7 @@ def copy_files(src_root, dest_root, override=True, symlink=False): default_recipe_priorities = [ - "webview", "sdl2", "service_only" # last is highest + "webview", "sdl2", "sdl3", "service_only" # last is highest ] # ^^ NOTE: these are just the default priorities if no special rules # apply (which you can find in the code below), so basically if no @@ -150,18 +150,18 @@ def get_bootstrap_dirs(self): return bootstrap_dirs def _copy_in_final_files(self): - if self.name == "sdl2": - # Get the paths for copying SDL2's java source code: - sdl2_recipe = Recipe.get_recipe("sdl2", self.ctx) - sdl2_build_dir = sdl2_recipe.get_jni_dir() - src_dir = join(sdl2_build_dir, "SDL", "android-project", + if self.name in ["sdl2", "sdl3"]: + # Get the paths for copying SDL's java source code: + sdl_recipe = Recipe.get_recipe(self.name, self.ctx) + sdl_build_dir = sdl_recipe.get_jni_dir() + src_dir = join(sdl_build_dir, "SDL", "android-project", "app", "src", "main", "java", "org", "libsdl", "app") target_dir = join(self.dist_dir, 'src', 'main', 'java', 'org', 'libsdl', 'app') # Do actual copying: - info('Copying in SDL2 .java files from: ' + str(src_dir)) + info('Copying in SDL .java files from: ' + str(src_dir)) if not os.path.exists(target_dir): os.makedirs(target_dir) copy_files(src_dir, target_dir, override=True) @@ -272,6 +272,13 @@ def have_dependency_in_recipes(dep): info('Using sdl2 bootstrap since it is in dependencies') return cls.get_bootstrap("sdl2", ctx) + # Special rule: return SDL3 bootstrap if there's an sdl3 dep: + if (have_dependency_in_recipes("sdl3") and + "sdl3" in [b.name for b in acceptable_bootstraps] + ): + info('Using sdl3 bootstrap since it is in dependencies') + return cls.get_bootstrap("sdl3", ctx) + # Special rule: return "webview" if we depend on common web recipe: for possible_web_dep in known_web_packages: if have_dependency_in_recipes(possible_web_dep): diff --git a/pythonforandroid/bootstraps/common/build/build.py b/pythonforandroid/bootstraps/common/build/build.py index 94382049bf..255153e1e5 100644 --- a/pythonforandroid/bootstraps/common/build/build.py +++ b/pythonforandroid/bootstraps/common/build/build.py @@ -83,7 +83,7 @@ def get_bootstrap_name(): if PYTHON is not None and not exists(PYTHON): PYTHON = None -if _bootstrap_name in ('sdl2', 'webview', 'service_only', 'qt'): +if _bootstrap_name in ('sdl2', 'sdl3', 'webview', 'service_only', 'qt'): WHITELIST_PATTERNS.append('pyconfig.h') environment = jinja2.Environment(loader=jinja2.FileSystemLoader( @@ -541,7 +541,7 @@ def make_package(args): "debug": "debug" in args.build_mode, "native_services": args.native_services } - if get_bootstrap_name() == "sdl2": + if get_bootstrap_name() in ["sdl2", "sdl3"]: render_args["url_scheme"] = url_scheme render( @@ -596,7 +596,7 @@ def make_package(args): "args": args, "private_version": hashlib.sha1(private_version.encode()).hexdigest() } - if get_bootstrap_name() == "sdl2": + if get_bootstrap_name() in ["sdl2", "sdl3"]: render_args["url_scheme"] = url_scheme render( 'strings.tmpl.xml', @@ -769,7 +769,7 @@ def create_argument_parser(): ap.add_argument('--private', dest='private', help='the directory with the app source code files' + ' (containing your main.py entrypoint)', - required=(get_bootstrap_name() != "sdl2")) + required=(get_bootstrap_name() not in ["sdl2", "sdl3"])) ap.add_argument('--package', dest='package', help=('The name of the java package the project will be' ' packaged under.'), @@ -787,7 +787,7 @@ def create_argument_parser(): 'same number of groups of numbers as previous ' 'versions.'), required=True) - if get_bootstrap_name() == "sdl2": + if get_bootstrap_name() in ["sdl2", "sdl3"]: ap.add_argument('--launcher', dest='launcher', action='store_true', help=('Provide this argument to build a multi-app ' 'launcher, rather than a single app.')) @@ -1044,7 +1044,7 @@ def _read_configuration(): args.orientation, args.manifest_orientation ) - if get_bootstrap_name() == "sdl2": + if get_bootstrap_name() in ["sdl2", "sdl3"]: args.sdl_orientation_hint = get_sdl_orientation_hint(args.orientation) if args.res_xmls and isinstance(args.res_xmls[0], list): @@ -1074,9 +1074,9 @@ def _read_configuration(): WHITELIST_PATTERNS += patterns if args.private is None and \ - get_bootstrap_name() == 'sdl2' and args.launcher is None: + get_bootstrap_name() in ['sdl2', 'sdl3'] and args.launcher is None: print('Need --private directory or ' + - '--launcher (SDL2 bootstrap only)' + + '--launcher (SDL2/SDL3 bootstrap only)' + 'to have something to launch inside the .apk!') sys.exit(1) make_package(args) diff --git a/pythonforandroid/bootstraps/common/build/jni/application/src/Android.mk b/pythonforandroid/bootstraps/common/build/jni/application/src/Android.mk index fb2b17719d..eced58db08 100644 --- a/pythonforandroid/bootstraps/common/build/jni/application/src/Android.mk +++ b/pythonforandroid/bootstraps/common/build/jni/application/src/Android.mk @@ -9,12 +9,11 @@ SDL_PATH := ../../SDL LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include # Add your application source files here... -LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.c \ - start.c +LOCAL_SRC_FILES := start.c LOCAL_CFLAGS += -I$(PYTHON_INCLUDE_ROOT) $(EXTRA_CFLAGS) -LOCAL_SHARED_LIBRARIES := SDL2 python_shared +LOCAL_SHARED_LIBRARIES := python_shared LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog $(EXTRA_LDLIBS) diff --git a/pythonforandroid/bootstraps/common/build/jni/application/src/start.c b/pythonforandroid/bootstraps/common/build/jni/application/src/start.c index 88999faf98..ef910cab3d 100644 --- a/pythonforandroid/bootstraps/common/build/jni/application/src/start.c +++ b/pythonforandroid/bootstraps/common/build/jni/application/src/start.c @@ -16,10 +16,16 @@ #include "bootstrap_name.h" -#ifndef BOOTSTRAP_USES_NO_SDL_HEADERS +#ifdef BOOTSTRAP_NAME_SDL2 #include "SDL.h" #include "SDL_opengles2.h" #endif + +#ifdef BOOTSTRAP_NAME_SDL3 +#include "SDL3/SDL.h" +#include "SDL3/SDL_main.h" +#endif + #include "android/log.h" #define ENTRYPOINT_MAXLEN 128 diff --git a/pythonforandroid/bootstraps/common/build/src/main/java/org/kivy/android/PythonUtil.java b/pythonforandroid/bootstraps/common/build/src/main/java/org/kivy/android/PythonUtil.java index cc04d83f6b..83d11639bb 100644 --- a/pythonforandroid/bootstraps/common/build/src/main/java/org/kivy/android/PythonUtil.java +++ b/pythonforandroid/bootstraps/common/build/src/main/java/org/kivy/android/PythonUtil.java @@ -49,6 +49,10 @@ protected static ArrayList getLibraries(File libsDir) { addLibraryIfExists(libsList, "SDL2_image", libsDir); addLibraryIfExists(libsList, "SDL2_mixer", libsDir); addLibraryIfExists(libsList, "SDL2_ttf", libsDir); + addLibraryIfExists(libsList, "SDL3", libsDir); + addLibraryIfExists(libsList, "SDL3_image", libsDir); + addLibraryIfExists(libsList, "SDL3_mixer", libsDir); + addLibraryIfExists(libsList, "SDL3_ttf", libsDir); libsList.add("python3.5m"); libsList.add("python3.6m"); libsList.add("python3.7m"); diff --git a/pythonforandroid/bootstraps/qt/build/jni/application/src/bootstrap_name.h b/pythonforandroid/bootstraps/qt/build/jni/application/src/bootstrap_name.h index 8a4d8aa464..76709f02c9 100644 --- a/pythonforandroid/bootstraps/qt/build/jni/application/src/bootstrap_name.h +++ b/pythonforandroid/bootstraps/qt/build/jni/application/src/bootstrap_name.h @@ -1,4 +1,3 @@ -#define BOOTSTRAP_USES_NO_SDL_HEADERS const char bootstrap_name[] = "qt"; diff --git a/pythonforandroid/bootstraps/sdl2/build/jni/application/src/Android.mk b/pythonforandroid/bootstraps/sdl2/build/jni/application/src/Android.mk new file mode 100644 index 0000000000..09fb3b212e --- /dev/null +++ b/pythonforandroid/bootstraps/sdl2/build/jni/application/src/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := main + +SDL_PATH := ../../SDL + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include + +# Add your application source files here... +LOCAL_SRC_FILES := start.c + +LOCAL_CFLAGS += -I$(PYTHON_INCLUDE_ROOT) $(EXTRA_CFLAGS) + +LOCAL_SHARED_LIBRARIES := SDL2 python_shared + +LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog $(EXTRA_LDLIBS) + +LOCAL_LDFLAGS += -L$(PYTHON_LINK_ROOT) $(APPLICATION_ADDITIONAL_LDFLAGS) + +include $(BUILD_SHARED_LIBRARY) diff --git a/pythonforandroid/bootstraps/sdl3/__init__.py b/pythonforandroid/bootstraps/sdl3/__init__.py new file mode 100644 index 0000000000..fee87603a8 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/__init__.py @@ -0,0 +1,56 @@ +from os.path import join + +import sh + +from pythonforandroid.toolchain import ( + Bootstrap, shprint, current_directory, info, info_main) +from pythonforandroid.util import ensure_dir, rmdir + + +class SDL3GradleBootstrap(Bootstrap): + name = 'sdl3' + + conflicts = ['sdl2'] + + recipe_depends = list( + set(Bootstrap.recipe_depends).union({'sdl3'}) + ) + + def assemble_distribution(self): + info_main("# Creating Android project ({})".format(self.name)) + + rmdir(self.dist_dir) + info("Copying SDL3/gradle build") + shprint(sh.cp, "-r", self.build_dir, self.dist_dir) + + # either the build use environment variable (ANDROID_HOME) + # or the local.properties if exists + with current_directory(self.dist_dir): + with open('local.properties', 'w') as fileh: + fileh.write('sdk.dir={}'.format(self.ctx.sdk_dir)) + + with current_directory(self.dist_dir): + info("Copying Python distribution") + + self.distribute_javaclasses(self.ctx.javaclass_dir, + dest_dir=join("src", "main", "java")) + + for arch in self.ctx.archs: + python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle') + ensure_dir(python_bundle_dir) + + self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)]) + site_packages_dir = self.ctx.python_recipe.create_python_bundle( + join(self.dist_dir, python_bundle_dir), arch) + if not self.ctx.with_debug_symbols: + self.strip_libraries(arch) + self.fry_eggs(site_packages_dir) + + if 'sqlite3' not in self.ctx.recipe_build_order: + with open('blacklist.txt', 'a') as fileh: + fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n') + + super().assemble_distribution() + + +bootstrap = SDL3GradleBootstrap() diff --git a/pythonforandroid/bootstraps/sdl3/build/.gitignore b/pythonforandroid/bootstraps/sdl3/build/.gitignore new file mode 100644 index 0000000000..a1fc39c070 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/.gitignore @@ -0,0 +1,14 @@ +.gradle +/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties diff --git a/pythonforandroid/bootstraps/sdl3/build/blacklist.txt b/pythonforandroid/bootstraps/sdl3/build/blacklist.txt new file mode 100644 index 0000000000..d5e230c89a --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/blacklist.txt @@ -0,0 +1,84 @@ +# prevent user to include invalid extensions +*.apk +*.aab +*.apks +*.pxd + +# eggs +*.egg-info + +# unit test +unittest/* + +# python config +config/makesetup + +# unused kivy files (platform specific) +kivy/input/providers/wm_* +kivy/input/providers/mactouch* +kivy/input/providers/probesysfs* +kivy/input/providers/mtdev* +kivy/input/providers/hidinput* +kivy/core/camera/camera_videocapture* +kivy/core/spelling/*osx* +kivy/core/video/video_pyglet* +kivy/tools +kivy/tests/* +kivy/*/*.h +kivy/*/*.pxi + +# unused encodings +lib-dynload/*codec* +encodings/cp*.pyo +encodings/tis* +encodings/shift* +encodings/bz2* +encodings/iso* +encodings/undefined* +encodings/johab* +encodings/p* +encodings/m* +encodings/euc* +encodings/k* +encodings/unicode_internal* +encodings/quo* +encodings/gb* +encodings/big5* +encodings/hp* +encodings/hz* + +# unused python modules +bsddb/* +wsgiref/* +hotshot/* +pydoc_data/* +tty.pyo +anydbm.pyo +nturl2path.pyo +LICENCE.txt +macurl2path.pyo +dummy_threading.pyo +audiodev.pyo +antigravity.pyo +dumbdbm.pyo +sndhdr.pyo +__phello__.foo.pyo +sunaudio.pyo +os2emxpath.pyo +multiprocessing/dummy* + +# unused binaries python modules +lib-dynload/termios.so +lib-dynload/_lsprof.so +lib-dynload/*audioop.so +lib-dynload/_hotshot.so +lib-dynload/_heapq.so +lib-dynload/_json.so +lib-dynload/grp.so +lib-dynload/resource.so +lib-dynload/pyexpat.so +lib-dynload/_ctypes_test.so +lib-dynload/_testcapi.so + +# odd files +plat-linux3/regen diff --git a/pythonforandroid/bootstraps/sdl3/build/jni/Application.mk b/pythonforandroid/bootstraps/sdl3/build/jni/Application.mk new file mode 100644 index 0000000000..15598537ca --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/jni/Application.mk @@ -0,0 +1,8 @@ + +# Uncomment this if you're using STL in your project +# See CPLUSPLUS-SUPPORT.html in the NDK documentation for more information +# APP_STL := stlport_static + +# APP_ABI := armeabi armeabi-v7a x86 +APP_ABI := $(ARCH) +APP_PLATFORM := $(NDK_API) diff --git a/pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android.mk b/pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android.mk new file mode 100644 index 0000000000..14b4e0ed66 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := main + +SDL_PATH := ../../SDL + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include + +# Add your application source files here... +LOCAL_SRC_FILES := start.c + +LOCAL_CFLAGS += -I$(PYTHON_INCLUDE_ROOT) $(EXTRA_CFLAGS) + +LOCAL_SHARED_LIBRARIES := SDL3 python_shared + +LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog $(EXTRA_LDLIBS) + +LOCAL_LDFLAGS += -L$(PYTHON_LINK_ROOT) $(APPLICATION_ADDITIONAL_LDFLAGS) + +include $(BUILD_SHARED_LIBRARY) diff --git a/pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android_static.mk b/pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android_static.mk new file mode 100644 index 0000000000..f4ff2462e6 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android_static.mk @@ -0,0 +1,13 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := main + +LOCAL_SRC_FILES := start.c + +LOCAL_STATIC_LIBRARIES := SDL3_static + + +include $(BUILD_SHARED_LIBRARY) +$(call import-module,SDL)LOCAL_PATH := $(call my-dir) diff --git a/pythonforandroid/bootstraps/sdl3/build/jni/application/src/bootstrap_name.h b/pythonforandroid/bootstraps/sdl3/build/jni/application/src/bootstrap_name.h new file mode 100644 index 0000000000..55096a4aad --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/jni/application/src/bootstrap_name.h @@ -0,0 +1,5 @@ + +#define BOOTSTRAP_NAME_SDL3 + +const char bootstrap_name[] = "SDL3"; // capitalized for historic reasons + diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/assets/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/java/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java new file mode 100644 index 0000000000..58a1c5edf8 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java @@ -0,0 +1,19 @@ +package org.kivy.android; + +import android.content.BroadcastReceiver; +import android.content.Intent; +import android.content.Context; + +public class GenericBroadcastReceiver extends BroadcastReceiver { + + GenericBroadcastReceiverCallback listener; + + public GenericBroadcastReceiver(GenericBroadcastReceiverCallback listener) { + super(); + this.listener = listener; + } + + public void onReceive(Context context, Intent intent) { + this.listener.onReceive(context, intent); + } +} diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java new file mode 100644 index 0000000000..1a87c98b2d --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java @@ -0,0 +1,8 @@ +package org.kivy.android; + +import android.content.Intent; +import android.content.Context; + +public interface GenericBroadcastReceiverCallback { + void onReceive(Context context, Intent intent); +}; diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/PythonActivity.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/PythonActivity.java new file mode 100644 index 0000000000..0a9c884cc4 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/PythonActivity.java @@ -0,0 +1,645 @@ +package org.kivy.android; + +import java.io.InputStream; +import java.io.FileWriter; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.PowerManager; +import android.util.Log; +import android.view.inputmethod.InputMethodManager; +import android.view.SurfaceView; +import android.view.ViewGroup; +import android.view.View; +import android.widget.ImageView; +import android.widget.Toast; +import android.content.res.Resources.NotFoundException; + +import org.libsdl.app.SDLActivity; + +import org.kivy.android.launcher.Project; + +import org.renpy.android.ResourceManager; + + +public class PythonActivity extends SDLActivity { + private static final String TAG = "PythonActivity"; + + public static PythonActivity mActivity = null; + + private ResourceManager resourceManager = null; + private Bundle mMetaData = null; + private PowerManager.WakeLock mWakeLock = null; + + public String getAppRoot() { + String app_root = getFilesDir().getAbsolutePath() + "/app"; + return app_root; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + Log.v(TAG, "PythonActivity onCreate running"); + resourceManager = new ResourceManager(this); + + Log.v(TAG, "About to do super onCreate"); + super.onCreate(savedInstanceState); + Log.v(TAG, "Did super onCreate"); + + this.mActivity = this; + this.showLoadingScreen(this.getLoadingScreen()); + + new UnpackFilesTask().execute(getAppRoot()); + } + + public void loadLibraries() { + String app_root = new String(getAppRoot()); + File app_root_file = new File(app_root); + PythonUtil.loadLibraries(app_root_file, + new File(getApplicationInfo().nativeLibraryDir)); + } + + /** + * Show an error using a toast. (Only makes sense from non-UI + * threads.) + */ + public void toastError(final String msg) { + + final Activity thisActivity = this; + + runOnUiThread(new Runnable () { + public void run() { + Toast.makeText(thisActivity, msg, Toast.LENGTH_LONG).show(); + } + }); + + // Wait to show the error. + synchronized (this) { + try { + this.wait(1000); + } catch (InterruptedException e) { + } + } + } + + private class UnpackFilesTask extends AsyncTask { + @Override + protected String doInBackground(String... params) { + File app_root_file = new File(params[0]); + Log.v(TAG, "Ready to unpack"); + PythonUtil.unpackAsset(mActivity, "private", app_root_file, true); + PythonUtil.unpackPyBundle(mActivity, getApplicationInfo().nativeLibraryDir + "/" + "libpybundle", app_root_file, false); + return null; + } + + @Override + protected void onPostExecute(String result) { + // Figure out the directory where the game is. If the game was + // given to us via an intent, then we use the scheme-specific + // part of that intent to determine the file to launch. We + // also use the android.txt file to determine the orientation. + // + // Otherwise, we use the public data, if we have it, or the + // private data if we do not. + mActivity.finishLoad(); + + // finishLoad called setContentView with the SDL view, which + // removed the loading screen. However, we still need it to + // show until the app is ready to render, so pop it back up + // on top of the SDL view. + mActivity.showLoadingScreen(getLoadingScreen()); + + String app_root_dir = getAppRoot(); + if (getIntent() != null && getIntent().getAction() != null && + getIntent().getAction().equals("org.kivy.LAUNCH")) { + File path = new File(getIntent().getData().getSchemeSpecificPart()); + + Project p = Project.scanDirectory(path); + String entry_point = getEntryPoint(p.dir); + SDLActivity.nativeSetenv("ANDROID_ENTRYPOINT", p.dir + "/" + entry_point); + SDLActivity.nativeSetenv("ANDROID_ARGUMENT", p.dir); + SDLActivity.nativeSetenv("ANDROID_APP_PATH", p.dir); + + if (p != null) { + if (p.landscape) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } else { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + } + + // Let old apps know they started. + try { + FileWriter f = new FileWriter(new File(path, ".launch")); + f.write("started"); + f.close(); + } catch (IOException e) { + // pass + } + } else { + String entry_point = getEntryPoint(app_root_dir); + SDLActivity.nativeSetenv("ANDROID_ENTRYPOINT", entry_point); + SDLActivity.nativeSetenv("ANDROID_ARGUMENT", app_root_dir); + SDLActivity.nativeSetenv("ANDROID_APP_PATH", app_root_dir); + } + + String mFilesDirectory = mActivity.getFilesDir().getAbsolutePath(); + Log.v(TAG, "Setting env vars for start.c and Python to use"); + SDLActivity.nativeSetenv("ANDROID_PRIVATE", mFilesDirectory); + SDLActivity.nativeSetenv("ANDROID_UNPACK", app_root_dir); + SDLActivity.nativeSetenv("PYTHONHOME", app_root_dir); + SDLActivity.nativeSetenv("PYTHONPATH", app_root_dir + ":" + app_root_dir + "/lib"); + SDLActivity.nativeSetenv("PYTHONOPTIMIZE", "2"); + + try { + Log.v(TAG, "Access to our meta-data..."); + mActivity.mMetaData = mActivity.getPackageManager().getApplicationInfo( + mActivity.getPackageName(), PackageManager.GET_META_DATA).metaData; + + PowerManager pm = (PowerManager) mActivity.getSystemService(Context.POWER_SERVICE); + if ( mActivity.mMetaData.getInt("wakelock") == 1 ) { + mActivity.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "Screen On"); + mActivity.mWakeLock.acquire(); + } + if ( mActivity.mMetaData.getInt("surface.transparent") != 0 ) { + Log.v(TAG, "Surface will be transparent."); + getSurface().setZOrderOnTop(true); + getSurface().getHolder().setFormat(PixelFormat.TRANSPARENT); + } else { + Log.i(TAG, "Surface will NOT be transparent"); + } + } catch (PackageManager.NameNotFoundException e) { + } + + // Launch app if that hasn't been done yet: + if (mActivity.mHasFocus && ( + // never went into proper resume state: + mActivity.mCurrentNativeState == NativeState.INIT || + ( + // resumed earlier but wasn't ready yet + mActivity.mCurrentNativeState == NativeState.RESUMED && + mActivity.mSDLThread == null + ))) { + // Because sometimes the app will get stuck here and never + // actually run, ensure that it gets launched if we're active: + mActivity.resumeNativeThread(); + } + } + + @Override + protected void onPreExecute() { + } + + @Override + protected void onProgressUpdate(Void... values) { + } + } + + public static ViewGroup getLayout() { + return mLayout; + } + + public static SurfaceView getSurface() { + return mSurface; + } + + //---------------------------------------------------------------------------- + // Listener interface for onNewIntent + // + + public interface NewIntentListener { + void onNewIntent(Intent intent); + } + + private List newIntentListeners = null; + + public void registerNewIntentListener(NewIntentListener listener) { + if ( this.newIntentListeners == null ) + this.newIntentListeners = Collections.synchronizedList(new ArrayList()); + this.newIntentListeners.add(listener); + } + + public void unregisterNewIntentListener(NewIntentListener listener) { + if ( this.newIntentListeners == null ) + return; + this.newIntentListeners.remove(listener); + } + + @Override + protected void onNewIntent(Intent intent) { + if ( this.newIntentListeners == null ) + return; + this.onResume(); + synchronized ( this.newIntentListeners ) { + Iterator iterator = this.newIntentListeners.iterator(); + while ( iterator.hasNext() ) { + (iterator.next()).onNewIntent(intent); + } + } + } + + //---------------------------------------------------------------------------- + // Listener interface for onActivityResult + // + + public interface ActivityResultListener { + void onActivityResult(int requestCode, int resultCode, Intent data); + } + + private List activityResultListeners = null; + + public void registerActivityResultListener(ActivityResultListener listener) { + if ( this.activityResultListeners == null ) + this.activityResultListeners = Collections.synchronizedList(new ArrayList()); + this.activityResultListeners.add(listener); + } + + public void unregisterActivityResultListener(ActivityResultListener listener) { + if ( this.activityResultListeners == null ) + return; + this.activityResultListeners.remove(listener); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent intent) { + if ( this.activityResultListeners == null ) + return; + this.onResume(); + synchronized ( this.activityResultListeners ) { + Iterator iterator = this.activityResultListeners.iterator(); + while ( iterator.hasNext() ) + (iterator.next()).onActivityResult(requestCode, resultCode, intent); + } + } + + public static void start_service( + String serviceTitle, + String serviceDescription, + String pythonServiceArgument + ) { + _do_start_service( + serviceTitle, serviceDescription, pythonServiceArgument, true + ); + } + + public static void start_service_not_as_foreground( + String serviceTitle, + String serviceDescription, + String pythonServiceArgument + ) { + _do_start_service( + serviceTitle, serviceDescription, pythonServiceArgument, false + ); + } + + public static void _do_start_service( + String serviceTitle, + String serviceDescription, + String pythonServiceArgument, + boolean showForegroundNotification + ) { + Intent serviceIntent = new Intent(PythonActivity.mActivity, PythonService.class); + String argument = PythonActivity.mActivity.getFilesDir().getAbsolutePath(); + String app_root_dir = PythonActivity.mActivity.getAppRoot(); + String entry_point = PythonActivity.mActivity.getEntryPoint(app_root_dir + "/service"); + serviceIntent.putExtra("androidPrivate", argument); + serviceIntent.putExtra("androidArgument", app_root_dir); + serviceIntent.putExtra("serviceEntrypoint", "service/" + entry_point); + serviceIntent.putExtra("pythonName", "python"); + serviceIntent.putExtra("pythonHome", app_root_dir); + serviceIntent.putExtra("pythonPath", app_root_dir + ":" + app_root_dir + "/lib"); + serviceIntent.putExtra("serviceStartAsForeground", + (showForegroundNotification ? "true" : "false") + ); + serviceIntent.putExtra("serviceTitle", serviceTitle); + serviceIntent.putExtra("serviceDescription", serviceDescription); + serviceIntent.putExtra("pythonServiceArgument", pythonServiceArgument); + PythonActivity.mActivity.startService(serviceIntent); + } + + public static void stop_service() { + Intent serviceIntent = new Intent(PythonActivity.mActivity, PythonService.class); + PythonActivity.mActivity.stopService(serviceIntent); + } + + /** Loading screen view **/ + public static ImageView mImageView = null; + public static View mLottieView = null; + /** Whether main routine/actual app has started yet **/ + protected boolean mAppConfirmedActive = false; + /** Timer for delayed loading screen removal. **/ + protected Timer loadingScreenRemovalTimer = null; + + // Overridden since it's called often, to check whether to remove the + // loading screen: + @Override + protected boolean sendCommand(int command, Object data) { + boolean result = super.sendCommand(command, data); + considerLoadingScreenRemoval(); + return result; + } + + /** Confirm that the app's main routine has been launched. + **/ + @Override + public void appConfirmedActive() { + if (!mAppConfirmedActive) { + Log.v(TAG, "appConfirmedActive() -> preparing loading screen removal"); + mAppConfirmedActive = true; + considerLoadingScreenRemoval(); + } + } + + /** This is called from various places to check whether the app's main + * routine has been launched already, and if it has, then the loading + * screen will be removed. + **/ + public void considerLoadingScreenRemoval() { + if (loadingScreenRemovalTimer != null) + return; + runOnUiThread(new Runnable() { + public void run() { + if (((PythonActivity)PythonActivity.mSingleton).mAppConfirmedActive && + loadingScreenRemovalTimer == null) { + // Remove loading screen but with a delay. + // (app can use p4a's android.loadingscreen module to + // do it quicker if it wants to) + // get a handler (call from main thread) + // this will run when timer elapses + TimerTask removalTask = new TimerTask() { + @Override + public void run() { + // post a runnable to the handler + runOnUiThread(new Runnable() { + @Override + public void run() { + PythonActivity activity = + ((PythonActivity)PythonActivity.mSingleton); + if (activity != null) + activity.removeLoadingScreen(); + } + }); + } + }; + loadingScreenRemovalTimer = new Timer(); + loadingScreenRemovalTimer.schedule(removalTask, 5000); + } + } + }); + } + + public void removeLoadingScreen() { + runOnUiThread(new Runnable() { + public void run() { + View view = mLottieView != null ? mLottieView : mImageView; + if (view != null && view.getParent() != null) { + ((ViewGroup)view.getParent()).removeView(view); + mLottieView = null; + mImageView = null; + } + } + }); + } + + public String getEntryPoint(String search_dir) { + /* Get the main file (.pyc|.py) depending on if we + * have a compiled version or not. + */ + List entryPoints = new ArrayList(); + entryPoints.add("main.pyc"); // python 3 compiled files + for (String value : entryPoints) { + File mainFile = new File(search_dir + "/" + value); + if (mainFile.exists()) { + return value; + } + } + return "main.py"; + } + + protected void showLoadingScreen(View view) { + try { + if (mLayout == null) { + setContentView(view); + } else if (view.getParent() == null) { + mLayout.addView(view); + } + } catch (IllegalStateException e) { + // The loading screen can be attempted to be applied twice if app + // is tabbed in/out, quickly. + // (Gives error "The specified child already has a parent. + // You must call removeView() on the child's parent first.") + } + } + + protected void setBackgroundColor(View view) { + /* + * Set the presplash loading screen background color + * https://developer.android.com/reference/android/graphics/Color.html + * Parse the color string, and return the corresponding color-int. + * If the string cannot be parsed, throws an IllegalArgumentException exception. + * Supported formats are: #RRGGBB #AARRGGBB or one of the following names: + * 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta', 'yellow', + * 'lightgray', 'darkgray', 'grey', 'lightgrey', 'darkgrey', 'aqua', 'fuchsia', + * 'lime', 'maroon', 'navy', 'olive', 'purple', 'silver', 'teal'. + */ + String backgroundColor = resourceManager.getString("presplash_color"); + if (backgroundColor != null) { + try { + view.setBackgroundColor(Color.parseColor(backgroundColor)); + } catch (IllegalArgumentException e) {} + } + } + + protected View getLoadingScreen() { + // If we have an mLottieView or mImageView already, then do + // nothing because it will have already been made the content + // view or added to the layout. + if (mLottieView != null || mImageView != null) { + // we already have a splash screen + return mLottieView != null ? mLottieView : mImageView; + } + + // first try to load the lottie one + try { + mLottieView = getLayoutInflater().inflate( + this.resourceManager.getIdentifier("lottie", "layout"), + mLayout, + false + ); + try { + if (mLayout == null) { + setContentView(mLottieView); + } else if (PythonActivity.mLottieView.getParent() == null) { + mLayout.addView(mLottieView); + } + } catch (IllegalStateException e) { + // The loading screen can be attempted to be applied twice if app + // is tabbed in/out, quickly. + // (Gives error "The specified child already has a parent. + // You must call removeView() on the child's parent first.") + } + setBackgroundColor(mLottieView); + return mLottieView; + } + catch (NotFoundException e) { + Log.v("SDL", "couldn't find lottie layout or animation, trying static splash"); + } + + // no lottie asset, try to load the static image then + int presplashId = this.resourceManager.getIdentifier("presplash", "drawable"); + InputStream is = this.getResources().openRawResource(presplashId); + Bitmap bitmap = null; + try { + bitmap = BitmapFactory.decodeStream(is); + } finally { + try { + is.close(); + } catch (IOException e) {}; + } + + mImageView = new ImageView(this); + mImageView.setImageBitmap(bitmap); + setBackgroundColor(mImageView); + + mImageView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.FILL_PARENT)); + mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + return mImageView; + } + + @Override + protected void onPause() { + if (this.mWakeLock != null && mWakeLock.isHeld()) { + this.mWakeLock.release(); + } + + Log.v(TAG, "onPause()"); + try { + super.onPause(); + } catch (UnsatisfiedLinkError e) { + // Catch pause while still in loading screen failing to + // call native function (since it's not yet loaded) + } + } + + @Override + protected void onResume() { + if (this.mWakeLock != null) { + this.mWakeLock.acquire(); + } + Log.v(TAG, "onResume()"); + try { + super.onResume(); + } catch (UnsatisfiedLinkError e) { + // Catch resume while still in loading screen failing to + // call native function (since it's not yet loaded) + } + considerLoadingScreenRemoval(); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + try { + super.onWindowFocusChanged(hasFocus); + } catch (UnsatisfiedLinkError e) { + // Catch window focus while still in loading screen failing to + // call native function (since it's not yet loaded) + } + considerLoadingScreenRemoval(); + } + + /** + * Used by android.permissions p4a module to register a call back after + * requesting runtime permissions + **/ + public interface PermissionsCallback { + void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults); + } + + private PermissionsCallback permissionCallback; + private boolean havePermissionsCallback = false; + + public void addPermissionsCallback(PermissionsCallback callback) { + permissionCallback = callback; + havePermissionsCallback = true; + Log.v(TAG, "addPermissionsCallback(): Added callback for onRequestPermissionsResult"); + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + Log.v(TAG, "onRequestPermissionsResult()"); + if (havePermissionsCallback) { + Log.v(TAG, "onRequestPermissionsResult passed to callback"); + permissionCallback.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + /** + * Used by android.permissions p4a module to check a permission + **/ + public boolean checkCurrentPermission(String permission) { + if (android.os.Build.VERSION.SDK_INT < 23) + return true; + + try { + java.lang.reflect.Method methodCheckPermission = + Activity.class.getMethod("checkSelfPermission", String.class); + Object resultObj = methodCheckPermission.invoke(this, permission); + int result = Integer.parseInt(resultObj.toString()); + if (result == PackageManager.PERMISSION_GRANTED) + return true; + } catch (IllegalAccessException | NoSuchMethodException | + InvocationTargetException e) { + } + return false; + } + + /** + * Used by android.permissions p4a module to request runtime permissions + **/ + public void requestPermissionsWithRequestCode(String[] permissions, int requestCode) { + if (android.os.Build.VERSION.SDK_INT < 23) + return; + try { + java.lang.reflect.Method methodRequestPermission = + Activity.class.getMethod("requestPermissions", + String[].class, int.class); + methodRequestPermission.invoke(this, permissions, requestCode); + } catch (IllegalAccessException | NoSuchMethodException | + InvocationTargetException e) { + } + } + + public void requestPermissions(String[] permissions) { + requestPermissionsWithRequestCode(permissions, 1); + } + + public static void changeKeyboard(int inputType) { + /* + if (SDLActivity.keyboardInputType != inputType){ + SDLActivity.keyboardInputType = inputType; + InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.restartInput(mTextEdit); + } + */ + } +} diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/Project.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/Project.java new file mode 100644 index 0000000000..9177b43bb7 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/Project.java @@ -0,0 +1,99 @@ +package org.kivy.android.launcher; + +import java.io.UnsupportedEncodingException; +import java.io.File; +import java.io.FileInputStream; +import java.util.Properties; + +import android.util.Log; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + + +/** + * This represents a project we've scanned for. + */ +public class Project { + + public String dir = null; + String title = null; + String author = null; + Bitmap icon = null; + public boolean landscape = false; + + static String decode(String s) { + try { + return new String(s.getBytes("ISO-8859-1"), "UTF-8"); + } catch (UnsupportedEncodingException e) { + return s; + } + } + + /** + * Scans directory for a android.txt file. If it finds one, + * and it looks valid enough, then it creates a new Project, + * and returns that. Otherwise, returns null. + */ + public static Project scanDirectory(File dir) { + + // We might have a link file. + if (dir.getAbsolutePath().endsWith(".link")) { + try { + + // Scan the android.txt file. + File propfile = new File(dir, "android.txt"); + FileInputStream in = new FileInputStream(propfile); + Properties p = new Properties(); + p.load(in); + in.close(); + + String directory = p.getProperty("directory", null); + + if (directory == null) { + return null; + } + + dir = new File(directory); + + } catch (Exception e) { + Log.i("Project", "Couldn't open link file " + dir, e); + } + } + + // Make sure we're dealing with a directory. + if (! dir.isDirectory()) { + return null; + } + + try { + + // Scan the android.txt file. + File propfile = new File(dir, "android.txt"); + FileInputStream in = new FileInputStream(propfile); + Properties p = new Properties(); + p.load(in); + in.close(); + + // Get the various properties. + String title = decode(p.getProperty("title", "Untitled")); + String author = decode(p.getProperty("author", "")); + boolean landscape = p.getProperty("orientation", "portrait").equals("landscape"); + + // Create the project object. + Project rv = new Project(); + rv.title = title; + rv.author = author; + rv.icon = BitmapFactory.decodeFile(new File(dir, "icon.png").getAbsolutePath()); + rv.landscape = landscape; + rv.dir = dir.getAbsolutePath(); + + return rv; + + } catch (Exception e) { + Log.i("Project", "Couldn't open android.txt", e); + } + + return null; + + } +} diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java new file mode 100644 index 0000000000..457f83f79b --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java @@ -0,0 +1,35 @@ +package org.kivy.android.launcher; + +import android.app.Activity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; +import android.widget.ImageView; + +import org.renpy.android.ResourceManager; + +public class ProjectAdapter extends ArrayAdapter { + + private ResourceManager resourceManager; + + public ProjectAdapter(Activity context) { + super(context, 0); + resourceManager = new ResourceManager(context); + } + + public View getView(int position, View convertView, ViewGroup parent) { + Project p = getItem(position); + + View v = resourceManager.inflateView("chooser_item"); + TextView title = (TextView) resourceManager.getViewById(v, "title"); + TextView author = (TextView) resourceManager.getViewById(v, "author"); + ImageView icon = (ImageView) resourceManager.getViewById(v, "icon"); + + title.setText(p.title); + author.setText(p.author); + icon.setImageBitmap(p.icon); + + return v; + } +} diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java new file mode 100644 index 0000000000..486f88bae4 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java @@ -0,0 +1,90 @@ +package org.kivy.android.launcher; + +import android.app.Activity; + +import android.content.Intent; +import android.view.View; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.AdapterView; +import android.os.Environment; + +import java.io.File; +import java.util.Arrays; +import android.net.Uri; + +import org.renpy.android.ResourceManager; + +public class ProjectChooser extends Activity implements AdapterView.OnItemClickListener { + + ResourceManager resourceManager; + + String urlScheme; + + @Override + public void onStart() + { + super.onStart(); + + resourceManager = new ResourceManager(this); + + urlScheme = resourceManager.getString("urlScheme"); + + // Set the window title. + setTitle(resourceManager.getString("appName")); + + // Scan the sdcard for files, and sort them. + File dir = new File(Environment.getExternalStorageDirectory(), urlScheme); + + File entries[] = dir.listFiles(); + + if (entries == null) { + entries = new File[0]; + } + + Arrays.sort(entries); + + // Create a ProjectAdapter and fill it with projects. + ProjectAdapter projectAdapter = new ProjectAdapter(this); + + // Populate it with the properties files. + for (File d : entries) { + Project p = Project.scanDirectory(d); + if (p != null) { + projectAdapter.add(p); + } + } + + if (projectAdapter.getCount() != 0) { + + View v = resourceManager.inflateView("project_chooser"); + ListView l = (ListView) resourceManager.getViewById(v, "projectList"); + + l.setAdapter(projectAdapter); + l.setOnItemClickListener(this); + + setContentView(v); + + } else { + + View v = resourceManager.inflateView("project_empty"); + TextView emptyText = (TextView) resourceManager.getViewById(v, "emptyText"); + + emptyText.setText("No projects are available to launch. Please place a project into " + dir + " and restart this application. Press the back button to exit."); + + setContentView(v); + } + } + + public void onItemClick(AdapterView parent, View view, int position, long id) { + Project p = (Project) parent.getItemAtPosition(position); + + Intent intent = new Intent( + "org.kivy.LAUNCH", + Uri.fromParts(urlScheme, p.dir, "")); + + intent.setClassName(getPackageName(), "org.kivy.android.PythonActivity"); + this.startActivity(intent); + this.finish(); + } +} diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/jniLibs/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/jniLibs/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/libs/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/libs/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-hdpi/ic_launcher.png b/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d50bdaae06ee5a8d3f39911f81715abd3bf7b24d GIT binary patch literal 2683 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 literal 0 HcmV?d00001 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-mdpi/ic_launcher.png b/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..0a299eb3cc0273ad1fc260cf0b4a2c35f5d373f5 GIT binary patch literal 1698 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 literal 0 HcmV?d00001 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-xxhdpi/ic_launcher.png b/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d423dac2624cf0b5dc90821a15362bc29e5a1e6b GIT binary patch literal 6874 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 literal 0 HcmV?d00001 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/chooser_item.xml b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/chooser_item.xml new file mode 100644 index 0000000000..1823b13223 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/chooser_item.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/main.xml b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/main.xml new file mode 100644 index 0000000000..123c4b6eac --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/main.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_chooser.xml b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_chooser.xml new file mode 100644 index 0000000000..23828e644b --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_chooser.xml @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_empty.xml b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_empty.xml new file mode 100644 index 0000000000..ee5481421d --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_empty.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap-anydpi-v26/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap-anydpi-v26/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/patches/SDLActivity.java.patch b/pythonforandroid/bootstraps/sdl3/build/src/patches/SDLActivity.java.patch new file mode 100644 index 0000000000..e1ad50cda5 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/src/patches/SDLActivity.java.patch @@ -0,0 +1,49 @@ +--- a/src/main/java/org/libsdl/app/SDLActivity.java ++++ b/src/main/java/org/libsdl/app/SDLActivity.java +@@ -259,6 +259,7 @@ + String[] arguments = SDLActivity.mSingleton.getArguments(); + + Log.v("SDL", "Running main function " + function + " from library " + library); ++ SDLActivity.mSingleton.appConfirmedActive(); + SDLActivity.nativeRunMain(library, function, arguments); + Log.v("SDL", "Finished main function"); + } +@@ -351,6 +352,15 @@ + Log.v(TAG, "Model: " + Build.MODEL); + Log.v(TAG, "onCreate()"); + super.onCreate(savedInstanceState); ++ ++ SDL.initialize(); ++ // So we can call stuff from static callbacks ++ mSingleton = this; ++ } ++ ++ // We don't do this in onCreate because we unpack and load the app data on a thread ++ // and we can't run setup tasks until that thread completes. ++ protected void finishLoad() { + + + /* Control activity re-creation */ +@@ -1541,8 +1551,22 @@ + return null; + } + return SDLActivity.mSurface.getNativeSurface(); ++ } ++ ++ /** ++ * Calls turnActive() on singleton to keep loading screen active ++ */ ++ public static void triggerAppConfirmedActive() { ++ mSingleton.appConfirmedActive(); + } + ++ /** ++ * Trick needed for loading screen, overridden by PythonActivity ++ * to keep loading screen active ++ */ ++ public void appConfirmedActive() { ++ } ++ + // Input + + /** diff --git a/pythonforandroid/bootstraps/sdl3/build/templates/AndroidManifest.tmpl.xml b/pythonforandroid/bootstraps/sdl3/build/templates/AndroidManifest.tmpl.xml new file mode 100644 index 0000000000..c31bb3f747 --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/templates/AndroidManifest.tmpl.xml @@ -0,0 +1,144 @@ + + + + + = 9 %} + android:xlargeScreens="true" + {% endif %} + /> + + + + + + + + + {% for perm in args.permissions %} + + {% endfor %} + + {% if args.wakelock %} + + {% endif %} + + {% if args.billing_pubkey %} + + {% endif %} + + {{ args.extra_manifest_xml }} + + + + + {% for l in args.android_used_libs %} + + {% endfor %} + + {% for m in args.meta_data %} + {% endfor %} + + + + + + {% if args.launcher %} + + + + {% else %} + + + {% endif %} + + {% if args.home_app %} + + + {% endif %} + + + {%- if args.intent_filters -%} + {{- args.intent_filters -}} + {%- endif -%} + + + {% if args.launcher %} + + + + + + + + + {% endif %} + + {% if service or args.launcher %} + + {% endif %} + {% for name in service_names %} + + {% endfor %} + {% for name in native_services %} + + {% endfor %} + + {% if args.billing_pubkey %} + + + + + + + + + {% endif %} + {% for a in args.add_activity %} + + {% endfor %} + + + diff --git a/pythonforandroid/bootstraps/sdl3/build/templates/strings.tmpl.xml b/pythonforandroid/bootstraps/sdl3/build/templates/strings.tmpl.xml new file mode 100644 index 0000000000..17e376adbd --- /dev/null +++ b/pythonforandroid/bootstraps/sdl3/build/templates/strings.tmpl.xml @@ -0,0 +1,17 @@ + + + + {{ args.name }} + {{ private_version }} + {{ args.presplash_color }} + {{ url_scheme }} + diff --git a/pythonforandroid/bootstraps/service_library/build/jni/application/src/bootstrap_name.h b/pythonforandroid/bootstraps/service_library/build/jni/application/src/bootstrap_name.h index 01fd122890..95bd2ef3ae 100644 --- a/pythonforandroid/bootstraps/service_library/build/jni/application/src/bootstrap_name.h +++ b/pythonforandroid/bootstraps/service_library/build/jni/application/src/bootstrap_name.h @@ -1,6 +1,5 @@ #define BOOTSTRAP_NAME_LIBRARY -#define BOOTSTRAP_USES_NO_SDL_HEADERS const char bootstrap_name[] = "service_library"; diff --git a/pythonforandroid/bootstraps/service_only/build/jni/application/src/bootstrap_name.h b/pythonforandroid/bootstraps/service_only/build/jni/application/src/bootstrap_name.h index b93a4ae6ce..9598d1abfe 100644 --- a/pythonforandroid/bootstraps/service_only/build/jni/application/src/bootstrap_name.h +++ b/pythonforandroid/bootstraps/service_only/build/jni/application/src/bootstrap_name.h @@ -1,6 +1,5 @@ #define BOOTSTRAP_NAME_SERVICEONLY -#define BOOTSTRAP_USES_NO_SDL_HEADERS const char bootstrap_name[] = "service_only"; diff --git a/pythonforandroid/bootstraps/webview/build/jni/application/src/bootstrap_name.h b/pythonforandroid/bootstraps/webview/build/jni/application/src/bootstrap_name.h index 11c7905dfe..87b64ac724 100644 --- a/pythonforandroid/bootstraps/webview/build/jni/application/src/bootstrap_name.h +++ b/pythonforandroid/bootstraps/webview/build/jni/application/src/bootstrap_name.h @@ -1,6 +1,5 @@ #define BOOTSTRAP_NAME_WEBVIEW -#define BOOTSTRAP_USES_NO_SDL_HEADERS const char bootstrap_name[] = "webview"; diff --git a/pythonforandroid/build.py b/pythonforandroid/build.py index 98e2d70b2b..8b1c723423 100644 --- a/pythonforandroid/build.py +++ b/pythonforandroid/build.py @@ -892,6 +892,10 @@ def copylibs_function(soname, objs_paths, extra_link_dirs=None, env=None): 'SDL2_ttf', 'SDL2_image', 'SDL2_mixer', + 'SDL3', + 'SDL3_ttf', + 'SDL3_image', + 'SDL3_mixer', ) found_libs = [] sofiles = [] diff --git a/pythonforandroid/recipes/android/__init__.py b/pythonforandroid/recipes/android/__init__.py index 608d9ee738..5174a69bfa 100644 --- a/pythonforandroid/recipes/android/__init__.py +++ b/pythonforandroid/recipes/android/__init__.py @@ -12,7 +12,7 @@ class AndroidRecipe(IncludedFilesBehaviour, CythonRecipe): src_filename = 'src' - depends = [('sdl2', 'genericndkbuild'), 'pyjnius'] + depends = [('sdl3', 'sdl2', 'genericndkbuild'), 'pyjnius'] config_env = {} @@ -34,8 +34,7 @@ def prebuild_arch(self, arch): if isinstance(ctx_bootstrap, bytes): ctx_bootstrap = ctx_bootstrap.decode('utf-8') bootstrap = bootstrap_name = ctx_bootstrap - is_sdl2 = (bootstrap_name == "sdl2") - if bootstrap_name in ["sdl2", "webview", "service_only", "service_library", "qt"]: + if bootstrap_name in ["sdl2", "sdl3", "webview", "service_only", "service_library", "qt"]: java_ns = u'org.kivy.android' jni_ns = u'org/kivy/android' else: @@ -47,7 +46,8 @@ def prebuild_arch(self, arch): config = { 'BOOTSTRAP': bootstrap, - 'IS_SDL2': int(is_sdl2), + 'IS_SDL2': int(bootstrap_name == "sdl2"), + 'IS_SDL3': int(bootstrap_name == "sdl3"), 'PY2': 0, 'JAVA_NAMESPACE': java_ns, 'JNI_NAMESPACE': jni_ns, @@ -73,11 +73,16 @@ def prebuild_arch(self, arch): )) self.config_env[key] = str(value) - if is_sdl2: + if bootstrap_name == "sdl2": fh.write('JNIEnv *SDL_AndroidGetJNIEnv(void);\n') fh.write( '#define SDL_ANDROID_GetJNIEnv SDL_AndroidGetJNIEnv\n' ) + elif bootstrap_name == "sdl3": + fh.write('JNIEnv *SDL_GetAndroidJNIEnv(void);\n') + fh.write( + '#define SDL_ANDROID_GetJNIEnv SDL_GetAndroidJNIEnv\n' + ) else: fh.write('JNIEnv *WebView_AndroidGetJNIEnv(void);\n') fh.write( diff --git a/pythonforandroid/recipes/android/src/android/_android.pyx b/pythonforandroid/recipes/android/src/android/_android.pyx index 6708b846a8..1d6e65a161 100644 --- a/pythonforandroid/recipes/android/src/android/_android.pyx +++ b/pythonforandroid/recipes/android/src/android/_android.pyx @@ -194,7 +194,7 @@ TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 112 TYPE_TEXT_VARIATION_URI = 16 TYPE_CLASS_PHONE = 3 -IF BOOTSTRAP == 'sdl2': +IF BOOTSTRAP in ['sdl2', 'sdl3']: def remove_presplash(): # Remove android presplash in SDL2 bootstrap. mActivity.removeLoadingScreen() diff --git a/pythonforandroid/recipes/android/src/setup.py b/pythonforandroid/recipes/android/src/setup.py index bcd411f46b..0f5ceb1fd3 100755 --- a/pythonforandroid/recipes/android/src/setup.py +++ b/pythonforandroid/recipes/android/src/setup.py @@ -3,7 +3,8 @@ library_dirs = ['libs/' + os.environ['ARCH']] lib_dict = { - 'sdl2': ['SDL2', 'SDL2_image', 'SDL2_mixer', 'SDL2_ttf'] + 'sdl2': ['SDL2', 'SDL2_image', 'SDL2_mixer', 'SDL2_ttf'], + 'sdl3': ['SDL3', 'SDL3_image', 'SDL3_mixer', 'SDL3_ttf'], } sdl_libs = lib_dict.get(os.environ['BOOTSTRAP'], ['main']) diff --git a/pythonforandroid/recipes/genericndkbuild/__init__.py b/pythonforandroid/recipes/genericndkbuild/__init__.py index 8b2a9c26a2..9e85aac5d6 100644 --- a/pythonforandroid/recipes/genericndkbuild/__init__.py +++ b/pythonforandroid/recipes/genericndkbuild/__init__.py @@ -10,7 +10,7 @@ class GenericNDKBuildRecipe(BootstrapNDKRecipe): url = None depends = ['python3'] - conflicts = ['sdl2'] + conflicts = ['sdl2', 'sdl3'] def should_build(self, arch): return True diff --git a/pythonforandroid/recipes/kivy/__init__.py b/pythonforandroid/recipes/kivy/__init__.py index b28e03a7a5..a5030abf95 100644 --- a/pythonforandroid/recipes/kivy/__init__.py +++ b/pythonforandroid/recipes/kivy/__init__.py @@ -26,8 +26,9 @@ class KivyRecipe(CythonRecipe): url = 'https://github.com/kivy/kivy/archive/{version}.zip' name = 'kivy' - depends = ['sdl2', 'pyjnius', 'setuptools'] + depends = [('sdl2', 'sdl3'), 'pyjnius', 'setuptools'] python_depends = ['certifi', 'chardet', 'idna', 'requests', 'urllib3', 'filetype'] + hostpython_prerequisites = [] # sdl-gl-swapwindow-nogil.patch is needed to avoid a deadlock. # See: https://github.com/kivy/kivy/pull/8025 @@ -53,7 +54,7 @@ def cythonize_build(self, env, build_dir='.'): def cythonize_file(self, env, build_dir, filename): # We can ignore a few files that aren't important to the # android build, and may not work on Android anyway - do_not_cythonize = ['window_x11.pyx', ] + do_not_cythonize = ['window_x11.pyx', 'camera_avfoundation.pyx', 'img_imageio.pyx', 'egl_angle_metal.pyx'] if basename(filename) in do_not_cythonize: return super().cythonize_file(env, build_dir, filename) @@ -73,6 +74,21 @@ def get_recipe_env(self, arch): *sdl2_mixer_recipe.get_include_dirs(arch), join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'), ]) + if "sdl3" in self.ctx.recipe_build_order: + sdl3_mixer_recipe = self.get_recipe("sdl3_mixer", self.ctx) + sdl3_image_recipe = self.get_recipe("sdl3_image", self.ctx) + sdl3_ttf_recipe = self.get_recipe("sdl3_ttf", self.ctx) + sdl3_recipe = self.get_recipe("sdl3", self.ctx) + env["USE_SDL3"] = "1" + env["KIVY_SPLIT_EXAMPLES"] = "1" + env["KIVY_SDL3_PATH"] = ":".join( + [ + *sdl3_mixer_recipe.get_include_dirs(arch), + *sdl3_image_recipe.get_include_dirs(arch), + *sdl3_ttf_recipe.get_include_dirs(arch), + *sdl3_recipe.get_include_dirs(arch), + ] + ) return env diff --git a/pythonforandroid/recipes/pyjnius/__init__.py b/pythonforandroid/recipes/pyjnius/__init__.py index 0bcb74d392..00369df216 100644 --- a/pythonforandroid/recipes/pyjnius/__init__.py +++ b/pythonforandroid/recipes/pyjnius/__init__.py @@ -9,10 +9,13 @@ class PyjniusRecipe(CythonRecipe): version = '1.6.1' url = 'https://github.com/kivy/pyjnius/archive/{version}.zip' name = 'pyjnius' - depends = [('genericndkbuild', 'sdl2'), 'six'] + depends = [('genericndkbuild', 'sdl2', 'sdl3'), 'six'] site_packages_name = 'jnius' - patches = [('genericndkbuild_jnienv_getter.patch', will_build('genericndkbuild'))] + patches = [ + ('genericndkbuild_jnienv_getter.patch', will_build('genericndkbuild')), + ('sdl3_jnienv_getter.patch', will_build('sdl3')), + ] def get_recipe_env(self, arch): env = super().get_recipe_env(arch) diff --git a/pythonforandroid/recipes/pyjnius/sdl3_jnienv_getter.patch b/pythonforandroid/recipes/pyjnius/sdl3_jnienv_getter.patch new file mode 100644 index 0000000000..d91da76fbb --- /dev/null +++ b/pythonforandroid/recipes/pyjnius/sdl3_jnienv_getter.patch @@ -0,0 +1,24 @@ +diff -Naur pyjnius.orig/jnius/env.py pyjnius/jnius/env.py +--- pyjnius.orig/jnius/env.py 2022-05-28 11:16:02.000000000 +0200 ++++ pyjnius/jnius/env.py 2022-05-28 11:18:30.000000000 +0200 +@@ -268,7 +268,7 @@ + + class AndroidJavaLocation(UnixJavaLocation): + def get_libraries(self): +- return ['SDL2', 'log'] ++ return ['SDL3', 'log'] + + def get_include_dirs(self): + # When cross-compiling for Android, we should not use the include dirs +diff -Naur pyjnius.orig/jnius/jnius_jvm_android.pxi pyjnius/jnius/jnius_jvm_android.pxi +--- pyjnius.orig/jnius/jnius_jvm_android.pxi 2022-05-28 11:16:02.000000000 +0200 ++++ pyjnius/jnius/jnius_jvm_android.pxi 2022-05-28 11:17:17.000000000 +0200 +@@ -1,6 +1,6 @@ + # on android, rely on SDL to get the JNI env +-cdef extern JNIEnv *SDL_AndroidGetJNIEnv() ++cdef extern JNIEnv *SDL_GetAndroidJNIEnv() + + + cdef JNIEnv *get_platform_jnienv() except NULL: +- return SDL_AndroidGetJNIEnv() ++ return SDL_GetAndroidJNIEnv() diff --git a/pythonforandroid/recipes/sdl2/__init__.py b/pythonforandroid/recipes/sdl2/__init__.py index 8d5fbc2dc2..cd0185c717 100644 --- a/pythonforandroid/recipes/sdl2/__init__.py +++ b/pythonforandroid/recipes/sdl2/__init__.py @@ -10,6 +10,8 @@ class LibSDL2Recipe(BootstrapNDKRecipe): url = "https://github.com/libsdl-org/SDL/releases/download/release-{version}/SDL2-{version}.tar.gz" md5sum = 'a344eb827a03045c9b399e99af4af13d' + conflicts = ['sdl3'] + dir_name = 'SDL' depends = ['sdl2_image', 'sdl2_mixer', 'sdl2_ttf'] diff --git a/pythonforandroid/recipes/sdl3/__init__.py b/pythonforandroid/recipes/sdl3/__init__.py new file mode 100644 index 0000000000..f22884deda --- /dev/null +++ b/pythonforandroid/recipes/sdl3/__init__.py @@ -0,0 +1,57 @@ +from os.path import exists, join + +from pythonforandroid.recipe import BootstrapNDKRecipe +from pythonforandroid.toolchain import current_directory, shprint +import sh + + +class LibSDL3Recipe(BootstrapNDKRecipe): + version = "3.2.8" + url = "https://github.com/libsdl-org/SDL/releases/download/release-{version}/SDL3-{version}.tar.gz" + # md5sum = 'a344eb827a03045c9b399e99af4af13d' + + dir_name = "SDL" + + depends = ["sdl3_image", "sdl3_mixer", "sdl3_ttf"] + + def get_recipe_env( + self, arch=None, with_flags_in_cc=True, with_python=True + ): + env = super().get_recipe_env( + arch=arch, + with_flags_in_cc=with_flags_in_cc, + with_python=with_python, + ) + env["APP_ALLOW_MISSING_DEPS"] = "true" + return env + + def get_include_dirs(self, arch): + return [ + join(self.ctx.bootstrap.build_dir, "jni", "SDL", "include"), + join(self.ctx.bootstrap.build_dir, "jni", "SDL", "include", "SDL3"), + ] + + def should_build(self, arch): + libdir = join(self.get_build_dir(arch.arch), "../..", "libs", arch.arch) + libs = [ + "libmain.so", + "libSDL3.so", + "libSDL3_image.so", + "libSDL3_mixer.so", + "libSDL3_ttf.so", + ] + return not all(exists(join(libdir, x)) for x in libs) + + def build_arch(self, arch): + env = self.get_recipe_env(arch) + + with current_directory(self.get_jni_dir()): + shprint( + sh.Command(join(self.ctx.ndk_dir, "ndk-build")), + "V=1", + "NDK_DEBUG=" + ("1" if self.ctx.build_as_debuggable else "0"), + _env=env, + ) + + +recipe = LibSDL3Recipe() diff --git a/pythonforandroid/recipes/sdl3_image/__init__.py b/pythonforandroid/recipes/sdl3_image/__init__.py new file mode 100644 index 0000000000..f6d705b168 --- /dev/null +++ b/pythonforandroid/recipes/sdl3_image/__init__.py @@ -0,0 +1,41 @@ +import os +import sh +from pythonforandroid.logger import shprint +from pythonforandroid.recipe import BootstrapNDKRecipe +from pythonforandroid.util import current_directory + + +class LibSDL3Image(BootstrapNDKRecipe): + version = "3.2.4" + url = "https://github.com/libsdl-org/SDL_image/releases/download/release-{version}/SDL3_image-{version}.tar.gz" + dir_name = "SDL3_image" + + patches = ["enable-webp.patch"] + + def get_include_dirs(self, arch): + return [ + os.path.join( + self.ctx.bootstrap.build_dir, "jni", "SDL3_image", "include" + ), + os.path.join( + self.ctx.bootstrap.build_dir, + "jni", + "SDL3_image", + "include", + "SDL3_image", + ), + ] + + def prebuild_arch(self, arch): + # We do not have a folder for each arch on BootstrapNDKRecipe, so we + # need to skip the external deps download if we already have done it. + external_deps_dir = os.path.join( + self.get_build_dir(arch.arch), "external" + ) + if not os.path.exists(os.path.join(external_deps_dir, "libwebp")): + with current_directory(external_deps_dir): + shprint(sh.Command("./download.sh")) + super().prebuild_arch(arch) + + +recipe = LibSDL3Image() diff --git a/pythonforandroid/recipes/sdl3_image/enable-webp.patch b/pythonforandroid/recipes/sdl3_image/enable-webp.patch new file mode 100644 index 0000000000..98d72f2017 --- /dev/null +++ b/pythonforandroid/recipes/sdl3_image/enable-webp.patch @@ -0,0 +1,12 @@ +diff -Naur SDL2_image.orig/Android.mk SDL2_image/Android.mk +--- SDL2_image.orig/Android.mk 2022-10-03 20:51:52.000000000 +0200 ++++ SDL2_image/Android.mk 2022-10-03 20:52:48.000000000 +0200 +@@ -32,7 +32,7 @@ + + # Enable this if you want to support loading WebP images + # The library path should be a relative path to this directory. +-SUPPORT_WEBP ?= false ++SUPPORT_WEBP := true + WEBP_LIBRARY_PATH := external/libwebp + + diff --git a/pythonforandroid/recipes/sdl3_mixer/__init__.py b/pythonforandroid/recipes/sdl3_mixer/__init__.py new file mode 100644 index 0000000000..c60c5bc157 --- /dev/null +++ b/pythonforandroid/recipes/sdl3_mixer/__init__.py @@ -0,0 +1,45 @@ +import os +import sh +from pythonforandroid.logger import shprint +from pythonforandroid.recipe import BootstrapNDKRecipe +from pythonforandroid.util import current_directory + + +class LibSDL3Mixer(BootstrapNDKRecipe): + version = "72a73339731a12c1002f9caca64f1ab924938102" + # url = "https://github.com/libsdl-org/SDL_ttf/releases/download/release-{version}/SDL3_ttf-{version}.tar.gz" + url = "https://github.com/libsdl-org/SDL_mixer/archive/{version}.tar.gz" + dir_name = "SDL3_mixer" + + patches = ["disable-libgme.patch"] + + def get_include_dirs(self, arch): + return [ + os.path.join( + self.ctx.bootstrap.build_dir, "jni", "SDL3_mixer", "include" + ), + os.path.join( + self.ctx.bootstrap.build_dir, + "jni", + "SDL3_mixer", + "include", + "SDL3_mixer", + ), + ] + + def prebuild_arch(self, arch): + # We do not have a folder for each arch on BootstrapNDKRecipe, so we + # need to skip the external deps download if we already have done it. + external_deps_dir = os.path.join( + self.get_build_dir(arch.arch), "external" + ) + + if not os.path.exists( + os.path.join(external_deps_dir, "libgme", "Android.mk") + ): + with current_directory(external_deps_dir): + shprint(sh.Command("./download.sh")) + super().prebuild_arch(arch) + + +recipe = LibSDL3Mixer() diff --git a/pythonforandroid/recipes/sdl3_mixer/disable-libgme.patch b/pythonforandroid/recipes/sdl3_mixer/disable-libgme.patch new file mode 100644 index 0000000000..233808e7db --- /dev/null +++ b/pythonforandroid/recipes/sdl3_mixer/disable-libgme.patch @@ -0,0 +1,12 @@ +diff -Naur SDL3_mixer.orig/Android.mk SDL3_mixer/Android.mk +--- SDL3_mixer.orig/Android.mk 2025-03-16 21:05:19 ++++ SDL3_mixer/Android.mk 2025-03-16 21:06:33 +@@ -31,7 +31,7 @@ + WAVPACK_LIBRARY_PATH := external/wavpack + + # Enable this if you want to support loading music via libgme +-SUPPORT_GME ?= true ++SUPPORT_GME ?= false + GME_LIBRARY_PATH := external/libgme + + # Enable this if you want to support loading MOD music via XMP-lite diff --git a/pythonforandroid/recipes/sdl3_ttf/__init__.py b/pythonforandroid/recipes/sdl3_ttf/__init__.py new file mode 100644 index 0000000000..f291f69667 --- /dev/null +++ b/pythonforandroid/recipes/sdl3_ttf/__init__.py @@ -0,0 +1,39 @@ +import os +import sh +from pythonforandroid.logger import shprint +from pythonforandroid.recipe import BootstrapNDKRecipe +from pythonforandroid.util import current_directory + + +class LibSDL3TTF(BootstrapNDKRecipe): + version = "3.2.0" + url = "https://github.com/libsdl-org/SDL_ttf/releases/download/release-{version}/SDL3_ttf-{version}.tar.gz" + dir_name = "SDL3_ttf" + + def get_include_dirs(self, arch): + return [ + os.path.join( + self.ctx.bootstrap.build_dir, "jni", "SDL3_ttf", "include" + ), + os.path.join( + self.ctx.bootstrap.build_dir, + "jni", + "SDL3_ttf", + "include", + "SDL3_ttf", + ), + ] + + def prebuild_arch(self, arch): + # We do not have a folder for each arch on BootstrapNDKRecipe, so we + # need to skip the external deps download if we already have done it. + external_deps_dir = os.path.join( + self.get_build_dir(arch.arch), "external" + ) + if not os.path.exists(os.path.join(external_deps_dir, "harfbuzz")): + with current_directory(external_deps_dir): + shprint(sh.Command("./download.sh")) + super().prebuild_arch(arch) + + +recipe = LibSDL3TTF() diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index eea284b8c9..ffb4942f15 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -144,9 +144,17 @@ def test_all_bootstraps(self): """A test which will initialize a bootstrap and will check if the method :meth:`~pythonforandroid.bootstrap.Bootstrap.all_bootstraps ` returns the expected values, which should be: `empty", `service_only`, - `webview`, `sdl2` and `qt` + `webview`, `sdl2`, `sdl3` and `qt` """ - expected_bootstraps = {"empty", "service_only", "service_library", "webview", "sdl2", "qt"} + expected_bootstraps = { + "empty", + "service_only", + "service_library", + "webview", + "sdl2", + "sdl3", + "qt", + } set_of_bootstraps = Bootstrap.all_bootstraps() self.assertEqual( expected_bootstraps, expected_bootstraps & set_of_bootstraps @@ -180,8 +188,9 @@ def test_expand_dependencies_with_pure_python_package(self): expanded_result = expand_dependencies( ["python3", "kivy", "peewee"], self.ctx ) - # we expect to one results for python3 - self.assertEqual(len(expanded_result), 1) + # we expect to 2 results for python3 + # (python3, sdl2/sdl3 [one is blacklisted]) + self.assertEqual(len(expanded_result), 2) self.assertIsInstance(expanded_result, list) for i in expanded_result: self.assertIsInstance(i, list) diff --git a/tests/test_graph.py b/tests/test_graph.py index f7647bcac7..1ac9c68090 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -101,9 +101,9 @@ def test_blacklist(): get_recipe_order_and_bootstrap(ctx, ["flask", "kivy"], wbootstrap) assert "conflict" in e_info.value.message.lower() - # We should no longer get a conflict blacklisting sdl2: + # We should no longer get a conflict blacklisting sdl2 and sdl3 get_recipe_order_and_bootstrap( - ctx, ["flask", "kivy"], wbootstrap, blacklist=["sdl2"] + ctx, ["flask", "kivy"], wbootstrap, blacklist=["sdl2", "sdl3"] ) From 5b8896994b1b24e75babde0b657c195aa7ab82ac Mon Sep 17 00:00:00 2001 From: Mirko Galimberti Date: Thu, 10 Apr 2025 21:52:53 +0200 Subject: [PATCH 2/2] Avoid some DRY issues + minor fixes + version bump --- pythonforandroid/bootstrap.py | 6 +- .../bootstraps/_sdl_common/__init__.py | 49 ++++++ .../{sdl2 => _sdl_common}/build/.gitignore | 0 .../{sdl2 => _sdl_common}/build/blacklist.txt | 0 .../build/jni/Application.mk | 0 .../build/src/main/assets/.gitkeep | 0 .../build/src/main/java}/.gitkeep | 0 .../android/GenericBroadcastReceiver.java | 0 .../GenericBroadcastReceiverCallback.java | 0 .../org/kivy/android/launcher/Project.java | 0 .../kivy/android/launcher/ProjectAdapter.java | 0 .../kivy/android/launcher/ProjectChooser.java | 0 .../build/src/main/jniLibs}/.gitkeep | 0 .../build/src/main/libs}/.gitkeep | 0 .../main/res/drawable-hdpi/ic_launcher.png | Bin .../main/res/drawable-mdpi/ic_launcher.png | Bin .../main/res/drawable-xhdpi/ic_launcher.png | Bin .../main/res/drawable-xxhdpi/ic_launcher.png | Bin .../build/src/main/res/drawable}/.gitkeep | 0 .../src/main/res/layout/chooser_item.xml | 0 .../build/src/main/res/layout/main.xml | 0 .../src/main/res/layout/project_chooser.xml | 0 .../src/main/res/layout/project_empty.xml | 0 .../src/main/res/mipmap-anydpi-v26}/.gitkeep | 0 .../build/src/main/res/mipmap}/.gitkeep | 0 .../build/templates/AndroidManifest.tmpl.xml | 0 .../build/templates/strings.tmpl.xml | 0 .../bootstraps/common/build/build.py | 18 ++- pythonforandroid/bootstraps/sdl2/__init__.py | 50 +----- pythonforandroid/bootstraps/sdl3/__init__.py | 52 +------ .../bootstraps/sdl3/build/.gitignore | 14 -- .../bootstraps/sdl3/build/blacklist.txt | 84 ---------- .../bootstraps/sdl3/build/jni/Application.mk | 8 - .../sdl3/build/src/main/java/.gitkeep | 0 .../android/GenericBroadcastReceiver.java | 19 --- .../GenericBroadcastReceiverCallback.java | 8 - .../org/kivy/android/launcher/Project.java | 99 ------------ .../kivy/android/launcher/ProjectAdapter.java | 35 ----- .../kivy/android/launcher/ProjectChooser.java | 90 ----------- .../sdl3/build/src/main/jniLibs/.gitkeep | 0 .../sdl3/build/src/main/libs/.gitkeep | 0 .../main/res/drawable-hdpi/ic_launcher.png | Bin 2683 -> 0 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 1698 -> 0 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 3872 -> 0 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 6874 -> 0 bytes .../sdl3/build/src/main/res/drawable/.gitkeep | 0 .../src/main/res/layout/chooser_item.xml | 39 ----- .../sdl3/build/src/main/res/layout/main.xml | 13 -- .../src/main/res/layout/project_chooser.xml | 22 --- .../src/main/res/layout/project_empty.xml | 15 -- .../src/main/res/mipmap-anydpi-v26/.gitkeep | 0 .../sdl3/build/src/main/res/mipmap/.gitkeep | 0 .../build/templates/AndroidManifest.tmpl.xml | 144 ------------------ .../sdl3/build/templates/strings.tmpl.xml | 17 --- pythonforandroid/recipes/sdl3/__init__.py | 6 +- pythonforandroid/recipes/sdl3_ttf/__init__.py | 2 +- tests/test_bootstrap.py | 27 +++- tests/test_build.py | 2 +- 58 files changed, 100 insertions(+), 719 deletions(-) create mode 100644 pythonforandroid/bootstraps/_sdl_common/__init__.py rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/.gitignore (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/blacklist.txt (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/jni/Application.mk (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/assets/.gitkeep (100%) rename pythonforandroid/bootstraps/{sdl2/build/src/main/jniLibs => _sdl_common/build/src/main/java}/.gitkeep (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/java/org/kivy/android/launcher/Project.java (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java (100%) rename pythonforandroid/bootstraps/{sdl2/build/src/main/libs => _sdl_common/build/src/main/jniLibs}/.gitkeep (100%) rename pythonforandroid/bootstraps/{sdl2/build/src/main/res/drawable => _sdl_common/build/src/main/libs}/.gitkeep (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/res/drawable-hdpi/ic_launcher.png (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/res/drawable-mdpi/ic_launcher.png (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/res/drawable-xhdpi/ic_launcher.png (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/res/drawable-xxhdpi/ic_launcher.png (100%) rename pythonforandroid/bootstraps/{sdl2/build/src/main/res/mipmap-anydpi-v26 => _sdl_common/build/src/main/res/drawable}/.gitkeep (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/res/layout/chooser_item.xml (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/res/layout/main.xml (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/res/layout/project_chooser.xml (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/src/main/res/layout/project_empty.xml (100%) rename pythonforandroid/bootstraps/{sdl2/build/src/main/res/mipmap => _sdl_common/build/src/main/res/mipmap-anydpi-v26}/.gitkeep (100%) rename pythonforandroid/bootstraps/{sdl3/build/src/main/assets => _sdl_common/build/src/main/res/mipmap}/.gitkeep (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/templates/AndroidManifest.tmpl.xml (100%) rename pythonforandroid/bootstraps/{sdl2 => _sdl_common}/build/templates/strings.tmpl.xml (100%) delete mode 100644 pythonforandroid/bootstraps/sdl3/build/.gitignore delete mode 100644 pythonforandroid/bootstraps/sdl3/build/blacklist.txt delete mode 100644 pythonforandroid/bootstraps/sdl3/build/jni/Application.mk delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/.gitkeep delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/Project.java delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/jniLibs/.gitkeep delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/libs/.gitkeep delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-hdpi/ic_launcher.png delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-mdpi/ic_launcher.png delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-xhdpi/ic_launcher.png delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-xxhdpi/ic_launcher.png delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable/.gitkeep delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/chooser_item.xml delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/main.xml delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_chooser.xml delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_empty.xml delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap-anydpi-v26/.gitkeep delete mode 100644 pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap/.gitkeep delete mode 100644 pythonforandroid/bootstraps/sdl3/build/templates/AndroidManifest.tmpl.xml delete mode 100644 pythonforandroid/bootstraps/sdl3/build/templates/strings.tmpl.xml diff --git a/pythonforandroid/bootstrap.py b/pythonforandroid/bootstrap.py index 9088a39c8d..5f4b3e7ab9 100755 --- a/pythonforandroid/bootstrap.py +++ b/pythonforandroid/bootstrap.py @@ -14,6 +14,8 @@ rmdir, move) from pythonforandroid.recipe import Recipe +SDL_BOOTSTRAPS = ("sdl2", "sdl3") + def copy_files(src_root, dest_root, override=True, symlink=False): for root, dirnames, filenames in walk(src_root): @@ -150,7 +152,7 @@ def get_bootstrap_dirs(self): return bootstrap_dirs def _copy_in_final_files(self): - if self.name in ["sdl2", "sdl3"]: + if self.name in SDL_BOOTSTRAPS: # Get the paths for copying SDL's java source code: sdl_recipe = Recipe.get_recipe(self.name, self.ctx) sdl_build_dir = sdl_recipe.get_jni_dir() @@ -193,7 +195,7 @@ def assemble_distribution(self): @classmethod def all_bootstraps(cls): '''Find all the available bootstraps and return them.''' - forbidden_dirs = ('__pycache__', 'common') + forbidden_dirs = ('__pycache__', 'common', '_sdl_common') bootstraps_dir = join(dirname(__file__), 'bootstraps') result = set() for name in listdir(bootstraps_dir): diff --git a/pythonforandroid/bootstraps/_sdl_common/__init__.py b/pythonforandroid/bootstraps/_sdl_common/__init__.py new file mode 100644 index 0000000000..034e52c7c1 --- /dev/null +++ b/pythonforandroid/bootstraps/_sdl_common/__init__.py @@ -0,0 +1,49 @@ +from os.path import join + +import sh + +from pythonforandroid.toolchain import ( + Bootstrap, shprint, current_directory, info, info_main) +from pythonforandroid.util import ensure_dir, rmdir + + +class SDLGradleBootstrap(Bootstrap): + name = "_sdl_common" + + recipe_depends = [] + + def assemble_distribution(self): + info_main("# Creating Android project ({})".format(self.name)) + + rmdir(self.dist_dir) + info("Copying SDL/gradle build") + shprint(sh.cp, "-r", self.build_dir, self.dist_dir) + + # either the build use environment variable (ANDROID_HOME) + # or the local.properties if exists + with current_directory(self.dist_dir): + with open('local.properties', 'w') as fileh: + fileh.write('sdk.dir={}'.format(self.ctx.sdk_dir)) + + with current_directory(self.dist_dir): + info("Copying Python distribution") + + self.distribute_javaclasses(self.ctx.javaclass_dir, + dest_dir=join("src", "main", "java")) + + for arch in self.ctx.archs: + python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle') + ensure_dir(python_bundle_dir) + + self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)]) + site_packages_dir = self.ctx.python_recipe.create_python_bundle( + join(self.dist_dir, python_bundle_dir), arch) + if not self.ctx.with_debug_symbols: + self.strip_libraries(arch) + self.fry_eggs(site_packages_dir) + + if 'sqlite3' not in self.ctx.recipe_build_order: + with open('blacklist.txt', 'a') as fileh: + fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n') + + super().assemble_distribution() diff --git a/pythonforandroid/bootstraps/sdl2/build/.gitignore b/pythonforandroid/bootstraps/_sdl_common/build/.gitignore similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/.gitignore rename to pythonforandroid/bootstraps/_sdl_common/build/.gitignore diff --git a/pythonforandroid/bootstraps/sdl2/build/blacklist.txt b/pythonforandroid/bootstraps/_sdl_common/build/blacklist.txt similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/blacklist.txt rename to pythonforandroid/bootstraps/_sdl_common/build/blacklist.txt diff --git a/pythonforandroid/bootstraps/sdl2/build/jni/Application.mk b/pythonforandroid/bootstraps/_sdl_common/build/jni/Application.mk similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/jni/Application.mk rename to pythonforandroid/bootstraps/_sdl_common/build/jni/Application.mk diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/assets/.gitkeep b/pythonforandroid/bootstraps/_sdl_common/build/src/main/assets/.gitkeep similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/assets/.gitkeep rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/assets/.gitkeep diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/jniLibs/.gitkeep b/pythonforandroid/bootstraps/_sdl_common/build/src/main/java/.gitkeep similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/jniLibs/.gitkeep rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/java/.gitkeep diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java b/pythonforandroid/bootstraps/_sdl_common/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java b/pythonforandroid/bootstraps/_sdl_common/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/launcher/Project.java b/pythonforandroid/bootstraps/_sdl_common/build/src/main/java/org/kivy/android/launcher/Project.java similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/launcher/Project.java rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/java/org/kivy/android/launcher/Project.java diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java b/pythonforandroid/bootstraps/_sdl_common/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java b/pythonforandroid/bootstraps/_sdl_common/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/libs/.gitkeep b/pythonforandroid/bootstraps/_sdl_common/build/src/main/jniLibs/.gitkeep similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/libs/.gitkeep rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/jniLibs/.gitkeep diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/drawable/.gitkeep b/pythonforandroid/bootstraps/_sdl_common/build/src/main/libs/.gitkeep similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/drawable/.gitkeep rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/libs/.gitkeep diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/drawable-hdpi/ic_launcher.png b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/drawable-hdpi/ic_launcher.png similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/drawable-hdpi/ic_launcher.png rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/drawable-mdpi/ic_launcher.png b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/drawable-mdpi/ic_launcher.png similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/drawable-mdpi/ic_launcher.png rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/drawable-xhdpi/ic_launcher.png b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/drawable-xhdpi/ic_launcher.png similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/drawable-xhdpi/ic_launcher.png rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/drawable-xxhdpi/ic_launcher.png b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/drawable-xxhdpi/ic_launcher.png similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/drawable-xxhdpi/ic_launcher.png rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/mipmap-anydpi-v26/.gitkeep b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/drawable/.gitkeep similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/mipmap-anydpi-v26/.gitkeep rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/drawable/.gitkeep diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/layout/chooser_item.xml b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/layout/chooser_item.xml similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/layout/chooser_item.xml rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/layout/chooser_item.xml diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/layout/main.xml b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/layout/main.xml similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/layout/main.xml rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/layout/main.xml diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/layout/project_chooser.xml b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/layout/project_chooser.xml similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/layout/project_chooser.xml rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/layout/project_chooser.xml diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/layout/project_empty.xml b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/layout/project_empty.xml similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/layout/project_empty.xml rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/layout/project_empty.xml diff --git a/pythonforandroid/bootstraps/sdl2/build/src/main/res/mipmap/.gitkeep b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/mipmap-anydpi-v26/.gitkeep similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/src/main/res/mipmap/.gitkeep rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/mipmap-anydpi-v26/.gitkeep diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/assets/.gitkeep b/pythonforandroid/bootstraps/_sdl_common/build/src/main/res/mipmap/.gitkeep similarity index 100% rename from pythonforandroid/bootstraps/sdl3/build/src/main/assets/.gitkeep rename to pythonforandroid/bootstraps/_sdl_common/build/src/main/res/mipmap/.gitkeep diff --git a/pythonforandroid/bootstraps/sdl2/build/templates/AndroidManifest.tmpl.xml b/pythonforandroid/bootstraps/_sdl_common/build/templates/AndroidManifest.tmpl.xml similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/templates/AndroidManifest.tmpl.xml rename to pythonforandroid/bootstraps/_sdl_common/build/templates/AndroidManifest.tmpl.xml diff --git a/pythonforandroid/bootstraps/sdl2/build/templates/strings.tmpl.xml b/pythonforandroid/bootstraps/_sdl_common/build/templates/strings.tmpl.xml similarity index 100% rename from pythonforandroid/bootstraps/sdl2/build/templates/strings.tmpl.xml rename to pythonforandroid/bootstraps/_sdl_common/build/templates/strings.tmpl.xml diff --git a/pythonforandroid/bootstraps/common/build/build.py b/pythonforandroid/bootstraps/common/build/build.py index 255153e1e5..99c4ea24ab 100644 --- a/pythonforandroid/bootstraps/common/build/build.py +++ b/pythonforandroid/bootstraps/common/build/build.py @@ -20,6 +20,7 @@ from fnmatch import fnmatch import jinja2 +from pythonforandroid.bootstrap import SDL_BOOTSTRAPS from pythonforandroid.util import rmdir, ensure_dir, max_build_tool_version @@ -220,6 +221,10 @@ def compile_py_file(python_file, optimize_python=True): return ".".join([os.path.splitext(python_file)[0], "pyc"]) +def is_sdl_bootstrap(): + return get_bootstrap_name() in SDL_BOOTSTRAPS + + def make_package(args): # If no launcher is specified, require a main.py/main.pyc: if (get_bootstrap_name() != "sdl" or args.launcher is None) and \ @@ -541,7 +546,7 @@ def make_package(args): "debug": "debug" in args.build_mode, "native_services": args.native_services } - if get_bootstrap_name() in ["sdl2", "sdl3"]: + if is_sdl_bootstrap(): render_args["url_scheme"] = url_scheme render( @@ -596,7 +601,7 @@ def make_package(args): "args": args, "private_version": hashlib.sha1(private_version.encode()).hexdigest() } - if get_bootstrap_name() in ["sdl2", "sdl3"]: + if is_sdl_bootstrap(): render_args["url_scheme"] = url_scheme render( 'strings.tmpl.xml', @@ -769,7 +774,7 @@ def create_argument_parser(): ap.add_argument('--private', dest='private', help='the directory with the app source code files' + ' (containing your main.py entrypoint)', - required=(get_bootstrap_name() not in ["sdl2", "sdl3"])) + required=(not is_sdl_bootstrap())) ap.add_argument('--package', dest='package', help=('The name of the java package the project will be' ' packaged under.'), @@ -787,7 +792,7 @@ def create_argument_parser(): 'same number of groups of numbers as previous ' 'versions.'), required=True) - if get_bootstrap_name() in ["sdl2", "sdl3"]: + if is_sdl_bootstrap(): ap.add_argument('--launcher', dest='launcher', action='store_true', help=('Provide this argument to build a multi-app ' 'launcher, rather than a single app.')) @@ -1044,7 +1049,7 @@ def _read_configuration(): args.orientation, args.manifest_orientation ) - if get_bootstrap_name() in ["sdl2", "sdl3"]: + if is_sdl_bootstrap(): args.sdl_orientation_hint = get_sdl_orientation_hint(args.orientation) if args.res_xmls and isinstance(args.res_xmls[0], list): @@ -1073,8 +1078,7 @@ def _read_configuration(): if x.strip() and not x.strip().startswith('#')] WHITELIST_PATTERNS += patterns - if args.private is None and \ - get_bootstrap_name() in ['sdl2', 'sdl3'] and args.launcher is None: + if args.private is None and is_sdl_bootstrap() and args.launcher is None: print('Need --private directory or ' + '--launcher (SDL2/SDL3 bootstrap only)' + 'to have something to launch inside the .apk!') diff --git a/pythonforandroid/bootstraps/sdl2/__init__.py b/pythonforandroid/bootstraps/sdl2/__init__.py index 9334724a33..0be9f9a23b 100644 --- a/pythonforandroid/bootstraps/sdl2/__init__.py +++ b/pythonforandroid/bootstraps/sdl2/__init__.py @@ -1,54 +1,12 @@ -from os.path import join +from pythonforandroid.bootstraps._sdl_common import SDLGradleBootstrap -import sh -from pythonforandroid.toolchain import ( - Bootstrap, shprint, current_directory, info, info_main) -from pythonforandroid.util import ensure_dir, rmdir - - -class SDL2GradleBootstrap(Bootstrap): - name = 'sdl2' +class SDL2GradleBootstrap(SDLGradleBootstrap): + name = "sdl2" recipe_depends = list( - set(Bootstrap.recipe_depends).union({'sdl2'}) + set(SDLGradleBootstrap.recipe_depends).union({"sdl2"}) ) - def assemble_distribution(self): - info_main("# Creating Android project ({})".format(self.name)) - - rmdir(self.dist_dir) - info("Copying SDL2/gradle build") - shprint(sh.cp, "-r", self.build_dir, self.dist_dir) - - # either the build use environment variable (ANDROID_HOME) - # or the local.properties if exists - with current_directory(self.dist_dir): - with open('local.properties', 'w') as fileh: - fileh.write('sdk.dir={}'.format(self.ctx.sdk_dir)) - - with current_directory(self.dist_dir): - info("Copying Python distribution") - - self.distribute_javaclasses(self.ctx.javaclass_dir, - dest_dir=join("src", "main", "java")) - - for arch in self.ctx.archs: - python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle') - ensure_dir(python_bundle_dir) - - self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)]) - site_packages_dir = self.ctx.python_recipe.create_python_bundle( - join(self.dist_dir, python_bundle_dir), arch) - if not self.ctx.with_debug_symbols: - self.strip_libraries(arch) - self.fry_eggs(site_packages_dir) - - if 'sqlite3' not in self.ctx.recipe_build_order: - with open('blacklist.txt', 'a') as fileh: - fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n') - - super().assemble_distribution() - bootstrap = SDL2GradleBootstrap() diff --git a/pythonforandroid/bootstraps/sdl3/__init__.py b/pythonforandroid/bootstraps/sdl3/__init__.py index fee87603a8..83f50493f7 100644 --- a/pythonforandroid/bootstraps/sdl3/__init__.py +++ b/pythonforandroid/bootstraps/sdl3/__init__.py @@ -1,56 +1,12 @@ -from os.path import join +from pythonforandroid.bootstraps._sdl_common import SDLGradleBootstrap -import sh -from pythonforandroid.toolchain import ( - Bootstrap, shprint, current_directory, info, info_main) -from pythonforandroid.util import ensure_dir, rmdir - - -class SDL3GradleBootstrap(Bootstrap): - name = 'sdl3' - - conflicts = ['sdl2'] +class SDL3GradleBootstrap(SDLGradleBootstrap): + name = "sdl3" recipe_depends = list( - set(Bootstrap.recipe_depends).union({'sdl3'}) + set(SDLGradleBootstrap.recipe_depends).union({"sdl3"}) ) - def assemble_distribution(self): - info_main("# Creating Android project ({})".format(self.name)) - - rmdir(self.dist_dir) - info("Copying SDL3/gradle build") - shprint(sh.cp, "-r", self.build_dir, self.dist_dir) - - # either the build use environment variable (ANDROID_HOME) - # or the local.properties if exists - with current_directory(self.dist_dir): - with open('local.properties', 'w') as fileh: - fileh.write('sdk.dir={}'.format(self.ctx.sdk_dir)) - - with current_directory(self.dist_dir): - info("Copying Python distribution") - - self.distribute_javaclasses(self.ctx.javaclass_dir, - dest_dir=join("src", "main", "java")) - - for arch in self.ctx.archs: - python_bundle_dir = join(f'_python_bundle__{arch.arch}', '_python_bundle') - ensure_dir(python_bundle_dir) - - self.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)]) - site_packages_dir = self.ctx.python_recipe.create_python_bundle( - join(self.dist_dir, python_bundle_dir), arch) - if not self.ctx.with_debug_symbols: - self.strip_libraries(arch) - self.fry_eggs(site_packages_dir) - - if 'sqlite3' not in self.ctx.recipe_build_order: - with open('blacklist.txt', 'a') as fileh: - fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n') - - super().assemble_distribution() - bootstrap = SDL3GradleBootstrap() diff --git a/pythonforandroid/bootstraps/sdl3/build/.gitignore b/pythonforandroid/bootstraps/sdl3/build/.gitignore deleted file mode 100644 index a1fc39c070..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -.gradle -/build/ - -# Ignore Gradle GUI config -gradle-app.setting - -# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) -!gradle-wrapper.jar - -# Cache of project -.gradletasknamecache - -# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 -# gradle/wrapper/gradle-wrapper.properties diff --git a/pythonforandroid/bootstraps/sdl3/build/blacklist.txt b/pythonforandroid/bootstraps/sdl3/build/blacklist.txt deleted file mode 100644 index d5e230c89a..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/blacklist.txt +++ /dev/null @@ -1,84 +0,0 @@ -# prevent user to include invalid extensions -*.apk -*.aab -*.apks -*.pxd - -# eggs -*.egg-info - -# unit test -unittest/* - -# python config -config/makesetup - -# unused kivy files (platform specific) -kivy/input/providers/wm_* -kivy/input/providers/mactouch* -kivy/input/providers/probesysfs* -kivy/input/providers/mtdev* -kivy/input/providers/hidinput* -kivy/core/camera/camera_videocapture* -kivy/core/spelling/*osx* -kivy/core/video/video_pyglet* -kivy/tools -kivy/tests/* -kivy/*/*.h -kivy/*/*.pxi - -# unused encodings -lib-dynload/*codec* -encodings/cp*.pyo -encodings/tis* -encodings/shift* -encodings/bz2* -encodings/iso* -encodings/undefined* -encodings/johab* -encodings/p* -encodings/m* -encodings/euc* -encodings/k* -encodings/unicode_internal* -encodings/quo* -encodings/gb* -encodings/big5* -encodings/hp* -encodings/hz* - -# unused python modules -bsddb/* -wsgiref/* -hotshot/* -pydoc_data/* -tty.pyo -anydbm.pyo -nturl2path.pyo -LICENCE.txt -macurl2path.pyo -dummy_threading.pyo -audiodev.pyo -antigravity.pyo -dumbdbm.pyo -sndhdr.pyo -__phello__.foo.pyo -sunaudio.pyo -os2emxpath.pyo -multiprocessing/dummy* - -# unused binaries python modules -lib-dynload/termios.so -lib-dynload/_lsprof.so -lib-dynload/*audioop.so -lib-dynload/_hotshot.so -lib-dynload/_heapq.so -lib-dynload/_json.so -lib-dynload/grp.so -lib-dynload/resource.so -lib-dynload/pyexpat.so -lib-dynload/_ctypes_test.so -lib-dynload/_testcapi.so - -# odd files -plat-linux3/regen diff --git a/pythonforandroid/bootstraps/sdl3/build/jni/Application.mk b/pythonforandroid/bootstraps/sdl3/build/jni/Application.mk deleted file mode 100644 index 15598537ca..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/jni/Application.mk +++ /dev/null @@ -1,8 +0,0 @@ - -# Uncomment this if you're using STL in your project -# See CPLUSPLUS-SUPPORT.html in the NDK documentation for more information -# APP_STL := stlport_static - -# APP_ABI := armeabi armeabi-v7a x86 -APP_ABI := $(ARCH) -APP_PLATFORM := $(NDK_API) diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/java/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java deleted file mode 100644 index 58a1c5edf8..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiver.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.kivy.android; - -import android.content.BroadcastReceiver; -import android.content.Intent; -import android.content.Context; - -public class GenericBroadcastReceiver extends BroadcastReceiver { - - GenericBroadcastReceiverCallback listener; - - public GenericBroadcastReceiver(GenericBroadcastReceiverCallback listener) { - super(); - this.listener = listener; - } - - public void onReceive(Context context, Intent intent) { - this.listener.onReceive(context, intent); - } -} diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java deleted file mode 100644 index 1a87c98b2d..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/GenericBroadcastReceiverCallback.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.kivy.android; - -import android.content.Intent; -import android.content.Context; - -public interface GenericBroadcastReceiverCallback { - void onReceive(Context context, Intent intent); -}; diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/Project.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/Project.java deleted file mode 100644 index 9177b43bb7..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/Project.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.kivy.android.launcher; - -import java.io.UnsupportedEncodingException; -import java.io.File; -import java.io.FileInputStream; -import java.util.Properties; - -import android.util.Log; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; - - -/** - * This represents a project we've scanned for. - */ -public class Project { - - public String dir = null; - String title = null; - String author = null; - Bitmap icon = null; - public boolean landscape = false; - - static String decode(String s) { - try { - return new String(s.getBytes("ISO-8859-1"), "UTF-8"); - } catch (UnsupportedEncodingException e) { - return s; - } - } - - /** - * Scans directory for a android.txt file. If it finds one, - * and it looks valid enough, then it creates a new Project, - * and returns that. Otherwise, returns null. - */ - public static Project scanDirectory(File dir) { - - // We might have a link file. - if (dir.getAbsolutePath().endsWith(".link")) { - try { - - // Scan the android.txt file. - File propfile = new File(dir, "android.txt"); - FileInputStream in = new FileInputStream(propfile); - Properties p = new Properties(); - p.load(in); - in.close(); - - String directory = p.getProperty("directory", null); - - if (directory == null) { - return null; - } - - dir = new File(directory); - - } catch (Exception e) { - Log.i("Project", "Couldn't open link file " + dir, e); - } - } - - // Make sure we're dealing with a directory. - if (! dir.isDirectory()) { - return null; - } - - try { - - // Scan the android.txt file. - File propfile = new File(dir, "android.txt"); - FileInputStream in = new FileInputStream(propfile); - Properties p = new Properties(); - p.load(in); - in.close(); - - // Get the various properties. - String title = decode(p.getProperty("title", "Untitled")); - String author = decode(p.getProperty("author", "")); - boolean landscape = p.getProperty("orientation", "portrait").equals("landscape"); - - // Create the project object. - Project rv = new Project(); - rv.title = title; - rv.author = author; - rv.icon = BitmapFactory.decodeFile(new File(dir, "icon.png").getAbsolutePath()); - rv.landscape = landscape; - rv.dir = dir.getAbsolutePath(); - - return rv; - - } catch (Exception e) { - Log.i("Project", "Couldn't open android.txt", e); - } - - return null; - - } -} diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java deleted file mode 100644 index 457f83f79b..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectAdapter.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.kivy.android.launcher; - -import android.app.Activity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TextView; -import android.widget.ImageView; - -import org.renpy.android.ResourceManager; - -public class ProjectAdapter extends ArrayAdapter { - - private ResourceManager resourceManager; - - public ProjectAdapter(Activity context) { - super(context, 0); - resourceManager = new ResourceManager(context); - } - - public View getView(int position, View convertView, ViewGroup parent) { - Project p = getItem(position); - - View v = resourceManager.inflateView("chooser_item"); - TextView title = (TextView) resourceManager.getViewById(v, "title"); - TextView author = (TextView) resourceManager.getViewById(v, "author"); - ImageView icon = (ImageView) resourceManager.getViewById(v, "icon"); - - title.setText(p.title); - author.setText(p.author); - icon.setImageBitmap(p.icon); - - return v; - } -} diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java b/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java deleted file mode 100644 index 486f88bae4..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/src/main/java/org/kivy/android/launcher/ProjectChooser.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.kivy.android.launcher; - -import android.app.Activity; - -import android.content.Intent; -import android.view.View; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.AdapterView; -import android.os.Environment; - -import java.io.File; -import java.util.Arrays; -import android.net.Uri; - -import org.renpy.android.ResourceManager; - -public class ProjectChooser extends Activity implements AdapterView.OnItemClickListener { - - ResourceManager resourceManager; - - String urlScheme; - - @Override - public void onStart() - { - super.onStart(); - - resourceManager = new ResourceManager(this); - - urlScheme = resourceManager.getString("urlScheme"); - - // Set the window title. - setTitle(resourceManager.getString("appName")); - - // Scan the sdcard for files, and sort them. - File dir = new File(Environment.getExternalStorageDirectory(), urlScheme); - - File entries[] = dir.listFiles(); - - if (entries == null) { - entries = new File[0]; - } - - Arrays.sort(entries); - - // Create a ProjectAdapter and fill it with projects. - ProjectAdapter projectAdapter = new ProjectAdapter(this); - - // Populate it with the properties files. - for (File d : entries) { - Project p = Project.scanDirectory(d); - if (p != null) { - projectAdapter.add(p); - } - } - - if (projectAdapter.getCount() != 0) { - - View v = resourceManager.inflateView("project_chooser"); - ListView l = (ListView) resourceManager.getViewById(v, "projectList"); - - l.setAdapter(projectAdapter); - l.setOnItemClickListener(this); - - setContentView(v); - - } else { - - View v = resourceManager.inflateView("project_empty"); - TextView emptyText = (TextView) resourceManager.getViewById(v, "emptyText"); - - emptyText.setText("No projects are available to launch. Please place a project into " + dir + " and restart this application. Press the back button to exit."); - - setContentView(v); - } - } - - public void onItemClick(AdapterView parent, View view, int position, long id) { - Project p = (Project) parent.getItemAtPosition(position); - - Intent intent = new Intent( - "org.kivy.LAUNCH", - Uri.fromParts(urlScheme, p.dir, "")); - - intent.setClassName(getPackageName(), "org.kivy.android.PythonActivity"); - this.startActivity(intent); - this.finish(); - } -} diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/jniLibs/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/jniLibs/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/libs/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/libs/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-hdpi/ic_launcher.png b/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index d50bdaae06ee5a8d3f39911f81715abd3bf7b24d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2683 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 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-mdpi/ic_launcher.png b/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index 0a299eb3cc0273ad1fc260cf0b4a2c35f5d373f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1698 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 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-xxhdpi/ic_launcher.png b/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable-xxhdpi/ic_launcher.png deleted file mode 100644 index d423dac2624cf0b5dc90821a15362bc29e5a1e6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6874 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 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/res/drawable/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/chooser_item.xml b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/chooser_item.xml deleted file mode 100644 index 1823b13223..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/chooser_item.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/main.xml b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/main.xml deleted file mode 100644 index 123c4b6eac..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/main.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_chooser.xml b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_chooser.xml deleted file mode 100644 index 23828e644b..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_chooser.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_empty.xml b/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_empty.xml deleted file mode 100644 index ee5481421d..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/src/main/res/layout/project_empty.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap-anydpi-v26/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap-anydpi-v26/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap/.gitkeep b/pythonforandroid/bootstraps/sdl3/build/src/main/res/mipmap/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pythonforandroid/bootstraps/sdl3/build/templates/AndroidManifest.tmpl.xml b/pythonforandroid/bootstraps/sdl3/build/templates/AndroidManifest.tmpl.xml deleted file mode 100644 index c31bb3f747..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/templates/AndroidManifest.tmpl.xml +++ /dev/null @@ -1,144 +0,0 @@ - - - - - = 9 %} - android:xlargeScreens="true" - {% endif %} - /> - - - - - - - - - {% for perm in args.permissions %} - - {% endfor %} - - {% if args.wakelock %} - - {% endif %} - - {% if args.billing_pubkey %} - - {% endif %} - - {{ args.extra_manifest_xml }} - - - - - {% for l in args.android_used_libs %} - - {% endfor %} - - {% for m in args.meta_data %} - {% endfor %} - - - - - - {% if args.launcher %} - - - - {% else %} - - - {% endif %} - - {% if args.home_app %} - - - {% endif %} - - - {%- if args.intent_filters -%} - {{- args.intent_filters -}} - {%- endif -%} - - - {% if args.launcher %} - - - - - - - - - {% endif %} - - {% if service or args.launcher %} - - {% endif %} - {% for name in service_names %} - - {% endfor %} - {% for name in native_services %} - - {% endfor %} - - {% if args.billing_pubkey %} - - - - - - - - - {% endif %} - {% for a in args.add_activity %} - - {% endfor %} - - - diff --git a/pythonforandroid/bootstraps/sdl3/build/templates/strings.tmpl.xml b/pythonforandroid/bootstraps/sdl3/build/templates/strings.tmpl.xml deleted file mode 100644 index 17e376adbd..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/templates/strings.tmpl.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - {{ args.name }} - {{ private_version }} - {{ args.presplash_color }} - {{ url_scheme }} - diff --git a/pythonforandroid/recipes/sdl3/__init__.py b/pythonforandroid/recipes/sdl3/__init__.py index f22884deda..6b9c8ee7c6 100644 --- a/pythonforandroid/recipes/sdl3/__init__.py +++ b/pythonforandroid/recipes/sdl3/__init__.py @@ -6,9 +6,11 @@ class LibSDL3Recipe(BootstrapNDKRecipe): - version = "3.2.8" + version = "3.2.10" url = "https://github.com/libsdl-org/SDL/releases/download/release-{version}/SDL3-{version}.tar.gz" - # md5sum = 'a344eb827a03045c9b399e99af4af13d' + md5sum = "70cda886bcf5a4fdac550db796d2efa2" + + conflicts = ["sdl2"] dir_name = "SDL" diff --git a/pythonforandroid/recipes/sdl3_ttf/__init__.py b/pythonforandroid/recipes/sdl3_ttf/__init__.py index f291f69667..a0ebfac7a5 100644 --- a/pythonforandroid/recipes/sdl3_ttf/__init__.py +++ b/pythonforandroid/recipes/sdl3_ttf/__init__.py @@ -6,7 +6,7 @@ class LibSDL3TTF(BootstrapNDKRecipe): - version = "3.2.0" + version = "3.2.2" url = "https://github.com/libsdl-org/SDL_ttf/releases/download/release-{version}/SDL3_ttf-{version}.tar.gz" dir_name = "SDL3_ttf" diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index ffb4942f15..fc15bd45e6 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -356,13 +356,13 @@ def bootstrap_name(self): @mock.patch("pythonforandroid.bootstraps.qt.open", create=True) @mock.patch("pythonforandroid.bootstraps.service_only.open", create=True) @mock.patch("pythonforandroid.bootstraps.webview.open", create=True) - @mock.patch("pythonforandroid.bootstraps.sdl2.open", create=True) + @mock.patch("pythonforandroid.bootstraps._sdl_common.open", create=True) @mock.patch("pythonforandroid.distribution.open", create=True) @mock.patch("pythonforandroid.bootstrap.Bootstrap.strip_libraries") @mock.patch("pythonforandroid.util.exists") @mock.patch("pythonforandroid.util.chdir") @mock.patch("pythonforandroid.bootstrap.listdir") - @mock.patch("pythonforandroid.bootstraps.sdl2.rmdir") + @mock.patch("pythonforandroid.bootstraps._sdl_common.rmdir") @mock.patch("pythonforandroid.bootstraps.service_only.rmdir") @mock.patch("pythonforandroid.bootstraps.webview.rmdir") @mock.patch("pythonforandroid.bootstrap.sh.cp") @@ -377,7 +377,7 @@ def test_assemble_distribution( mock_ensure_dir, mock_strip_libraries, mock_open_dist_files, - mock_open_sdl2_files, + mock_open_sdl_files, mock_open_webview_files, mock_open_service_only_files, mock_open_qt_files @@ -418,7 +418,8 @@ def test_assemble_distribution( mock_open_dist_files.assert_called_once_with("dist_info.json", "w") mock_open_bootstraps = { - "sdl2": mock_open_sdl2_files, + "sdl2": mock_open_sdl_files, + "sdl3": mock_open_sdl_files, "webview": mock_open_webview_files, "service_only": mock_open_service_only_files, "qt": mock_open_qt_files @@ -428,6 +429,10 @@ def test_assemble_distribution( mock.call("local.properties", "w"), mock.call("blacklist.txt", "a"), ], + "sdl3": [ + mock.call("local.properties", "w"), + mock.call("blacklist.txt", "a"), + ], "webview": [mock.call("local.properties", "w")], "service_only": [mock.call("local.properties", "w")], "qt": [mock.call("local.properties", "w")] @@ -441,7 +446,7 @@ def test_assemble_distribution( mock.call().__enter__().write("sdk.dir=/opt/android/android-sdk"), mock_open_bs.mock_calls, ) - if self.bootstrap_name == "sdl2": + if self.bootstrap_name in ["sdl2", "sdl3"]: self.assertIn( mock.call() .__enter__() @@ -624,6 +629,18 @@ def bootstrap_name(self): return "sdl2" +class TestBootstrapSdl3(GenericBootstrapTest, unittest.TestCase): + """ + An inherited class of `GenericBootstrapTest` and `unittest.TestCase` which + will be used to perform tests for + :class:`~pythonforandroid.bootstraps.sdl3.BootstrapSdl3`. + """ + + @property + def bootstrap_name(self): + return "sdl3" + + class TestBootstrapServiceOnly(GenericBootstrapTest, unittest.TestCase): """ An inherited class of `GenericBootstrapTest` and `unittest.TestCase` which diff --git a/tests/test_build.py b/tests/test_build.py index 49f6311621..57db29b148 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -82,7 +82,7 @@ def test_android_manifest_xml(self): "native_services": args.native_services } environment = jinja2.Environment( - loader=jinja2.FileSystemLoader('pythonforandroid/bootstraps/sdl2/build/templates/') + loader=jinja2.FileSystemLoader('pythonforandroid/bootstraps/_sdl_common/build/templates/') ) template = environment.get_template('AndroidManifest.tmpl.xml') xml = template.render(**render_args)