Add LLM Service: fully-offline on-device Android chat app#310
Merged
Conversation
…I emulator UI test A standalone plain-Gradle/AGP example app (llama-android-example/) that consumes the shipped llama-android AAR + llama-kotlin coroutines facade: one Jetpack Compose screen that picks a GGUF from the file system (Storage Access Framework, copied to filesDir since llama.cpp mmaps a real path) and streams an on-device chat reply via generateChatFlow. No Android Studio required — plain Gradle/AGP builds a Play-shaped signed release .aab. Signing: release signingConfig reads an upload keystore from env/-P (Play App Signing model — the Maven Central GPG key cannot sign an APK/AAB), with a debug-signing fallback so forks/PRs/local builds stay green without secrets. CI: new build-android-example job in publish.yml builds the signed .aab and runs a real on-device UI test on the KVM x86_64 emulator (type a prompt, tap Send, assert a non-empty streamed reply), reusing the cached draft model. Not yet a publish gate — promote after it runs flake-free (same policy as test-android-emulator). Docs: example README (build/sign/Play/test walkthrough), root README pointer under 'Importing in Android', and a CLAUDE.md section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HTS5FpMtBLJENTGoRUrp5m
…r + private save/load Rebrand the Android example app to a generic, trademark-safe identity: - App label "LLM Service"; applicationId/namespace/package net.ladenthin.android.llmservice - Folder llama-android-example/ -> android-llmservice/ (CI job build-android-llmservice, run-android-llmservice-test.sh, android-llmservice-aab artifact, gitignore/docs updated) Add three features: - Internationalization: every UI string externalized; translations for 13 languages (en + de/es/fr/it/pt/ru/tr/ar[RTL]/hi/zh-CN/ja/ko), locales_config.xml. - In-app flag language picker (top-bar dropdown) via AppCompatDelegate.setApplicationLocales, persisted across restarts (AppCompat autoStoreLocales; MainActivity now AppCompatActivity). The ViewModel survives the locale-change recreation, so the chat is not lost. - Private local save/load session: Save/Load buttons persist the conversation + model path to filesDir/session.json (org.json, no new dep); readable only by the app, nothing uploaded. Docs note Gemma 3 4B Instruct as the recommended real on-device model. The instrumented Compose UI test moves to the new package and still drives the real on-device flow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HTS5FpMtBLJENTGoRUrp5m
Comment on lines
+15
to
+44
| <application | ||
| android:allowBackup="true" | ||
| android:label="@string/app_name" | ||
| android:localeConfig="@xml/locales_config" | ||
| android:supportsRtl="true" | ||
| android:theme="@style/Theme.LlmService"> | ||
|
|
||
| <!-- | ||
| Enables AppCompat's per-app language persistence (AppCompatDelegate | ||
| .setApplicationLocales): the flag language picker's choice survives restarts and | ||
| integrates with the Android 13+ system per-app language setting. | ||
| --> | ||
| <service | ||
| android:name="androidx.appcompat.app.AppLocalesMetadataHolderService" | ||
| android:enabled="false" | ||
| android:exported="false"> | ||
| <meta-data | ||
| android:name="autoStoreLocales" | ||
| android:value="true" /> | ||
| </service> | ||
|
|
||
| <activity | ||
| android:name=".MainActivity" | ||
| android:exported="true"> | ||
| <intent-filter> | ||
| <action android:name="android.intent.action.MAIN" /> | ||
| <category android:name="android.intent.category.LAUNCHER" /> | ||
| </intent-filter> | ||
| </activity> | ||
| </application> |
|
This was referenced Jul 9, 2026
android-llmservice: feature-roadmap TODO + llama.cpp b9941 + Kotlin build fix & installable APK
#312
Merged
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
android-llmservice/) — a KISS, fully-offline local-AI chat demo consuming thellama-androidAAR andllama-kotlincoroutines façadeINTERNET, no storage permission — nothing leaves the devicebuild-android-llmservicejob builds a release App Bundle, runs end-to-end instrumented UI tests on the emulator, and validates the full "real app" storyDetails
The app demonstrates the complete integration of the llama-android AAR and llama-kotlin façade in a production-shaped Android application:
MainActivity.kt— Compose UI entry point with SAF file picker, language menu, and session save/load buttonsChatViewModel.kt— Holds the loadedLlamaModel, drives streaming chat viagenerateChatFlow, manages model lifecycle and error handlingSessionStore.kt— Persists conversations to private app-internal storage (JSON, no upload)Languages.kt— 13 supported languages (English, German, Spanish, French, Italian, Portuguese, Russian, Turkish, Arabic, Hindi, Chinese, Japanese, Korean) with flag emoji picker and per-app locale persistencevalues-*/strings.xmlfor all 13 languages,locales_config.xmlfor Android 13+ per-app language integrationminSdk 28, release signing support via env vars / properties, R8 minification with AAR consumer ProGuard rulesChatFlowInstrumentedTest.ktdrives the actual UI (type prompt, tap Send) against real on-device inference, validates token streamingThe app is not published to Maven Central (it is a runnable app, not a library) but is built and tested by CI on every push/PR to validate the AAR + façade integration end-to-end.
Test plan
build-android-llmservicejob passes: builds release AAB, runs instrumented UI test on emulatorllama-kotlin)Related issues / PRs
Completes the "real app" story for the llama-android AAR and llama-kotlin façade.
Checklist
CONTRIBUTING.mdandCODE_OF_CONDUCT.mdhttps://claude.ai/code/session_01HTS5FpMtBLJENTGoRUrp5m