diff --git a/direct/src/dist/FreezeTool.py b/direct/src/dist/FreezeTool.py index 678f8c0888..aad6dc4b24 100644 --- a/direct/src/dist/FreezeTool.py +++ b/direct/src/dist/FreezeTool.py @@ -925,7 +925,22 @@ class Freezer: if sys.version_info < (3, 8): abi_flags += 'm' - if 'linux' in self.platform: + if 'android' in self.platform: + arch = self.platform.split('_', 1)[1] + if arch in ('arm64', 'aarch64'): + suffixes.append(('.cpython-{0}{1}-aarch64-linux-android.so'.format(abi_version, abi_flags), 'rb', 3)) + elif arch in ('arm', 'armv7l'): + suffixes.append(('.cpython-{0}{1}-arm-linux-androideabi.so'.format(abi_version, abi_flags), 'rb', 3)) + elif arch in ('x86_64', 'amd64'): + suffixes.append(('.cpython-{0}{1}-x86_64-linux-android.so'.format(abi_version, abi_flags), 'rb', 3)) + elif arch in ('i386', 'i686'): + suffixes.append(('.cpython-{0}{1}-i686-linux-android.so'.format(abi_version, abi_flags), 'rb', 3)) + + suffixes += [ + ('.abi{0}.so'.format(sys.version_info[0]), 'rb', 3), + ('.so', 'rb', 3), + ] + elif 'linux' in self.platform: suffixes += [ ('.cpython-{0}{1}-x86_64-linux-gnu.so'.format(abi_version, abi_flags), 'rb', 3), ('.cpython-{0}{1}-i686-linux-gnu.so'.format(abi_version, abi_flags), 'rb', 3), @@ -1150,6 +1165,9 @@ class Freezer: self.modules['_frozen_importlib'] = self.ModuleDef('importlib._bootstrap', implicit = True) self.modules['_frozen_importlib_external'] = self.ModuleDef('importlib._bootstrap_external', implicit = True) + if self.platform.startswith('android'): + self.modules['_android_support'] = self.ModuleDef('_android_support', implicit = True) + for moduleName in startupModules: if moduleName not in self.modules: self.addModule(moduleName, implicit = True) diff --git a/direct/src/dist/_android.py b/direct/src/dist/_android.py index ac6a8c85b9..bebb7bf9df 100644 --- a/direct/src/dist/_android.py +++ b/direct/src/dist/_android.py @@ -50,7 +50,7 @@ def flag_resource(id, **values): bitmask = 0 flags = attrib.value.split('|') for flag in flags: - bitmask = values[flag] + bitmask |= values[flag] attrib.compiled_item.prim.int_hexadecimal_value = bitmask return compile @@ -168,10 +168,11 @@ ANDROID_ATTRIBUTES = { 'allowSingleTap': bool_resource(0x1010259), 'allowTaskReparenting': bool_resource(0x1010204), 'alwaysRetainTaskState': bool_resource(0x1010203), + 'appCategory': enum_resource(0x01010545, "game", "audio", "video", "image", "social", "news", "maps", "productivity", "accessibility"), 'clearTaskOnLaunch': bool_resource(0x1010015), + 'configChanges': flag_resource(0x0101001f, mcc=0x0001, mnc=0x0002, locale=0x0004, touchscreen=0x0008, keyboard=0x0010, keyboardHidden=0x0020, navigation=0x0040, orientation=0x0080, screenLayout=0x0100, uiMode=0x0200, screenSize=0x0400, smallestScreenSize=0x0800, layoutDirection=0x2000, colorMode=0x4000, grammaticalGender=0x8000, fontScale=0x40000000, fontWeightAdjustment=0x10000000), 'debuggable': bool_resource(0x0101000f), 'documentLaunchMode': enum_resource(0x1010445, "none", "intoExisting", "always", "never"), - 'configChanges': flag_resource(0x0101001f, mcc=0x0001, mnc=0x0002, locale=0x0004, touchscreen=0x0008, keyboard=0x0010, keyboardHidden=0x0020, navigation=0x0040, orientation=0x0080, screenLayout=0x0100, uiMode=0x0200, screenSize=0x0400, smallestScreenSize=0x0800, layoutDirection=0x2000, fontScale=0x40000000), 'enabled': bool_resource(0x101000e), 'excludeFromRecents': bool_resource(0x1010017), 'exported': bool_resource(0x1010010), @@ -179,6 +180,7 @@ ANDROID_ATTRIBUTES = { 'finishOnTaskLaunch': bool_resource(0x1010014), 'fullBackupContent': bool_resource(0x10104eb), 'glEsVersion': int_resource(0x1010281), + 'hardwareAccelerated': bool_resource(0x10102d3), 'hasCode': bool_resource(0x101000c), 'host': str_resource(0x1010028), 'icon': ref_resource(0x1010002), @@ -194,8 +196,9 @@ ANDROID_ATTRIBUTES = { 'name': str_resource(0x1010003), 'noHistory': bool_resource(0x101022d), 'pathPattern': str_resource(0x101002c), - 'resizeableActivity': bool_resource(0x10104f6), + 'preferMinimalPostProcessing': bool_resource(0x101060c), 'required': bool_resource(0x101028e), + 'resizeableActivity': bool_resource(0x10104f6), 'scheme': str_resource(0x1010027), 'screenOrientation': enum_resource(0x101001e, 'landscape', 'portrait', 'user', 'behind', 'sensor', 'nosensor', 'sensorLandscape', 'sensorPortrait', 'reverseLandscape', 'reversePortrait', 'fullSensor', 'userLandscape', 'userPortrait', 'fullUser', 'locked'), 'stateNotNeeded': bool_resource(0x1010016), diff --git a/direct/src/dist/commands.py b/direct/src/dist/commands.py index 5f12b7fe4b..cfddcd89af 100644 --- a/direct/src/dist/commands.py +++ b/direct/src/dist/commands.py @@ -188,11 +188,26 @@ FrozenImporter.get_data = get_data """ SITE_PY_ANDROID = """ +# Define this first, before we import anything that might import an extension +# module. import sys, os +from importlib import _bootstrap, _bootstrap_external + +class AndroidExtensionFinder: + @classmethod + def find_spec(cls, fullname, path=None, target=None): + soname = 'libpy.' + fullname + '.so' + path = os.path.join(sys.platlibdir, soname) + + if os.path.exists(path): + loader = _bootstrap_external.ExtensionFileLoader(fullname, path) + return _bootstrap.ModuleSpec(fullname, loader, origin=path) + + +sys.meta_path.append(AndroidExtensionFinder) + + from _frozen_importlib import _imp, FrozenImporter -from importlib import _bootstrap_external -from importlib.abc import Loader, MetaPathFinder -from importlib.machinery import ModuleSpec from io import RawIOBase, TextIOWrapper from android_log import write as android_log_write @@ -242,8 +257,9 @@ class AndroidLogStream: def writable(self): return True -sys.stdout = AndroidLogStream(2, 'Python') -sys.stderr = AndroidLogStream(3, 'Python') +if sys.version_info < (3, 13): + sys.stdout = AndroidLogStream(4, 'python.stdout') + sys.stderr = AndroidLogStream(5, 'python.stderr') # Alter FrozenImporter to give a __file__ property to frozen modules. @@ -262,20 +278,6 @@ def get_data(path): FrozenImporter.find_spec = find_spec FrozenImporter.get_data = get_data - - -class AndroidExtensionFinder(MetaPathFinder): - @classmethod - def find_spec(cls, fullname, path=None, target=None): - soname = 'libpy.' + fullname + '.so' - path = os.path.join(os.path.dirname(sys.executable), soname) - - if os.path.exists(path): - loader = _bootstrap_external.ExtensionFileLoader(fullname, path) - return ModuleSpec(fullname, loader, origin=path) - - -sys.meta_path.append(AndroidExtensionFinder) """ @@ -294,6 +296,7 @@ class build_apps(setuptools.Command): self.application_id = None self.android_abis = None self.android_debuggable = False + self.android_app_category = None self.android_version_code = 1 self.android_min_sdk_version = 21 self.android_max_sdk_version = None @@ -516,6 +519,18 @@ class build_apps(setuptools.Command): tmp.update(self.package_data_dirs) self.package_data_dirs = tmp + if 'android' in self.platforms: + assert self.application_id, \ + 'Must have a valid application_id when targeting Android!' + + parts = self.application_id.split('.') + assert len(parts) >= 2, \ + 'application_id must contain at least one \'.\' separator!' + + for part in parts: + assert part.isidentifier(), \ + 'Each part of application_id must be a valid identifier!' + # Default to all supported ABIs (for the given Android version). if self.android_max_sdk_version and self.android_max_sdk_version < 21: assert self.android_max_sdk_version >= 19, \ @@ -782,10 +797,29 @@ class build_apps(setuptools.Command): version = self.distribution.get_version() classifiers = self.distribution.get_classifiers() - is_game = False - for classifier in classifiers: - if classifier == 'Topic :: Games/Entertainment' or classifier.startswith('Topic :: Games/Entertainment ::'): - is_game = True + # If we have no app category, determine it based on the classifiers. + category = self.android_app_category + if not category: + for classifier in classifiers: + classifier = tuple(classifier.split(' :: ')) + if len(classifier) < 2 or classifier[0] != 'Topic': + continue + + if classifier[:2] == ('Topic', 'Games/Entertainment'): + category = 'game' + break + elif classifier[:3] == ('Topic', 'Multimedia', 'Audio'): + category = 'audio' + elif classifier[:4] == ('Topic', 'Multimedia', 'Graphics', 'Editors'): + category = 'image' + elif classifier[:2] == ('Topic', 'Communications', 'Usenet News'): + category = 'news' + elif classifier[:2] == ('Topic', 'Office/Business'): + category = 'productivity' + elif classifier[:3] == ('Topic', 'Communications', 'Chat'): + category = 'social' + elif classifier[:3] == ('Topic', 'Multimedia', 'Video'): + category = 'video' manifest = ET.Element('manifest') manifest.set('xmlns:android', 'http://schemas.android.com/apk/res/android') @@ -816,9 +850,13 @@ class build_apps(setuptools.Command): application = ET.SubElement(manifest, 'application') application.set('android:label', name) - application.set('android:isGame', ('false', 'true')[is_game]) + if category == 'game': + application.set('android:isGame', 'true') + if category: + application.set('android:appCategory', category) application.set('android:debuggable', ('false', 'true')[self.android_debuggable]) application.set('android:extractNativeLibs', 'true') + application.set('android:hardwareAccelerated', 'true') app_icon = self.icon_objects.get('*', self.icon_objects.get(self.macos_main_app)) if app_icon: @@ -828,9 +866,11 @@ class build_apps(setuptools.Command): activity = ET.SubElement(application, 'activity') activity.set('android:name', 'org.panda3d.android.PythonActivity') activity.set('android:label', appname) - activity.set('android:theme', '@android:style/Theme.NoTitleBar') - activity.set('android:configChanges', 'orientation|keyboardHidden') + activity.set('android:theme', '@android:style/Theme.NoTitleBar.Fullscreen') + activity.set('android:alwaysRetainTaskState', 'true') + activity.set('android:configChanges', 'layoutDirection|locale|grammaticalGender|fontScale|fontWeightAdjustment|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation') activity.set('android:launchMode', 'singleInstance') + activity.set('android:preferMinimalPostProcessing', 'true') act_icon = self.icon_objects.get(appname) if act_icon and act_icon is not app_icon: diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 71ed125746..0ffbc6fba8 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -679,7 +679,7 @@ class ShowBase(DirectObject.DirectObject): complete. """ - if Thread.getCurrentThread() != Thread.getMainThread(): + if sys.platform != "android" and Thread.getCurrentThread() != Thread.getMainThread(): task = taskMgr.add(self.destroy, extraArgs=[]) task.wait() return @@ -3439,7 +3439,7 @@ class ShowBase(DirectObject.DirectObject): This method must be called from the main thread, otherwise an error is thrown. """ - if Thread.getCurrentThread() != Thread.getMainThread(): + if Thread.getCurrentThread() != Thread.getMainThread() and sys.platform != "android": self.notify.error("run() must be called from the main thread.") return diff --git a/dtool/src/prc/notify.cxx b/dtool/src/prc/notify.cxx index 009c6ab818..ce7df151c6 100644 --- a/dtool/src/prc/notify.cxx +++ b/dtool/src/prc/notify.cxx @@ -467,12 +467,12 @@ config_initialized() { Notify *ptr = Notify::ptr(); - for (int i = 0; i <= NS_fatal; ++i) { + for (int severity = 0; severity <= NS_fatal; ++severity) { int priority = ANDROID_LOG_UNKNOWN; if (severity != NS_unspecified) { - priority = i + 1; + priority = severity + 1; } - ptr->_log_streams[i] = new AndroidLogStream(priority); + ptr->_log_streams[severity] = new AndroidLogStream(priority); } #elif defined(__EMSCRIPTEN__) diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index 26447c9b6d..a46684d7d0 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -866,7 +866,7 @@ def MakeInstallerAndroid(version, **kwargs): shutil.copy(source, target) # Walk through the library dependencies. - handle = subprocess.Popen(['readelf', '--dynamic', target], stdout=subprocess.PIPE) + handle = subprocess.Popen(['llvm-readelf', '--dynamic', target], stdout=subprocess.PIPE) for line in handle.communicate()[0].splitlines(): # The line will look something like: # 0x0000000000000001 (NEEDED) Shared library: [libpanda.so] diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 15d14cb04b..3d3ae9e6f1 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -2077,13 +2077,23 @@ def CompileJava(target, src, opts): if GetHost() == 'android': cmd = "ecj " else: - cmd = "javac -bootclasspath " + BracketNameWithQuotes(SDK["ANDROID_JAR"]) + " " + cmd = "javac " + home = os.environ.get('JAVA_HOME') + if home: + javac_path = os.path.join(home, 'bin', 'javac') + if GetHost() == 'windows': + javac_path += '.exe' + if os.path.isfile(javac_path): + cmd = BracketNameWithQuotes(javac_path) + " " + + cmd += "-Xlint:deprecation " optlevel = GetOptimizeOption(opts) if optlevel >= 4: cmd += "-debug:none " - cmd += "-cp " + GetOutputDir() + "/classes " + classpath = BracketNameWithQuotes(SDK["ANDROID_JAR"] + ":" + GetOutputDir() + "/classes") + cmd += "-cp " + classpath + " " cmd += "-d " + GetOutputDir() + "/classes " cmd += BracketNameWithQuotes(src) oscmd(cmd) @@ -4945,11 +4955,13 @@ if GetTarget() == 'android': TargetAdd('org/panda3d/android/NativeIStream.class', opts=OPTS, input='NativeIStream.java') TargetAdd('org/panda3d/android/NativeOStream.class', opts=OPTS, input='NativeOStream.java') TargetAdd('org/panda3d/android/PandaActivity.class', opts=OPTS, input='PandaActivity.java') + TargetAdd('org/panda3d/android/PandaActivity$1.class', opts=OPTS+['DEPENDENCYONLY'], input='PandaActivity.java') TargetAdd('org/panda3d/android/PythonActivity.class', opts=OPTS, input='PythonActivity.java') TargetAdd('classes.dex', input='org/panda3d/android/NativeIStream.class') TargetAdd('classes.dex', input='org/panda3d/android/NativeOStream.class') TargetAdd('classes.dex', input='org/panda3d/android/PandaActivity.class') + TargetAdd('classes.dex', input='org/panda3d/android/PandaActivity$1.class') TargetAdd('classes.dex', input='org/panda3d/android/PythonActivity.class') TargetAdd('p3android_composite1.obj', opts=OPTS, input='p3android_composite1.cxx') diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 3a4feb5b57..f34b847dec 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -1846,7 +1846,7 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None, DefSymbol(target_pkg, d, v) return - elif not custom_loc and GetHost() == "darwin" and framework is not None: + elif not custom_loc and GetHost() == "darwin" and GetTarget() == "darwin" and framework is not None: prefix = SDK["MACOSX"] if (os.path.isdir(prefix + "/Library/Frameworks/%s.framework" % framework) or os.path.isdir(prefix + "/System/Library/Frameworks/%s.framework" % framework) or @@ -2622,6 +2622,8 @@ def SdkLocateAndroid(): # We need to redistribute the C++ standard library. stdlibc = os.path.join(ndk_root, 'sources', 'cxx-stl', 'llvm-libc++') stl_lib = os.path.join(stdlibc, 'libs', abi, 'libc++_shared.so') + if not os.path.isfile(stl_lib): + stl_lib = os.path.join(prebuilt_dir, 'sysroot', 'usr', 'lib', ANDROID_TRIPLE.rstrip('0123456789'), 'libc++_shared.so') CopyFile(os.path.join(GetOutputDir(), 'lib', 'libc++_shared.so'), stl_lib) # The Android support library polyfills C++ features not available in the diff --git a/makepanda/makewheel.py b/makepanda/makewheel.py index bafda55f3f..1ccbc618b0 100644 --- a/makepanda/makewheel.py +++ b/makepanda/makewheel.py @@ -677,6 +677,7 @@ def makewheel(version, output_dir, platform=None): or platform.startswith('win_') \ or platform.startswith('cygwin_') is_macosx = platform.startswith('macosx_') + is_android = platform.startswith('android_') # Global filepaths panda3d_dir = join(output_dir, "panda3d") @@ -747,6 +748,9 @@ def makewheel(version, output_dir, platform=None): elif is_macosx: pylib_name = 'libpython{0}.{1}{2}.dylib'.format(sys.version_info[0], sys.version_info[1], suffix) pylib_path = os.path.join(get_config_var('LIBDIR'), pylib_name) + elif is_android and CrossCompiling(): + pylib_name = 'libpython{0}.{1}{2}.so'.format(sys.version_info[0], sys.version_info[1], suffix) + pylib_path = os.path.join(GetThirdpartyDir(), 'python', 'lib', pylib_name) else: pylib_name = get_config_var('LDLIBRARY') pylib_arch = get_config_var('MULTIARCH') diff --git a/panda/src/android/android_main.cxx b/panda/src/android/android_main.cxx index 13895d99f6..55355533c3 100644 --- a/panda/src/android/android_main.cxx +++ b/panda/src/android/android_main.cxx @@ -75,6 +75,7 @@ void android_main(struct android_app* app) { << "New native activity started on " << *current_thread << "\n"; // Were we given an optional location to write the stdout/stderr streams? + bool owns_stdout = false; methodID = env->GetMethodID(activity_class, "getIntentOutputUri", "()Ljava/lang/String;"); jstring joutput_uri = (jstring) env->CallObjectMethod(activity->clazz, methodID); if (joutput_uri != nullptr) { @@ -92,6 +93,7 @@ void android_main(struct android_app* app) { dup2(fd, 1); dup2(fd, 2); + owns_stdout = true; } else { android_cat.error() << "Failed to open output path " << path << "\n"; @@ -109,6 +111,7 @@ void android_main(struct android_app* app) { << spec.get_server_and_port() << "\n"; dup2(fd, 1); dup2(fd, 2); + owns_stdout = true; } else { android_cat.error() << "Failed to open output socket " @@ -267,11 +270,10 @@ void android_main(struct android_app* app) { // We still need to keep an event loop going until Android gives us leave // to end the process. - int looper_id; - int events; - struct android_poll_source *source; - while ((looper_id = ALooper_pollAll(-1, nullptr, &events, (void**)&source)) >= 0) { - // Process this event, but intercept application command events. + while (!app->destroyRequested) { + int looper_id; + struct android_poll_source *source; + auto result = ALooper_pollOnce(-1, &looper_id, nullptr, (void **)&source); if (looper_id == LOOPER_ID_MAIN) { int8_t cmd = android_app_read_cmd(app); android_app_pre_exec_cmd(app, cmd); @@ -300,8 +302,10 @@ void android_main(struct android_app* app) { env->ReleaseStringUTFChars(filename, filename_str); } - close(1); - close(2); + if (owns_stdout) { + close(1); + close(2); + } // Detach the thread before exiting. activity->vm->DetachCurrentThread(); diff --git a/panda/src/android/pview_manifest.xml b/panda/src/android/pview_manifest.xml index b462e4018a..e68dce5584 100644 --- a/panda/src/android/pview_manifest.xml +++ b/panda/src/android/pview_manifest.xml @@ -8,7 +8,7 @@ - + diff --git a/panda/src/androiddisplay/androidGraphicsWindow.cxx b/panda/src/androiddisplay/androidGraphicsWindow.cxx index b3a8ae425d..1cc59d8298 100644 --- a/panda/src/androiddisplay/androidGraphicsWindow.cxx +++ b/panda/src/androiddisplay/androidGraphicsWindow.cxx @@ -181,16 +181,14 @@ process_events() { GraphicsWindow::process_events(); // Read all pending events. - int looper_id; - int events; - struct android_poll_source* source; + struct android_poll_source *source; - // Loop until all events are read. - while ((looper_id = ALooper_pollAll(0, nullptr, &events, (void**)&source)) >= 0) { - // Process this event. - if (source != nullptr) { - source->process(_app, source); - } + auto result = ALooper_pollOnce(0, nullptr, nullptr, (void **)&source); + nassertv(result != ALOOPER_POLL_ERROR); + + // Process this event. + if (source != nullptr) { + source->process(_app, source); } } @@ -437,14 +435,15 @@ ns_handle_command(int32_t command) { case APP_CMD_WINDOW_RESIZED: properties.set_size(ANativeWindow_getWidth(_app->window), ANativeWindow_getHeight(_app->window)); + system_changed_properties(properties); break; case APP_CMD_WINDOW_REDRAW_NEEDED: break; case APP_CMD_CONTENT_RECT_CHANGED: - properties.set_origin(_app->contentRect.left, _app->contentRect.top); + /*properties.set_origin(_app->contentRect.left, _app->contentRect.top); properties.set_size(_app->contentRect.right - _app->contentRect.left, _app->contentRect.bottom - _app->contentRect.top); - system_changed_properties(properties); + system_changed_properties(properties);*/ break; case APP_CMD_GAINED_FOCUS: properties.set_foreground(true); diff --git a/panda/src/framework/pandaFramework.cxx b/panda/src/framework/pandaFramework.cxx index 6d249cdc56..32de3dda76 100644 --- a/panda/src/framework/pandaFramework.cxx +++ b/panda/src/framework/pandaFramework.cxx @@ -204,6 +204,8 @@ close_framework() { _event_handler.remove_all_hooks(); + _task_mgr.cleanup(); + _is_open = false; _made_default_pipe = false; _default_pipe.clear(); diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index eca73217b6..fc4ac4e7ad 100644 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -1653,11 +1653,11 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { (!cp_errchk_parameter_uniform(p))) { return false; } - bool k_prefix = false; + //bool k_prefix = false; // solve backward compatibility issue if (pieces[0] == "k") { - k_prefix = true; + //k_prefix = true; basename = basename.substr(2); } diff --git a/panda/src/pipeline/threadPosixImpl.I b/panda/src/pipeline/threadPosixImpl.I index 308dc3ede0..326868ab61 100644 --- a/panda/src/pipeline/threadPosixImpl.I +++ b/panda/src/pipeline/threadPosixImpl.I @@ -19,7 +19,7 @@ ThreadPosixImpl(Thread *parent_obj) : _parent_obj(parent_obj) { _joinable = false; - _detached = false; + _detached = true; _status = S_new; #ifdef ANDROID _jni_env = nullptr; diff --git a/panda/src/text/textAssembler.cxx b/panda/src/text/textAssembler.cxx index a98abb68b3..7e18b07d03 100644 --- a/panda/src/text/textAssembler.cxx +++ b/panda/src/text/textAssembler.cxx @@ -1479,7 +1479,7 @@ assemble_row(TextAssembler::TextRow &row, PN_stdfloat underscore_start = 0.0f; const TextProperties *underscore_properties = nullptr; -#ifdef HAVE_HARFBUZZ +#if defined(HAVE_HARFBUZZ) && defined(HAVE_FREETYPE) const ComputedProperties *prev_cprops = nullptr; hb_buffer_t *harfbuff = nullptr; #endif @@ -1525,7 +1525,7 @@ assemble_row(TextAssembler::TextRow &row, line_height = max(line_height, font->get_line_height() * properties->get_glyph_scale() * properties->get_text_scale()); } -#ifdef HAVE_HARFBUZZ +#if defined(HAVE_HARFBUZZ) && defined(HAVE_FREETYPE) if (tch._cprops != prev_cprops || graphic != nullptr) { if (harfbuff != nullptr && hb_buffer_get_length(harfbuff) > 0) { // Shape the buffer accumulated so far. @@ -1760,7 +1760,7 @@ assemble_row(TextAssembler::TextRow &row, } } -#ifdef HAVE_HARFBUZZ +#if defined(HAVE_HARFBUZZ) && defined(HAVE_FREETYPE) if (harfbuff != nullptr && hb_buffer_get_length(harfbuff) > 0) { shape_buffer(harfbuff, placed_glyphs, xpos, prev_cprops->_properties); } @@ -1797,7 +1797,7 @@ void TextAssembler:: shape_buffer(hb_buffer_t *buf, PlacedGlyphs &placed_glyphs, PN_stdfloat &xpos, const TextProperties &properties) { -#ifdef HAVE_HARFBUZZ +#if defined(HAVE_HARFBUZZ) && defined(HAVE_FREETYPE) // If we did not specify a text direction, harfbuzz will guess it based on // the script we are using. hb_direction_t direction = HB_DIRECTION_INVALID; diff --git a/pandatool/src/deploy-stub/android_main.cxx b/pandatool/src/deploy-stub/android_main.cxx index 5aa24b53d2..d1e140c5f3 100644 --- a/pandatool/src/deploy-stub/android_main.cxx +++ b/pandatool/src/deploy-stub/android_main.cxx @@ -161,8 +161,6 @@ void android_main(struct android_app *app) { std::string dtool_name = std::string(libdir) + "/libp3dtool.so"; ExecutionEnvironment::set_dtool_name(dtool_name); android_cat.info() << "Path to dtool: " << dtool_name << "\n"; - - env->ReleaseStringUTFChars(libdir_jstr, libdir); } // Get the path to the APK. @@ -184,6 +182,7 @@ void android_main(struct android_app *app) { // Map the blob to memory void *blob = map_blob(lib_path, (off_t)blobinfo.blob_offset, (size_t)blobinfo.blob_size); + env->ReleaseStringUTFChars(lib_path_jstr, lib_path); assert(blob != NULL); assert(blobinfo.num_pointers <= MAX_NUM_POINTERS); @@ -242,14 +241,16 @@ void android_main(struct android_app *app) { preconfig.utf8_mode = 1; PyStatus status = Py_PreInitialize(&preconfig); if (PyStatus_Exception(status)) { - Py_ExitStatusException(status); - return; + env->ReleaseStringUTFChars(libdir_jstr, libdir); + Py_ExitStatusException(status); + return; } // Register the android_log module. if (PyImport_AppendInittab("android_log", &PyInit_android_log) < 0) { android_cat.error() << "Failed to register android_log module.\n"; + env->ReleaseStringUTFChars(libdir_jstr, libdir); return; } @@ -259,8 +260,8 @@ void android_main(struct android_app *app) { config.buffered_stdio = 0; config.configure_c_stdio = 0; config.write_bytecode = 0; - PyConfig_SetBytesString(&config, &config.executable, lib_path); - env->ReleaseStringUTFChars(lib_path_jstr, lib_path); + PyConfig_SetBytesString(&config, &config.platlibdir, libdir); + env->ReleaseStringUTFChars(libdir_jstr, libdir); status = Py_InitializeFromConfig(&config); PyConfig_Clear(&config); @@ -297,11 +298,10 @@ void android_main(struct android_app *app) { // We still need to keep an event loop going until Android gives us leave // to end the process. - int looper_id; - int events; - struct android_poll_source *source; - while ((looper_id = ALooper_pollAll(-1, nullptr, &events, (void**)&source)) >= 0) { - // Process this event, but intercept application command events. + while (!app->destroyRequested) { + int looper_id; + struct android_poll_source *source; + auto result = ALooper_pollOnce(-1, &looper_id, nullptr, (void **)&source); if (looper_id == LOOPER_ID_MAIN) { int8_t cmd = android_app_read_cmd(app); android_app_pre_exec_cmd(app, cmd); @@ -332,4 +332,6 @@ void android_main(struct android_app *app) { // Detach the thread before exiting. activity->vm->DetachCurrentThread(); + + _exit(0); }