Skip to content

KDE Android News (March 2025)

Saturday, 8 March 2025  |  Volker Krause

Here’s an overview of recent work around the Android platform support for KDE Frameworks and KDE applications. Since the last update there have been improvements in localization and packaging, and an encounter with a bizarre calling convention issues deep down in the Android stack.

Localization

Application-specific language settings

Starting with SDK 33 Android allows apps to opt-in to application-specific language settings. That is, you can select a different language for an application than for the platform itself. This is for example useful when using a language the application doesn’t support.

For this to work applications need to indicate which languages they support, which can be done with minimal changes to the build.gradle file:

android {
    ...
    androidResources {
        generateLocaleConfig true
    }
}

As well as adding android/res/resources.properties with the following content:

unqualifiedResLocale=en-US

See also this example in Itinerary.

Qt translation catalogs

We fixed bundling (MR 488) and loading (MR 135) Qt’s own translation catalogs, and applied the same fallback language fixes described last time for those as well (MR 136).

This should fix some small but somewhat prominent gaps in the translation coverage, such as standard dialog button texts.

Runtime language change

The foundational changes to support language changes during application runtime have meanwhile landed in both Qt and KDE Frameworks. To benefit from this make sure your application is using the new API for setting up its KLocalizedQmlContext:

KLocalization::setupLocalizedContext(&engine);

More QML API has also been updated to support this, such as the formatting functions in KCoreAddons (MR 474).

QLocale support for 24h time format

Android has a system setting to force a 24h time format even in locales that would otherwise use an AM/PM format. With Qt 6.8 this is considered by QLocale, ie. all its date/time formatting functions will automatically follow this (CR 600295).

Packaging

APK version codes

We have reworked the APK version code generation to comply with the various ordering constraints posed by Android, F-Droid and Google Play also when building APKs for multiple architectures in parallel in the CI system.

APK version codes need to:

  • be strictly increasing for Android to install a newer version.
  • be different for all architectures for Google Play to accept them.
  • not have a higher version code on ARM32 APKs than ARM64 APKs for F-Droid to not complain.
  • have a higher version code on ARM64 APKs than ARM32 APKs for Google Play to not complain.

Our previous approach managed to only guarantee the first constraint, for all others it depended in which order the CI was building things, ie. it was effectively random. Additionally, the version code logic was copy/pasted into all applications.

Starting with KDE Frameworks 6.12 this has been improved by ECM providing a Gradle include file with version code computation that satisfies all of the above constraints (MR 513, MR 514).

What remains in the application build.gradle file then is the following:

apply from: '../ecm-version.gradle'

...

android {
    ...
    defaultConfig {
        ...
        versionName ecmVersionName
        versionCode ecmVersionCode
        manifestPlaceholders = [versionName: ecmVersionName, versionCode: ecmVersionCode]
    }
}

Qt 6.8 update

The Qt version used for CI/CD builds and thus also the release APK packages has been updated to 6.8. What sounds like and should be a relatively straightforward process was unfortunately unusually bumpy.

  • 6.8.0 broke packaging of the QQC2 Breeze style and thus practically all our APKs (MR 111).
  • 6.8.1 broke the build all over the place (list of MRs).
  • Finally, 6.8.2 was relatively smooth, as it should be.

SDK/NDK update

There has also been work towards updating to SDK 35 and NDK 27, by fixing numerous build errors across the stack caused by the newer versions (list of MRs).

We aren’t quite there yet though, as the changes to window insets/edge-to-edge mode in Android 15 might require new API in Qt 6.9 to prevent our application from rendering behind to Android status bar. Attempts to find a workaround for this led to discovering the following issue.

Qt and JNI native function calls

For interfacing with Android’s Java-based platform API Qt heavily relies on the Java Native Interface (JNI), a way for C++ and Java code to call each other. JNI is very fundamental for Android and Java in general and is decades old technology, ie. usually not a thing you’d expect to change or break.

And yet, that’s exactly what we observed under certain conditions in December last year: When calling native functions from Java code with floating point arguments on Android 15 and x86_64 the arguments arrived corrupted on the native side. One of the calls affected by this was passing the screen geometry to Qt, which arrived there as negative values. That is physically impossible of course, and resulted in all kinds of spectacular UI breakage.

This is particularly tricky to track down as for normal debugging tools the breakage happens behind the scenes of a method call, something that is usually seen as an atomic step not able change any data. Instead it gets you into the dark magic of platform-specific calling conventions.

While we still haven’t managed to pinpoint the change in Android causing this, the best guess at this point is that an optimization in Android’s JNI implementation missed (or intentionally ignored) that the way floating point arguments are passed to native functions differs between regular and va_arg functions on x86_64. The JNI specification suggests that the latter is supposed to work as well, and that’s the thing that broke here.

That combination is probably quite rare, x86_64 is practically only relevant for the emulator, and you’d only use va_arg functions as a last resort in generic code normally. And that’s what Qt did in Q_DECLARE_JNI_NATIVE_METHOD.

For the full story see QTBUG-132410. If you look at the names and times there, the Qt chief maintainer himself implementing a fix on Christmas Day gives you an idea of the severity of this.

CR 613563 reproduced the issue in the Qt CI, CR 613552 works around it by replacing the use of va_arg functions with clever template magic.

Outlook

We still have plenty more to do regarding Android platform integration. The currently probably most pressing issues are the following I think:

  • There’s an annoying interaction between input focus, the onscreen keyboard and resizing/repositioning the application window that makes using input forms rather unpleasant.
  • On some devices the font size is unusably small, caused by the display scale factor being wrong.
  • Selecting files in the platform file dialog that are located on a cloud storage such as Nextcloud silently fails.

If you are interested in Android integration for KDE applications, feel free to join us in the #kde-android Matrix channel!