ai-chat-android-auto / files / README.md
README.md
d522fe6d 2026-05-15 Pavel Safronov | 1 | # AI Chat for Android Auto |
449ce939 2026-05-14 Pavel Safronov | 2 | |
| 3 | An Android Auto voice assistant that sends your spoken questions to an AI provider and reads the responses back through the car's speakers. | |
| 4 | ||
| 5 | You choose the provider — Anthropic, OpenAI, Groq, Mistral, Google Gemini, or a local Ollama instance. API keys are stored on-device in `EncryptedSharedPreferences` and never leave the phone. | |
| 6 | ||
| 7 | --- | |
| 8 | ||
| 9 | ## How it works | |
| 10 | ||
d522fe6d 2026-05-15 Pavel Safronov | 11 | 1. Open the **AI Chat for Android Auto** app on your phone and configure a provider + API key. |
449ce939 2026-05-14 Pavel Safronov | 12 | 2. Connect your phone to the car. The app appears in the Android Auto launcher. |
| 13 | 3. Tap **Ask AI** (or press Play on the steering wheel) and speak your question. | |
| 14 | 4. The app sends your question to the provider's API and reads the answer aloud. | |
| 15 | 5. Past exchanges appear in the browse list so you can re-ask any previous question. | |
| 16 | ||
| 17 | --- | |
| 18 | ||
| 19 | ## Setup | |
| 20 | ||
| 21 | ### Requirements | |
| 22 | - Android 6.0+ (API 23) | |
| 23 | - Android Auto on the phone | |
| 24 | ||
| 25 | ### Phone setup | |
| 26 | 1. Install the APK (sideload or Play Store release). | |
d522fe6d 2026-05-15 Pavel Safronov | 27 | 2. Open **AI Chat for Android Auto** on your phone. |
449ce939 2026-05-14 Pavel Safronov | 28 | 3. Select a provider, enter your API key, and tap **Save Key**. |
| 29 | 4. Tap **↻** to fetch available models and select one. | |
| 30 | 5. Grant microphone permission when prompted. | |
| 31 | ||
| 32 | ### Android Auto | |
| 33 | The app registers as a media browser service, so it requires no special permissions beyond a standard media app. If using a sideloaded build, enable **Unknown sources** for Android Auto via ADB first: | |
| 34 | ||
| 35 | ``` | |
| 36 | adb shell settings put global android_auto_unknown_sources 1 | |
| 37 | ``` | |
| 38 | ||
| 39 | --- | |
| 40 | ||
| 41 | ## Supported providers | |
| 42 | ||
| 43 | | Provider | API key required | Web search | Notes | | |
| 44 | |---|---|---|---| | |
| 45 | | [Anthropic](https://console.anthropic.com) | ✅ | ✅ (built-in) | Default provider | | |
| 46 | | [OpenAI](https://platform.openai.com) | ✅ | — | GPT-4o and newer | | |
| 47 | | [Groq](https://console.groq.com) | ✅ | — | Very fast inference | | |
| 48 | | [Mistral](https://console.mistral.ai) | ✅ | — | | | |
| 49 | | [Google Gemini](https://aistudio.google.com) | ✅ | — | | | |
| 50 | | Ollama (local) | — | — | Requires local server; configure base URL | | |
| 51 | | Custom (OpenAI-compatible) | Optional | — | Any endpoint that speaks `/v1/chat/completions` | | |
| 52 | ||
| 53 | --- | |
| 54 | ||
| 55 | ## Adding a new provider | |
| 56 | ||
| 57 | ### OpenAI-compatible API (5 lines) | |
| 58 | ||
d522fe6d 2026-05-15 Pavel Safronov | 59 | Add an object to [OpenAiCompatibleProvider.kt](app/src/main/java/net/fuzzyworld/aichat/OpenAiCompatibleProvider.kt): |
449ce939 2026-05-14 Pavel Safronov | 60 | |
| 61 | ```kotlin | |
| 62 | object MyProvider : OpenAiCompatibleProvider() { | |
| 63 | override val id = "myprovider" // stable, never change | |
| 64 | override val displayName = "My Provider" | |
| 65 | override val defaultBaseUrl = "https://api.myprovider.com" | |
| 66 | override val defaultModel = "my-model-name" | |
| 67 | override val requiresApiKey = true | |
| 68 | } | |
| 69 | ``` | |
| 70 | ||
d522fe6d 2026-05-15 Pavel Safronov | 71 | Then add `MyProvider` to the list in [ProviderRegistry.kt](app/src/main/java/net/fuzzyworld/aichat/ProviderRegistry.kt). |
449ce939 2026-05-14 Pavel Safronov | 72 | |
| 73 | ### Unique API format | |
| 74 | ||
d522fe6d 2026-05-15 Pavel Safronov | 75 | Implement the `AiProvider` interface directly (see [GeminiProvider.kt](app/src/main/java/net/fuzzyworld/aichat/GeminiProvider.kt) as an example), then register it in `ProviderRegistry`. |
449ce939 2026-05-14 Pavel Safronov | 76 | |
| 77 | The interface requires two methods: | |
| 78 | - `ask(apiKey, baseUrl, model, question, onResult)` — call the API and return the text response | |
| 79 | - `listModels(apiKey, baseUrl, onResult)` — return a list of `ModelInfo(id, displayName)` | |
| 80 | ||
| 81 | --- | |
| 82 | ||
| 83 | ## Building from source | |
| 84 | ||
| 85 | ```bash | |
| 86 | # Clone and open in Android Studio, or build from the command line: | |
| 87 | ./gradlew assembleRelease | |
| 88 | ``` | |
| 89 | ||
846a86b0 2026-05-15 Pavel Safronov | 90 | Signing credentials go in `local.properties` (gitignored): |
| 91 | ||
| 92 | ```properties | |
| 93 | release.storeFile=path/to/release.jks | |
| 94 | release.storePassword=... | |
| 95 | release.keyAlias=... | |
| 96 | release.keyPassword=... | |
| 97 | ``` | |
| 98 | ||
| 99 | --- | |
| 100 | ||
| 101 | ## Releasing | |
| 102 | ||
| 103 | Push a tag to trigger the CI pipeline, which builds a signed APK, uploads it to | |
| 104 | the Package Registry, and creates a GitLab Release with a download link. | |
| 105 | ||
| 106 | ```bash | |
| 107 | git tag v1.2.3 && git push origin v1.2.3 | |
| 108 | ``` | |
| 109 | ||
| 110 | The release will appear under **Deploy → Releases** in the GitLab sidebar. | |
| 111 | ||
| 112 | ### CI/CD variables | |
| 113 | ||
| 114 | Configure these in **Settings → CI/CD → Variables** (all masked): | |
| 115 | ||
| 116 | | Variable | Description | | |
| 117 | |---|---| | |
effbd800 2026-05-15 Pavel Safronov | 118 | | `KEYSTORE_BASE64` | Release keystore encoded as base64 (`base64 -i claudeauto-release.jks \| pbcopy`) | |
| 119 | | `KEYSTORE_PASSWORD` | Keystore password (used for both the store and the key) | | |
449ce939 2026-05-14 Pavel Safronov | 120 | |
| 121 | --- | |
| 122 | ||
| 123 | ## Upcoming work | |
| 124 | ||
| 125 | - **Persist conversation history across sessions** — current history is in-memory only and lost when the service stops | |
| 126 | - **Per-provider system prompt customization** — let users adjust the assistant's persona and instructions | |
| 127 | - **Streaming response support** — start speaking the first sentence while the rest of the response is still arriving, reducing perceived latency | |
| 128 | - **Web search for non-Anthropic providers** — integrate an external search API (e.g. Brave Search, Tavily) so all providers can answer current-events questions | |
| 129 | - **Gemini grounding / web search** — wire up Google's native grounding tool for Gemini responses | |
| 130 | - **Hands-free activation** — start listening without tapping, triggered by a wake phrase or steering-wheel button mapping | |
| 131 | - **Export / import configuration** — back up and restore provider settings and API keys | |
| 132 | - **Android Automotive OS (AAOS) support** — native in-car OS support alongside the current Android Auto projection mode | |
2182d243 2026-05-15 Pavel Safronov | 133 | |
| 134 | --- | |
| 135 | ||
4fd10384 2026-05-16 Pavel Safronov | 136 | ## Attribution |
| 137 | ||
| 138 | App icon by [icongeek26](https://www.flaticon.com/authors/icongeek26) from the [Outline collection](https://www.flaticon.com/authors/icongeek26/outline?author_id=296&type=standard) on [Flaticon](https://www.flaticon.com). | |
| 139 | ||
| 140 | --- | |
| 141 | ||
2182d243 2026-05-15 Pavel Safronov | 142 | ## License |
| 143 | ||
| 144 | MIT — see [LICENSE](LICENSE). |