Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
33ec818
feat(auto): declare Android Auto notification capability
michaave Aug 24, 2026
9a84e5f
feat(auto): add Android Auto app descriptor
michaave Aug 24, 2026
3c35e4f
ci(auto): add one-shot PR 6012 import
michaave Aug 24, 2026
5af798b
feat(auto): import upstream Android Auto messaging support
github-actions[bot] Aug 24, 2026
dd95fbf
ci(auto): bootstrap Car App and Telecom foundation
michaave Aug 24, 2026
867bd8a
tools(auto): add idempotent Car App bootstrap
michaave Aug 24, 2026
129a2e1
ci(auto): apply Car App bootstrap
michaave Aug 24, 2026
0d25e2b
feat(auto): add Car App and Telecom foundation
github-actions[bot] Aug 24, 2026
ebccc58
ci(auto): add foundation compile validator
michaave Aug 24, 2026
be58d5c
ci(auto): record foundation compile result
github-actions[bot] Aug 24, 2026
7d671ec
ci(auto): generate dependency verification metadata
michaave Aug 24, 2026
f8f3ebe
ci(auto): resolve verification metadata before compile
michaave Aug 24, 2026
50c3743
ci(auto): narrowly verify AndroidX Car dependencies
michaave Aug 24, 2026
fcc5750
build(auto): verify AndroidX Car dependencies
github-actions[bot] Aug 24, 2026
677aed0
ci(auto): validate Android Auto source changes
michaave Aug 24, 2026
c1d85b0
feat(auto): add flavor-neutral call interop bridge
michaave Aug 24, 2026
631a27b
feat(auto): bridge Talk calls into Core-Telecom
michaave Aug 24, 2026
0bb477b
ci(auto): record foundation compile result
github-actions[bot] Aug 24, 2026
ce5fd3a
feat(auto): receive Talk call lifecycle in Telecom
michaave Aug 24, 2026
7fb2cd3
feat(auto): register Telecom interop receiver
michaave Aug 24, 2026
bb1556b
ci(auto): wire and validate Talk call bridge
michaave Aug 24, 2026
75fa07b
fix(auto): distinguish Telecom answer and active transitions
michaave Aug 24, 2026
99bec0d
ci(auto): record foundation compile result
github-actions[bot] Aug 24, 2026
1b978a5
fix(auto): stabilize Telecom call control scope
michaave Aug 24, 2026
b9dcbd0
build(auto): add reusable call bridge patcher
michaave Aug 24, 2026
b995f2b
ci(auto): apply and compile call bridge safely
michaave Aug 24, 2026
15f4f26
build(auto): add Android Auto dependency updater
michaave Aug 24, 2026
d4a30c8
ci(auto): compile call bridge against Core-Telecom beta
michaave Aug 24, 2026
4cb8507
feat(auto): wire Talk calls to current Core-Telecom
github-actions[bot] Aug 24, 2026
e263c17
ci(auto): record call bridge compile result
github-actions[bot] Aug 24, 2026
9be77ef
ci(auto): expose call bridge build as PR check
michaave Aug 24, 2026
7881211
ci(auto): record foundation compile result
github-actions[bot] Aug 24, 2026
e990dfe
ci(auto): record call bridge compile result
github-actions[bot] Aug 24, 2026
21f533d
fix(auto): import ApplicationInfo from pm
michaave Aug 24, 2026
ca87d58
fix(auto): keep latest published Core-Telecom artifact
michaave Aug 24, 2026
f26a764
ci(auto): rerun call bridge on published Telecom
michaave Aug 24, 2026
5d44b2f
fix(auto): import Flow collect for Telecom mute bridge
michaave Aug 24, 2026
5b02a43
ci(auto): record call bridge compile result
github-actions[bot] Aug 24, 2026
a12f05a
ci(auto): record foundation compile result
github-actions[bot] Aug 24, 2026
1168225
feat(auto): wire Talk calls to published Core-Telecom
github-actions[bot] Aug 24, 2026
b970753
ci(auto): record call bridge compile result
github-actions[bot] Aug 24, 2026
ba4fe88
ci(auto): replace bootstrap workflows with stable build check
michaave Aug 24, 2026
ddbbe5f
feat(auto): expose Telecom audio endpoint state
michaave Aug 24, 2026
4e100fb
feat(auto): route audio endpoint requests to Telecom
michaave Aug 24, 2026
bb510b5
feat(auto): mirror and request Telecom audio endpoints
michaave Aug 24, 2026
e842c8b
feat(auto): receive Telecom audio route requests
michaave Aug 24, 2026
cd3ad78
feat(auto): delegate Talk call audio routing to Telecom
michaave Aug 24, 2026
8a377e6
fix(auto): mark Telecom audio ownership before WebRTC starts
michaave Aug 24, 2026
3344299
fix(auto): route streaming endpoints from Talk audio picker
michaave Aug 24, 2026
75819cf
feat(auto): show recent Talk conversations
michaave Aug 25, 2026
78b4e8d
feat(auto): connect messages screen to Talk data
michaave Aug 25, 2026
612a7e6
fix(auto): preserve messaging screen cancellation
michaave Aug 25, 2026
391a797
fix(auto): load conversation messages from suspend context
michaave Aug 25, 2026
61ad52a
style(auto): align car service with Kotlin formatting
michaave Aug 25, 2026
51ebfc7
style(auto): format Telecom lifecycle methods
michaave Aug 25, 2026
7ba0958
feat(auto): add outgoing call conversation picker
michaave Aug 25, 2026
0b92bff
feat(auto): open call picker from car home
michaave Aug 25, 2026
721efaa
style(auto): format incoming call bridge
michaave Aug 25, 2026
c67e07e
ci(auto): validate outgoing call picker
michaave Aug 25, 2026
e8da530
style(auto): format empty call picker state
michaave Aug 25, 2026
b6483f3
ci(auto): rerun outgoing call validation
michaave Aug 25, 2026
31980bc
style(auto): wrap messaging notification condition
github-actions[bot] Aug 25, 2026
fb5b8d5
ci(auto): remove temporary outgoing validator
michaave Aug 25, 2026
10909e5
feat(auto): request microphone permission from car
michaave Aug 25, 2026
05c0d4a
fix(auto): refresh messages after direct reply
michaave Aug 25, 2026
5a1aa82
style(auto): wrap microphone permission check
michaave Aug 25, 2026
3060783
ci(auto): validate final Telecom participant integration
michaave Aug 25, 2026
60b4632
feat(auto): publish call participants to Telecom
github-actions[bot] Aug 25, 2026
33d80b9
ci(auto): remove completed participant validator
michaave Aug 25, 2026
635a14f
ci(auto): publish GPlay debug APK artifact
michaave Aug 25, 2026
d8af406
build(auto): add opt-in side-by-side package
michaave Aug 25, 2026
c240dda
ci(auto): publish standard and side-by-side APKs
michaave Aug 25, 2026
20e61ab
fix(auto): declare Car App template capability
michaave Aug 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions .github/workflows/android-auto-apk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
name: Android Auto test APK

on:
workflow_dispatch:
push:
branches:
- android-auto
paths:
- app/**
- build.gradle.kts
- settings.gradle.kts
- gradle/**
- gradle.properties
- .github/workflows/android-auto-apk.yml

permissions: read-all

concurrency:
group: android-auto-test-apk-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Set up JDK 21
uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '21'

- name: Validate Gradle wrapper
uses: gradle/actions/wrapper-validation@v5

- name: Assemble standard GPlay debug APK
run: ./gradlew --no-daemon :app:assembleGplayDebug --stacktrace

- name: Stage standard APK
shell: bash
run: |
set -euo pipefail
python3 - <<'PY'
import json
from pathlib import Path
import shutil

output_dir = Path('app/build/outputs/apk/gplay/debug')
metadata = output_dir / 'output-metadata.json'
if not metadata.exists():
raise SystemExit('Standard output-metadata.json not found')

data = json.loads(metadata.read_text())
actual = data.get('applicationId')
expected = 'com.nextcloud.talk2'
print(f'Standard APK applicationId: {actual}')
if actual != expected:
raise SystemExit(f'Expected {expected}, got {actual}')

apks = list(output_dir.glob('*.apk'))
if len(apks) != 1:
raise SystemExit(f'Expected exactly one standard APK, found {len(apks)}')

destination = Path('dist/standard')
destination.mkdir(parents=True, exist_ok=True)
shutil.copy2(apks[0], destination / 'Nextcloud-Talk-Android-Auto-Gplay-Debug.apk')
(destination / 'package-id.txt').write_text(expected + '\n')
PY
(
cd dist/standard
sha256sum Nextcloud-Talk-Android-Auto-Gplay-Debug.apk > Nextcloud-Talk-Android-Auto-Gplay-Debug.apk.sha256
)

- name: Upload standard Android Auto APK
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: Nextcloud-Talk-Android-Auto-Gplay-Debug
path: dist/standard/*
if-no-files-found: error
retention-days: 14

- name: Clean before side-by-side build
run: ./gradlew --no-daemon :app:clean

- name: Assemble side-by-side GPlay debug APK
run: ./gradlew --no-daemon -PandroidAutoSideBySide=true :app:assembleGplayDebug --stacktrace

- name: Stage side-by-side APK
shell: bash
run: |
set -euo pipefail
python3 - <<'PY'
import json
from pathlib import Path
import shutil

output_dir = Path('app/build/outputs/apk/gplay/debug')
metadata = output_dir / 'output-metadata.json'
if not metadata.exists():
raise SystemExit('Side-by-side output-metadata.json not found')

data = json.loads(metadata.read_text())
actual = data.get('applicationId')
expected = 'com.nextcloud.talk2.auto'
print(f'Side-by-side APK applicationId: {actual}')
if actual != expected:
raise SystemExit(f'Expected {expected}, got {actual}')

apks = list(output_dir.glob('*.apk'))
if len(apks) != 1:
raise SystemExit(f'Expected exactly one side-by-side APK, found {len(apks)}')

destination = Path('dist/side-by-side')
destination.mkdir(parents=True, exist_ok=True)
shutil.copy2(apks[0], destination / 'Nextcloud-Talk-Android-Auto-Gplay-Debug-SideBySide.apk')
(destination / 'package-id.txt').write_text(expected + '\n')
PY
(
cd dist/side-by-side
sha256sum Nextcloud-Talk-Android-Auto-Gplay-Debug-SideBySide.apk > Nextcloud-Talk-Android-Auto-Gplay-Debug-SideBySide.apk.sha256
)

- name: Upload side-by-side Android Auto APK
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: Nextcloud-Talk-Android-Auto-Gplay-Debug-SideBySide
path: dist/side-by-side/*
if-no-files-found: error
retention-days: 14
34 changes: 34 additions & 0 deletions .github/workflows/android-auto-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Android Auto build

on:
push:
branches:
- android-auto
pull_request:
branches:
- master

permissions:
contents: read

concurrency:
group: android-auto-build-${{ github.ref }}
cancel-in-progress: true

jobs:
compile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Set up JDK 21
uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '21'

- name: Validate Gradle wrapper
uses: gradle/actions/wrapper-validation@v5

- name: Compile Google Play and generic flavors
run: ./gradlew :app:compileGplayDebugKotlin :app:compileGenericDebugKotlin --stacktrace
13 changes: 13 additions & 0 deletions SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,19 @@ This requires a working Internet connection.

The generated APK file is saved in ```app/build/outputs/apk``` as ```app-generic-debug.apk```.

### Working with Android Auto

To test [notification extension to Android Auto](https://developer.android.com/training/cars/communication/notification-messaging), Developer settings and Unknown sources need to be enabled in
the Android Auto settings:

1. Open the Settings app on your device
2. Search for Android Auto, or click on Connected Devices > Android Auto
3. Scroll all the way down to Version, and click it 10 times to enable Developer settings
4. Click the 3 dots in the top right and select Developer settings
5. Enable Unknown sources

You can now receive notifications on Android Auto from a Nextcloud Talk development build.

### App flavours

The app is currently equipped to be built with three flavours:
Expand Down
14 changes: 14 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ plugins {

val kotlinVersion: String by rootProject.extra

val androidAutoSideBySide =
providers.gradleProperty("androidAutoSideBySide").orNull == "true"

val coilKtVersion = "2.7.0"
val daggerVersion = "2.60.1"
val emojiVersion = "1.6.0"
Expand Down Expand Up @@ -110,6 +113,13 @@ android {
}

buildTypes {
getByName("debug") {
if (androidAutoSideBySide) {
applicationIdSuffix = ".auto"
versionNameSuffix = "-auto"
}
}

release {
isMinifyEnabled = false
proguardFiles(
Expand Down Expand Up @@ -194,6 +204,10 @@ configurations.configureEach {
}

dependencies {
// Android Auto communication UI is isolated to the Google Play flavor.
"gplayImplementation"("androidx.car.app:app:1.7.0")
"gplayImplementation"("androidx.car.app:app-projected:1.7.0")
"gplayImplementation"("androidx.core:core-telecom:1.1.0-alpha06")
implementation("androidx.media3:media3-session:1.11.0")
kapt("org.jetbrains.kotlin:kotlin-metadata-jvm:$kotlinVersion")
implementation("androidx.room:room-testing-android:$roomVersion")
Expand Down
36 changes: 36 additions & 0 deletions app/src/gplay/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />

<application
android:name=".application.NextcloudTalkApplication"
android:allowBackup="true"
Expand All @@ -24,6 +26,40 @@
<meta-data android:name="firebase_analytics_collection_deactivated" android:value="true" />
<meta-data android:name="google_analytics_adid_collection_enabled" android:value="false" />


<!-- ConversationItem and communication templates require Car API 7. -->
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="7" />

<!-- Android Auto discovers the projected messaging capability through this descriptor. -->
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" />

<service
android:name=".auto.TalkCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.MESSAGING" />
<category android:name="androidx.car.app.category.CALLING" />
</intent-filter>
</service>

<receiver
android:name=".auto.call.TalkTelecomInteropReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.nextcloud.talk.call.action.INCOMING" />
<action android:name="com.nextcloud.talk.call.action.STARTED" />
<action android:name="com.nextcloud.talk.call.action.ACTIVE" />
<action android:name="com.nextcloud.talk.call.action.ENDED" />
<action android:name="com.nextcloud.talk.call.action.PARTICIPANTS_CHANGED" />
<action android:name="com.nextcloud.talk.call.action.CONTROL_AUDIO_ENDPOINT" />
</intent-filter>
</receiver>

<service
android:name=".services.firebase.NCFirebaseMessagingService"
android:exported="false">
Expand Down
Loading
Loading