Skip to content

Migrate from python-for-android to Chaquopy#259

Open
rtibbles wants to merge 7 commits intodevelopfrom
chaquopy_refactor
Open

Migrate from python-for-android to Chaquopy#259
rtibbles wants to merge 7 commits intodevelopfrom
chaquopy_refactor

Conversation

@rtibbles
Copy link
Copy Markdown
Member

@rtibbles rtibbles commented Jan 17, 2026

Summary

Migrates the Kolibri Android app from python-for-android (p4a) to Chaquopy for Python integration. This is a major architectural change that:

  • Replaces p4a with Chaquopy: Uses Chaquopy Gradle plugin for Python 3.10 integration instead of the p4a build system
  • Moves to standard Android project structure: Reorganizes from python-for-android/dists/kolibri/ to standard app/ module
  • Introduces WebView-based UI: Replaces p4a's PythonActivity with a native WebViewActivity that loads Kolibri via HTTP server
  • Simplifies the build process: Uses standard Gradle commands instead of custom p4a toolchain
  • Preserves task worker architecture: Maintains WorkManager-based background task execution for content downloads, sync operations, etc.
  • Drops x86 (32-bit) architecture: Now builds for armeabi-v7a, arm64-v8a, and x86_64 (Chromebooks/emulators)
  • Reduces APK size significantly: Universal APK reduced from ~200MB to ~74MB
  • Adds animated splash screen: Vector drawable Kolibri logo with wing-flap animation during server startup
  • Adds unit tests: JUnit + Robolectric tests for utility classes and task workers
  • Adds development tooling: CDP helper for WebView DOM inspection, Maestro smoke test, agent guides
  • Updates README with new dev setup: Complete documentation for the new build process

Commit history

  1. Remove obsolete python-for-android infrastructure — deletes p4a dist, kivy/renpy/jtar runtime, old Python source, Docker, Buildkite
  2. Add Gradle project with Chaquopy-based Android app — all new Java/Python source, Android resources, build configuration
  3. Update CI workflows and build scripts for Chaquopy — GitHub Actions, Makefile, pre-commit, build scripts
  4. Add unit tests for utility classes and task workers — AuthUtils, ContextUtil, ShareUtils, BaseTaskWorker
  5. Update README for Chaquopy-based architecture — full documentation rewrite
  6. Add development and testing tooling — AGENTS.md, CDP helper, Maestro smoke test

Manual verification performed

  1. Built debug APK successfully with ./gradlew assembleDebug
  2. Installed on Android emulator
  3. Verified Kolibri server starts correctly (confirmed via logcat)
  4. Verified WebView loads Kolibri UI and displays channels
  5. Verified navigation within the app works (channel browsing)
  6. Verified animated splash screen displays during startup
  7. Ran unit tests (./gradlew test) — all pass

Screenshots

Learn page with channels after fresh app start: Channel content view showing navigation:
Kolibri Learn Page Kolibri Channel View

References

Reviewer guidance

How to test

Follow the Development Setup section in the updated README:

  1. Ensure JDK 17+ is installed
  2. Run make setup to download Android SDK, system image, and create the emulator AVD
  3. Set up Python virtual environment: python3 -m venv venv && source venv/bin/activate && pip install -r build-requirements.txt
  4. Place a Kolibri tar file in the tar/ directory
  5. Run make emulator to start the emulator
  6. Run make install to build and install the APK
  7. Verify the app launches and displays content

CI validation

The build_apk workflow should produce a valid APK artifact — please verify the CI check completes successfully. The build_and_test workflow runs unit tests on every push.

Risky areas requiring careful review

  • app/build.gradle:150-180 — Custom Gradle task for patching Kolibri tar archive (extracts, patches settings, repackages)
  • KolibriEnvironmentSetup.java — Python environment initialization sequence and plugin enabling
  • KolibriServerService.java — Background service lifecycle for HTTP server
  • WebViewActivity.java — WebView configuration, auth token flow, splash screen lifecycle, and navigation handling
  • task_reconciler.py — Python-side task reconciliation between Kolibri and WorkManager
  • main.py — Kolibri server startup sequence and lifecycle management

Key architectural changes

Component Before (p4a) After (Chaquopy)
Python integration p4a bootstrap, custom recipes Chaquopy Gradle plugin
UI PythonActivity (SDL-based) WebViewActivity + Service Worker
Splash screen Static presplash.jpg Animated vector drawable (wing flap)
HTTP server Started from Python main Started via KolibriServerService
Task workers Direct Python process WorkManager + Chaquopy Python
Build system p4a commands + Gradle Standard Gradle
Architectures armeabi-v7a, arm64-v8a, x86, x86_64 armeabi-v7a, arm64-v8a, x86_64
Universal APK size ~200MB ~74MB
APK build time 25 minutes 2 minutes
Unit tests None JUnit + Robolectric (4 test classes)

🤖 Generated with Claude Code

@rtibbles rtibbles force-pushed the chaquopy_refactor branch 5 times, most recently from 9007d2d to 4eb9820 Compare January 17, 2026 22:24
@rtibbles rtibbles requested a review from rtibblesbot February 8, 2026 18:37
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this major migration! Moving from python-for-android to Chaquopy is a great step forward - the reduced APK size (~200MB to ~74MB) and faster build times (25min to 2min) are impressive wins. The new WebView-based architecture is clean and the code is well-organized.

I found no blocking issues - CI is green and the manual verification screenshots look solid. I have several suggestions and nitpicks that could improve robustness, particularly around edge-case error handling and thread safety.

Summary of findings:

  • 0 blocking issues
  • 8 suggestions (resource safety, null guards, thread safety, design clarity)
  • 3 nitpicks (logging, unused code, minor style)

Nice work on the migration! The architecture is significantly cleaner than the p4a bootstrap approach.

Comment thread app/src/main/java/org/learningequality/Kolibri/util/AuthUtils.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/util/AuthUtils.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/util/ContextUtil.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/util/ContextUtil.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/workers/BaseTaskWorker.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/util/ShareUtils.java Outdated
Comment thread app/src/main/python/main.py Outdated
Comment thread app/build.gradle Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/KolibriEnvironmentSetup.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/workers/BackgroundWorker.java Outdated
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this ambitious migration from python-for-android to Chaquopy! This is clearly a significant improvement -- the APK size reduction, build time improvement, and architectural cleanup are all excellent outcomes. The PR is well-structured with a thorough description and manual verification steps.

I found several issues that should be addressed before merging, organized by severity:

Blocking issues (5):

  1. CI failure: patchKolibriTar task fails when no tar file is present, breaking unit tests
  2. WebView security: MIXED_CONTENT_ALWAYS_ALLOW is unnecessarily permissive
  3. Thread safety: KolibriServerService.startHttpServer() has a race window for duplicate thread creation
  4. Supply chain risk: fkirc/skip-duplicate-actions@master is unpinned in CI
  5. Task reconciler: Tag filtering heuristic for distinguishing job IDs from class names is fragile

Key suggestions (not blocking but strongly recommended):

  • WebView setAllowFileAccess(true) and third-party cookies are unnecessary security relaxations
  • KolibriEnvironmentSetup.initialized should be volatile for thread-safe reads
  • Server state should be reset in KolibriServerService.onDestroy()
  • Duplicated tar extraction logic between configuration-phase and task should be consolidated

The inline comments below have the full details. Looking forward to the updates!

Comment thread app/build.gradle
Comment thread app/build.gradle
Comment thread app/build.gradle Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/WebViewActivity.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/WebViewActivity.java Outdated
Comment thread app/src/main/python/task_reconciler.py Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/App.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/WorkController.java
Comment thread app/src/main/python/main.py Outdated
Comment thread app/src/main/python/main.py
@rtibbles rtibbles force-pushed the chaquopy_refactor branch 4 times, most recently from 4d6a145 to 359de57 Compare February 9, 2026 23:23
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impressive migration from python-for-android to Chaquopy. The APK size reduction, build time improvement, and move to standard Android project structure are significant wins.

CI passing (all 7 checks green). Screenshots confirm the Learn page and channel navigation work correctly.

Blocking (not addressable as inline comments):

  • app/src/main/AndroidManifest.xml:92android:permission="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE, android.permission.FOREGROUND_SERVICE_DATA_SYNC" is invalid. android:permission accepts only a single permission string. This comma-separated value is treated as one literal string, which will never match. Either remove this attribute (the foregroundServiceType declaration + <uses-permission> should suffice) or split into separate service declarations.
  • .github/workflows/build_apk.yml:190cat .version-code reads a file that the new Chaquopy-based build never generates. This step will fail or produce empty output, breaking the release pipeline. Either write this file during the build or extract the version code from the APK via aapt2 dump badging.
  • app/src/main/AndroidManifest.xml:17 — Stale comment says <!-- Allow writing to external storage --> but the permission on line 18 is android.permission.INTERNET.

See inline comments for remaining blocking issues and suggestions.

Comment thread .github/workflows/build_and_test.yml Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/App.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/WebViewActivity.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/WebViewActivity.java Outdated
Comment thread app/src/main/AndroidManifest.xml Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/WorkControllerService.java Outdated
Comment thread app/src/main/java/org/learningequality/Kolibri/WorkControllerService.java Outdated
@rtibbles
Copy link
Copy Markdown
Member Author

Thanks for the review, taking a look now.

Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Significant progress since last review — the vast majority of prior findings have been addressed.

CI passing (all 7 checks green: linting, build, unit tests, smoke test). PR targets develop (the default branch).

21 prior finding(s) resolved. The WebView security hardening, thread safety fixes, supply chain pinning, task reconciler prefix tags, try-with-resources, volatile fields, and other feedback have all been incorporated cleanly.

Unresolved prior findings:

  • [suggestion] AndroidManifest.xml:92 — comma-separated android:permission is invalid — UNRESOLVED. android:permission accepts a single permission string, but line 92 has "android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE, android.permission.FOREGROUND_SERVICE_DATA_SYNC" which is one literal string containing a comma. This doesn't break the app (the attribute only restricts external callers, and this is an internal AndroidX service), but it's misleading — either remove the attribute entirely (the foregroundServiceType + <uses-permission> declarations are sufficient) or split into separate <service> declarations.

  • [suggestion] .github/workflows/build_apk.yml:190cat .version-code reads a file that the new build never generates — UNRESOLVED. The Chaquopy/Gradle build computes versionCode at configuration time in app/build.gradle but never writes a .version-code file. This step currently produces an empty version-code output. It doesn't break CI (the output isn't consumed by build_and_test.yml), but it will break the release pipeline when release_apk.yml tries to use this value. Either write the file during the build (e.g., a doLast in the Gradle build) or extract the version code from the APK via aapt2 dump badging.

  • [nitpick] AndroidManifest.xml:17 — stale comment — UNRESOLVED. Comment says <!-- Allow writing to external storage --> but the permission on line 18 is android.permission.INTERNET.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNRESOLVED, PARTIALLY_ADDRESSED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

@rtibbles
Copy link
Copy Markdown
Member Author

Revision Summary

Blocking items fixed

  • Added missing super.onCreate() call in WorkControllerService (b30c60e)
  • Quoted shell interpolation in CI workflow to prevent injection (b30c60e)

Suggestions addressed

  • Fixed WebView field shadowing in WebViewActivity (b30c60e)
  • Replaced broad usesCleartextTraffic="true" with scoped network security config allowing cleartext only to 127.0.0.1 and localhost (b30c60e)
  • Fixed taskCount leak — increment moved into startTask() so decrement always has a matching increment (b30c60e)
  • Fixed misleading "stopping service" log in onTrimMemory (b30c60e)
  • Added custom WebViewClient to open external URLs in system browser, keep local URLs in WebView (b30c60e)
  • Moved Kolibri init off main thread with CompletableFuture to avoid ANR — App.onCreate() kicks off async, server thread and work controller await completion (b74d75e)
  • Fixed server restart crash caused by stale _queue_logging_initialized_for_process flag in Kolibri's logger (b74d75e)
  • Added WebView history clearing after first real page load so back button doesn't return to loading screen (b74d75e)

Declined (with reasoning)

  • Foreground service: Deliberate design — previous implementation's persistent server drained battery. Android expectation is that backgrounding stops resource consumption. Can revisit in follow-up if needed.
  • Default WebViewClient: Addressed by implementing a custom one that handles external links.

@rtibbles
Copy link
Copy Markdown
Member Author

Addressed the three items from the review body in 0b8e49e:

  1. AndroidManifest.xml:92 — invalid android:permission: Removed the comma-separated android:permission attribute. The <uses-permission> declarations + foregroundServiceType are sufficient.

  2. build_apk.yml:190 — stale .version-code: Added a line in build.gradle to write .version-code to the project root during the build, so the CI step can read it.

  3. AndroidManifest.xml:17 — stale comment: Removed the "Allow writing to external storage" comment above the INTERNET permission.

Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All prior findings addressed. The latest commit (0b8e49e) fixes the invalid comma-separated android:permission, removes the stale manifest comment, and writes .version-code for CI.

CI: linting, build, unit tests all passing. Smoke test in progress.

25+ prior finding(s) resolved.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNRESOLVED, PARTIALLY_ADDRESSED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All prior findings from previous reviews have been resolved — nice work addressing everything systematically.

CI passing (Linting green). One new suggestion below.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNRESOLVED, PARTIALLY_ADDRESSED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Comment thread app/src/main/java/org/learningequality/Kolibri/WebViewActivity.java Outdated
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All prior blocking issues, suggestions, and nitpicks from previous reviews have been addressed. Nice work on the thorough revisions.

23 prior finding(s) resolved.

CI passing (Linting green). Two new minor findings below.

  • [suggestion] Lambda parameter shadows field in WorkController.dispatch() — see inline comment
  • [nitpick] WorkControllerService.onDestroy() missing super.onDestroy() — see inline comment

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNRESOLVED, PARTIALLY_ADDRESSED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Comment thread app/src/main/java/org/learningequality/Kolibri/WorkController.java Outdated
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All prior findings from three rounds of review have been thoroughly addressed. The fixes are solid — highlights include the synchronized startHttpServer() eliminating the race window, MIXED_CONTENT_NEVER_ALLOW + disabled file/content access hardening the WebView, the kolibri:job: tag prefix making reconciliation robust, scoped network security config replacing blanket cleartext, and the CompletableFuture-based async init preventing ANR.

CI passing (7/7 checks green). Code is clean and well-structured.

16 prior finding(s) resolved.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNRESOLVED, PARTIALLY_ADDRESSED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

@rtibbles rtibbles force-pushed the chaquopy_refactor branch 2 times, most recently from ed75ba4 to 382f479 Compare February 21, 2026 02:57
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All prior blocking issues, suggestions, and nitpicks from the three previous reviews have been addressed. The WebView security hardening (MIXED_CONTENT_NEVER_ALLOW, file access disabled, scoped network security config, custom WebViewClient), thread safety fixes (synchronized startHttpServer, volatile fields, CompletableFuture-based async init), CI fixes (pinned actions, .version-code generation), manifest corrections, and task reconciler improvements are all solid.

CI: Linting, build, and unit tests passing. Smoke test pending.

~25 prior finding(s) resolved.

Prior findings still open:

  • [suggestion] Unquoted ${{ }} in CI workflow run: steps — PARTIALLY_ADDRESSED. build_and_test.yml was properly quoted (tar="${{ ... }}"), but build_apk.yml lines 134 and 137 still use unquoted ${{ github.event.inputs.tar-url }} / ${{ inputs.tar-url }}. Low risk since workflow_dispatch requires write access, but quoting or using an env var is best practice per GitHub's security hardening guide.

New findings:

  • See inline comment on onTrimMemory.

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNRESOLVED, PARTIALLY_ADDRESSED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All prior findings have been thoroughly addressed across the revision commits. Nice work on the fixes.

16 prior finding(s) resolved. All blocking issues (manifest permissions, CI .version-code, WebView security, thread safety, supply chain pinning, task reconciler heuristic) and suggestions (volatile fields, server state reset, cleartext scoping, field shadowing, external URL handling, async init) are confirmed fixed in the current code.

CI: 6/7 checks green (lint, build, unit tests, download tar, path checks). Smoke test still in progress — worth confirming before merge.

One new nitpick below.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNRESOLVED, PARTIALLY_ADDRESSED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Comment thread app/src/main/java/org/learningequality/Kolibri/notification/Manager.java Outdated
@rtibbles rtibbles force-pushed the chaquopy_refactor branch 2 times, most recently from 2bc1141 to b891f16 Compare February 23, 2026 15:19
@rtibbles rtibbles marked this pull request as ready for review February 23, 2026 15:52
@rtibbles rtibbles force-pushed the chaquopy_refactor branch from 830ee20 to 86be385 Compare March 1, 2026 17:31
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid migration from python-for-android to Chaquopy. The codebase is significantly cleaner — well-structured Java/Python separation, proper Android lifecycle management, and the WebView architecture is sound.

CI: 6/7 checks passing, smoke test pending. All prior blocking findings have been addressed.

All prior findings resolved.

New findings:

  • 1 suggestion (see inline comment)

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Comment thread app/src/main/java/org/learningequality/Kolibri/WorkControllerService.java Outdated
@rtibbles rtibbles force-pushed the chaquopy_refactor branch 2 times, most recently from c018a7a to a8c52e4 Compare March 1, 2026 19:29
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thorough delta review of the Chaquopy migration. All prior findings from three rounds of review have been addressed — impressive follow-through.

CI passing. Screenshots verify the Learn page and channel navigation render correctly.

29 prior finding(s) resolved. 1 prior finding acknowledged (foreground service omitted by design to avoid battery drain — reasonable trade-off).

New findings:

  • 1 suggestion (inline): WorkController.mInstance missing volatile in double-checked locking pattern

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Comment thread app/src/main/java/org/learningequality/Kolibri/WorkController.java
@rtibbles rtibbles force-pushed the chaquopy_refactor branch from a8c52e4 to 6e4e9e9 Compare March 1, 2026 19:54
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major migration from p4a to Chaquopy — all prior blocking findings have been addressed. The WebView security hardening, kolibri:job: tag prefix, CI pinning, and manifest fixes are all solid.

CI passing. Screenshots verified.

19 prior finding(s) resolved. 1 prior suggestion acknowledged (foreground service design — deliberate choice per author's reasoning).

New findings:

  • 0 blocking
  • 2 suggestions (WebView null safety, CI expression interpolation)
  • 1 nitpick (CI release lookup robustness)

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Comment thread app/src/main/java/org/learningequality/Kolibri/WebViewActivity.java Outdated
Comment thread .github/workflows/build_and_test.yml Outdated
Comment thread .github/workflows/build_and_test.yml
@rtibbles rtibbles force-pushed the chaquopy_refactor branch from 6e4e9e9 to c868d53 Compare March 1, 2026 20:15
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All prior findings from Reviews 2 and 3 have been addressed — nice work on the thorough revisions.

14 prior finding(s) resolved. 2 findings acknowledged (foreground service design, WebViewClient approach — both reasonable).

CI passing. No blocking issues remain. A couple of minor suggestions below.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Comment thread app/src/main/python/main.py
Comment thread .github/workflows/build_and_test.yml Outdated
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strong migration — all prior findings have been addressed. CI passing.

All prior findings resolved. The author systematically addressed every blocking issue, suggestion, and nitpick from three previous reviews, including the manifest permission fix, .version-code generation, network security scoping, WebView hardening, thread safety improvements, and async initialization.

New finding (1 blocking):

  • Application.getProcessName() crashes on API 24–27 (see inline comment)

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Comment thread app/src/main/java/org/learningequality/Kolibri/App.java Outdated
@rtibbles rtibbles force-pushed the chaquopy_refactor branch from c868d53 to a116a2c Compare March 1, 2026 22:31
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All prior issues addressed. Clean migration from p4a to Chaquopy with solid architecture.

CI passing. Screenshots verified — Learn page and channel navigation render correctly.

24 prior finding(s) resolved. 1 prior finding acknowledged (foreground service design — deliberate choice to avoid battery drain).

No new blocking issues found. The code is well-structured: WebView security is properly locked down (MIXED_CONTENT_NEVER_ALLOW, file access disabled, scoped cleartext config), thread safety is handled correctly (synchronized server start, volatile fields, CompletableFuture chains), and the task reconciliation system uses explicit kolibri:job: tag prefixes instead of heuristics. The CI dependency is pinned (skip-duplicate-actions@v5.3.1) and .version-code is now generated during the build.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

@rtibbles rtibbles force-pushed the chaquopy_refactor branch from a116a2c to fc1ddce Compare March 21, 2026 00:20
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thorough migration from p4a to Chaquopy. All prior findings resolved.

Prior findings

All 19 prior findings remain resolved — no regressions since last review.

CI failing: ruff-format rejects kolibri_plugin.py:47. 1 blocking finding below.

Findings:

  • 1 blocking (CI lint failure)
  • 1 praise

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

class AndroidShareFileHook(ShareFileHook):
def share_file(self, *args, **kwargs):
return share_by_intent(*args, **kwargs)
def share_file(self, path=None, filename=None, message=None, app=None, mimetype=None):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocking: CI ruff-format check is failing because this line exceeds the formatter's line-length threshold. The fix is straightforward — run ruff format locally or split the signature and body across multiple lines:

def share_file(
    self, path=None, filename=None, message=None, app=None, mimetype=None
):
    ShareUtils.shareByIntent(
        path or "", message or "", app or "", mimetype or ""
    )

This is the only file causing the CI failure.

}
}

private boolean isMainProcess() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Good handling of the isMainProcess() API level split — using Application.getProcessName() on API 28+ and falling back to ActivityManager.getRunningAppProcesses() on older devices. This avoids the crash that the earlier Application.getProcessName() approach would have had on API 24-27.

@rtibbles rtibbles force-pushed the chaquopy_refactor branch from fc1ddce to e6c6500 Compare March 24, 2026 23:33
Copy link
Copy Markdown

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean migration from python-for-android to Chaquopy. All prior findings addressed.

Prior findings

All prior findings remain resolved or acknowledged — no changes since last review.

CI passing (Linting green). Screenshots verified in PR description — Learn page and channel navigation render correctly.

Findings:

  • 0 blocking
  • 0 suggestions
  • 2 praise (see inline comments)

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria


// No file:// or content:// access needed — Kolibri loads via http://127.0.0.1
settings.setAllowFileAccess(false);
settings.setAllowContentAccess(false);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Thorough WebView security posture — MIXED_CONTENT_NEVER_ALLOW, file/content access disabled, third-party cookies rejected, scoped cleartext via network security config, and external URLs delegated to the system browser. This is a textbook lockdown for a localhost-only WebView.

if (initFuture != null) {
return;
}
initFuture = CompletableFuture.runAsync(() -> initializeEnv(context, skipUpdate));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: The CompletableFuture-based async init is well-designed — App.onCreate() kicks it off without blocking (avoiding ANR), the server thread and work controller both awaitInit() before proceeding, and the synchronized + initFuture != null guard ensures exactly-once execution across processes. Clean separation of the "when to init" decision from the "what to init" logic.


// Enable required plugins BEFORE initialize()
// Plugins must be enabled before the registry is initialized
kolibriMain.callAttr("enable_plugin", "kolibri.plugins.app");
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be removed now.

@rtibbles
Copy link
Copy Markdown
Member Author

rtibbles commented Apr 2, 2026

Notes from code walkthrough with @bjester and @ozer550:

  • Clean up kolibri.plugins.app reference
  • Look to see if any files can be git mved rather than deleted and recreated
  • Remove committed loader html in xml resource files that removed in a later commit to prevent churn
  • Take a closer look at reconciliation to make sure it is preserving the Java functionality
  • Double check the metadata we're setting in execute_job - feels like it can be more granular and informative!

@rtibbles rtibbles force-pushed the chaquopy_refactor branch 4 times, most recently from 6cc459e to c78bddd Compare April 2, 2026 23:32
@bjester bjester self-assigned this Apr 7, 2026
rtibbles and others added 7 commits April 9, 2026 20:22
Move reusable source files to new app/ layout via git mv.
Delete kivy/renpy runtime, vendored jtar/jnius libraries,
Docker build, Buildkite CI, old SQLite layer, and
Sentinel/Reconciler/StateMap task infrastructure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the python-for-android/kivy build system with a standard Gradle
project using Chaquopy for Python integration. This is the core of the
architecture migration.

Build system:
- Gradle wrapper (8.11.1), root and app build files
- Chaquopy plugin for embedding Python in the Android app
- Updated .gitignore, requirements.txt, pyproject.toml

Java application layer:
- App, WebViewActivity, KolibriWebChromeClient for WebView-based UI
- KolibriServerService/ViewModel for managing the Kolibri HTTP server
- KolibriEnvironmentSetup for Python environment configuration
- WorkController/WorkControllerService for background task orchestration
- Worker classes (BaseTaskWorker, ForegroundWorker, BackgroundWorker)
- Task management (Task, TaskWorkerImpl, WorkerImpl, Observable/Observer)
- Notification system (Builder, Manager, NotificationRef, Notifier)
- Utility classes (AuthUtils, ContextUtil, NetworkUtils, ShareUtils)

Python application layer:
- main.py entry point for Kolibri server lifecycle
- taskworker.py and task_reconciler.py for background task execution
- auth.py for authentication token generation
- Kolibri plugin and settings modules
- monkey_patch_zeroconf.py for Android compatibility

Android resources:
- WebView layout with animated splash screen
- Kolibri logo vector drawable with wing-flap animation
- Notification icons, themes, colors
- Network security config, file provider paths
- Localized HTML content for loading/error screens

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add build_and_test.yml for running unit tests in CI
- Update build_apk.yml and release_apk.yml for Gradle-based builds
- Remove pr_build.yml (replaced by build_and_test.yml)
- Update pre-commit.yml and .pre-commit-config.yaml (add ruff, spotless)
- Overhaul Makefile for Gradle/Chaquopy workflow (SDK setup, emulator,
  build, install, test targets)
- Simplify scripts/version.py, create_strings.py, play_store_api.py
  for the new project structure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- AuthUtilsTest: token generation, URL building, header extraction
- ContextUtilTest: singleton initialization and context access
- ShareUtilsTest: share intent construction
- BaseTaskWorkerTest: Python task delegation and error handling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite documentation to reflect the new build system, project
structure, and development workflow. Covers Gradle setup, Chaquopy
Python integration, emulator usage, and CI configuration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CLAUDE.md and AGENTS.md for AI-assisted development workflow
- CDP helper (scripts/cdp_helper.py) for WebView DOM inspection and
  interaction via Chrome DevTools Protocol over ADB
- Unit tests for CDP helper
- Maestro smoke test for app launch verification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the apt dependencies step (buildozer-era packages not needed by
Chaquopy) and the make setup step (SDK, NDK, build-tools, platform-tools
are all preinstalled on ubuntu-latest). The runner provides
ANDROID_SDK_ROOT which the Makefile already respects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rtibbles rtibbles force-pushed the chaquopy_refactor branch from c78bddd to e37bade Compare April 10, 2026 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tracking Issue: Migrate App to use chaquopy

3 participants