diff --git a/.p4a b/.p4a index eee38235..a2c409e8 100644 --- a/.p4a +++ b/.p4a @@ -5,7 +5,7 @@ --dist_name "kolibri" --private "src" --requirements python3==3.9.13,hostpython3==3.9.13,android,pyjnius,genericndkbuild,sqlite3,cryptography,twisted,attrs,bcrypt,service_identity,pyasn1,pyasn1_modules,pyopenssl,openssl,six,kolibri,ifaddr ---android-api 33 +--android-api 35 --minsdk 23 --ndk-api 23 --permission ACCESS_NETWORK_STATE diff --git a/Makefile b/Makefile index 2c8406be..697ca1f5 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,9 @@ else PLATFORM := linux endif -ANDROID_API := 33 -ANDROIDNDKVER := 25.2.9519653 +ANDROID_API := 35 +ANDROIDNDKVER := 28.2.13676358 +SDKMANAGER_VERSION := 13114758 ifdef ANDROID_SDK_ROOT else @@ -191,19 +192,19 @@ logcat: $(SDK)/cmdline-tools/latest/bin/sdkmanager: @echo "Downloading Android SDK command line tools" - wget https://dl.google.com/android/repository/commandlinetools-$(PLATFORM)-9477386_latest.zip + wget https://dl.google.com/android/repository/commandlinetools-$(PLATFORM)-${SDKMANAGER_VERSION}_latest.zip rm -rf cmdline-tools - unzip commandlinetools-$(PLATFORM)-9477386_latest.zip -d $(SDK) + unzip commandlinetools-$(PLATFORM)-${SDKMANAGER_VERSION}_latest.zip -d $(SDK) mv $(SDK)/cmdline-tools $(SDK)/latest mkdir -p $(SDK)/cmdline-tools mv $(SDK)/latest $(SDK)/cmdline-tools/latest - rm commandlinetools-$(PLATFORM)-9477386_latest.zip + rm commandlinetools-$(PLATFORM)-${SDKMANAGER_VERSION}_latest.zip sdk: $(SDK)/cmdline-tools/latest/bin/sdkmanager yes y | $(SDK)/cmdline-tools/latest/bin/sdkmanager "platform-tools" yes y | $(SDK)/cmdline-tools/latest/bin/sdkmanager "platforms;android-$(ANDROID_API)" yes y | $(SDK)/cmdline-tools/latest/bin/sdkmanager "system-images;android-$(ANDROID_API);default;x86_64" - yes y | $(SDK)/cmdline-tools/latest/bin/sdkmanager "build-tools;30.0.3" + yes y | $(SDK)/cmdline-tools/latest/bin/sdkmanager "build-tools;35.0.0" yes y | $(SDK)/cmdline-tools/latest/bin/sdkmanager "ndk;$(ANDROIDNDKVER)" ln -sfT ndk/$(ANDROIDNDKVER) $(SDK)/ndk-bundle @echo "Accepting all licenses" diff --git a/README.md b/README.md index c80b3adc..422ad770 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Wraps Kolibri in an android-compatibility layer. Relies on Python-For-Android to 1. Setup a Python virtual environment in which to do development. The Kolibri developer documentation has a [How To guide for doing this with pyenv](https://kolibri-dev.readthedocs.io/en/develop/howtos/pyenv_virtualenv.html) but any Python virtualenv should work. -2. Ensure you have all [necessary packages for Python for Android](https://python-for-android.readthedocs.io/en/latest/quickstart/#installing-dependencies). Ensure you install java version 1.11, `sudo apt install openjdk-11-jdk` , and set it as the default java version: `sudo update-alternatives --auto javac` and `sudo update-alternatives --auto java`. +2. Ensure you have all [necessary packages for Python for Android](https://python-for-android.readthedocs.io/en/latest/quickstart.html#installing-prerequisites). Ensure you install java version 1.17, `sudo apt install openjdk-17-jdk` , and set it as the default java version: `sudo update-alternatives --auto javac` and `sudo update-alternatives --auto java`. 3. The `make setup` command will install the Android SDK and Android NDK. diff --git a/python-for-android/dists/kolibri/build.gradle b/python-for-android/dists/kolibri/build.gradle index e74b85c1..6dff46fb 100644 --- a/python-for-android/dists/kolibri/build.gradle +++ b/python-for-android/dists/kolibri/build.gradle @@ -2,20 +2,17 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.1.2' + classpath 'com.android.tools.build:gradle:8.13.0' } } allprojects { repositories { google() - jcenter() - flatDir { - dirs 'libs' - } + mavenCentral() } } @@ -24,7 +21,9 @@ apply plugin: 'com.android.application' android { - compileSdk 34 + namespace = 'org.learningequality.Kolibri' + compileSdkVersion = 35 + buildToolsVersion = "35.0.0" def versionPropsFile = file('version.properties') Properties versionProps = new Properties() @@ -45,21 +44,23 @@ android { def nameNoDebug = name.replace("-debug", "") defaultConfig { - minSdkVersion 23 - targetSdk 34 - versionCode code - versionName name + minSdkVersion = 23 + targetSdk = 35 + versionCode = code + versionName = name manifestPlaceholders = [:] - multiDexEnabled true + multiDexEnabled = true setProperty("archivesBaseName", "kolibri-$nameNoDebug") + buildConfigField "String", "VERSION_CODE", "\"${code.toString()}\"" } packagingOptions { jniLibs { useLegacyPackaging = true } - exclude 'lib/**/gdbserver' - exclude 'lib/**/gdb.setup' + resources { + excludes += ['lib/**/gdbserver', 'lib/**/gdb.setup'] + } } signingConfigs { @@ -73,30 +74,32 @@ android { buildTypes { debug { - debuggable true + debuggable = true } release { - signingConfig signingConfigs.release + signingConfig = signingConfigs.release } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } sourceSets { main { jniLibs.srcDir 'libs' - java { - } } } - aaptOptions { - noCompress "tflite" + + buildFeatures { + buildConfig = true + } + androidResources { + noCompress 'tflite' } } diff --git a/python-for-android/dists/kolibri/src/main/AndroidManifest.xml b/python-for-android/dists/kolibri/src/main/AndroidManifest.xml index a77a41ee..cba40cdd 100644 --- a/python-for-android/dists/kolibri/src/main/AndroidManifest.xml +++ b/python-for-android/dists/kolibri/src/main/AndroidManifest.xml @@ -2,7 +2,6 @@ @@ -38,7 +37,6 @@ android:theme="@android:style/Theme.NoTitleBar" android:hardwareAccelerated="true" android:usesCleartextTraffic="true" - android:extractNativeLibs="true" > @@ -82,14 +80,14 @@ android:name="androidx.work.multiprocess.RemoteWorkManagerService" android:process="@string/task_worker_process" android:exported="true" - tools:replace="android:process, android:exported" + tools:replace="android:exported" /> = 35) { + // Use FrameLayout for Android 15+ to properly support margins for edge-to-edge + mLayout = new FrameLayout(PythonActivity.mActivity); + + // Set WebView with FrameLayout params that support margins + FrameLayout.LayoutParams webViewParams = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT + ); + mWebView.setLayoutParams(webViewParams); + mLayout.addView(mWebView); + + mLayout.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { + @Override + public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { + // Get system bar insets using the Android 11+ API + android.graphics.Insets systemBarsInsets = insets.getInsets(WindowInsets.Type.systemBars()); + + // Apply margins to the WebView to avoid system bars + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mWebView.getLayoutParams(); + params.leftMargin = systemBarsInsets.left; + params.topMargin = systemBarsInsets.top; + params.rightMargin = systemBarsInsets.right; + params.bottomMargin = systemBarsInsets.bottom; + mWebView.setLayoutParams(params); + + // Return the insets unchanged to allow other views to also handle them + return insets; + } + }); + // Enable edge-to-edge but handle insets properly + mLayout.setFitsSystemWindows(false); + } else { + // For older Android versions, use the original AbsoluteLayout setup + mLayout = new AbsoluteLayout(PythonActivity.mActivity); + mWebView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); + mLayout.addView(mWebView); + } setContentView(mLayout); diff --git a/python-for-android/dists/kolibri/src/main/java/org/kivy/android/PythonUtil.java b/python-for-android/dists/kolibri/src/main/java/org/kivy/android/PythonUtil.java index dd13ee0c..44a6822d 100644 --- a/python-for-android/dists/kolibri/src/main/java/org/kivy/android/PythonUtil.java +++ b/python-for-android/dists/kolibri/src/main/java/org/kivy/android/PythonUtil.java @@ -23,7 +23,7 @@ public class PythonUtil { // We read this directly from the VERSION_CODE, // so that any upgrade of the app causes the Python // code to be extracted again. - private static final String PrivateVersion = Integer.toString(BuildConfig.VERSION_CODE); + private static final String PrivateVersion = BuildConfig.VERSION_CODE; protected static void addLibraryIfExists(ArrayList libsList, String pattern, File libsDir) { // pattern should be the name of the lib file, without the diff --git a/requirements.txt b/requirements.txt index 28a6fa28..ebcf79cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ cython~=0.29 ifaddr virtualenv setuptools -git+https://github.com/learningequality/python-for-android@60f3bf7d653d3e4e97d8371feaef221ffcdeb421#egg=python-for-android +git+https://github.com/learningequality/python-for-android@632047c77661710e1ed19b110ef78402c4c64228#egg=python-for-android google-api-python-client==2.96.0 google-auth==2.22.0 google-auth-httplib2==0.1.0 diff --git a/scripts/create_strings.py b/scripts/create_strings.py index 78242d0f..93f32726 100644 --- a/scripts/create_strings.py +++ b/scripts/create_strings.py @@ -20,7 +20,7 @@ XML_TEMPLATE = """ - @@ -53,7 +53,7 @@ def generate_loading_pages(output_dir): def _find_string(lang, string): from kolibri.main import initialize from django.utils.translation import override - from django.utils.translation import ugettext as _ + from django.utils.translation import gettext as _ from django.utils.translation import to_locale initialize(skip_update=True)